'use client';

import * as React from 'react';
import { Modal } from '@/components/ui/Modal';
import { Button } from '@/components/ui/Button';
import { Slider } from '@/components/ui/Slider';
import { cn } from '@/lib/utils/cn';
import type {
  CompressorParameters,
  LimiterParameters,
  GateParameters,
} from '@/lib/audio/effects/dynamics';

export type DynamicsType = 'compressor' | 'limiter' | 'gate';

export type DynamicsParameters =
  | (CompressorParameters & { type: 'compressor' })
  | (LimiterParameters & { type: 'limiter' })
  | (GateParameters & { type: 'gate' });

export interface EffectPreset {
  name: string;
  parameters: Partial<CompressorParameters | LimiterParameters | GateParameters>;
}

export interface DynamicsParameterDialogProps {
  open: boolean;
  onClose: () => void;
  effectType: DynamicsType;
  onApply: (params: DynamicsParameters) => void;
}

const EFFECT_LABELS: Record<DynamicsType, string> = {
  compressor: 'Compressor',
  limiter: 'Limiter',
  gate: 'Gate/Expander',
};

const EFFECT_DESCRIPTIONS: Record<DynamicsType, string> = {
  compressor: 'Reduces dynamic range by lowering loud sounds',
  limiter: 'Prevents audio from exceeding threshold',
  gate: 'Reduces volume of quiet sounds below threshold',
};

const PRESETS: Record<DynamicsType, EffectPreset[]> = {
  compressor: [
    { name: 'Gentle', parameters: { threshold: -20, ratio: 2, attack: 10, release: 100, knee: 6, makeupGain: 3 } },
    { name: 'Medium', parameters: { threshold: -18, ratio: 4, attack: 5, release: 50, knee: 3, makeupGain: 6 } },
    { name: 'Heavy', parameters: { threshold: -15, ratio: 8, attack: 1, release: 30, knee: 0, makeupGain: 10 } },
    { name: 'Vocal', parameters: { threshold: -16, ratio: 3, attack: 5, release: 80, knee: 4, makeupGain: 5 } },
  ],
  limiter: [
    { name: 'Transparent', parameters: { threshold: -3, attack: 0.5, release: 50, makeupGain: 0 } },
    { name: 'Loud', parameters: { threshold: -1, attack: 0.1, release: 20, makeupGain: 2 } },
    { name: 'Broadcast', parameters: { threshold: -0.5, attack: 0.1, release: 10, makeupGain: 0 } },
    { name: 'Mastering', parameters: { threshold: -2, attack: 0.3, release: 30, makeupGain: 1 } },
  ],
  gate: [
    { name: 'Gentle', parameters: { threshold: -40, ratio: 2, attack: 5, release: 100, knee: 6 } },
    { name: 'Medium', parameters: { threshold: -50, ratio: 4, attack: 1, release: 50, knee: 3 } },
    { name: 'Hard', parameters: { threshold: -60, ratio: 10, attack: 0.5, release: 20, knee: 0 } },
    { name: 'Noise Reduction', parameters: { threshold: -45, ratio: 6, attack: 1, release: 80, knee: 4 } },
  ],
};

export function DynamicsParameterDialog({
  open,
  onClose,
  effectType,
  onApply,
}: DynamicsParameterDialogProps) {
  const [parameters, setParameters] = React.useState<DynamicsParameters>(() => {
    if (effectType === 'compressor') {
      return {
        type: 'compressor',
        threshold: -20,
        ratio: 4,
        attack: 5,
        release: 50,
        knee: 3,
        makeupGain: 6,
      };
    } else if (effectType === 'limiter') {
      return {
        type: 'limiter',
        threshold: -3,
        attack: 0.5,
        release: 50,
        makeupGain: 0,
      };
    } else {
      return {
        type: 'gate',
        threshold: -40,
        ratio: 4,
        attack: 5,
        release: 50,
        knee: 3,
      };
    }
  });

  const canvasRef = React.useRef<HTMLCanvasElement>(null);

  // Get appropriate presets for this effect type
  const presets = PRESETS[effectType] || [];

  // Update parameters when effect type changes
  React.useEffect(() => {
    if (effectType === 'compressor') {
      setParameters({
        type: 'compressor',
        threshold: -20,
        ratio: 4,
        attack: 5,
        release: 50,
        knee: 3,
        makeupGain: 6,
      });
    } else if (effectType === 'limiter') {
      setParameters({
        type: 'limiter',
        threshold: -3,
        attack: 0.5,
        release: 50,
        makeupGain: 0,
      });
    } else {
      setParameters({
        type: 'gate',
        threshold: -40,
        ratio: 4,
        attack: 5,
        release: 50,
        knee: 3,
      });
    }
  }, [effectType]);

  // Draw transfer curve (input level vs output level)
  React.useEffect(() => {
    if (!canvasRef.current) return;

    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    // Get actual dimensions
    const rect = canvas.getBoundingClientRect();
    const dpr = window.devicePixelRatio || 1;

    // Set actual size in memory (scaled to account for extra pixel density)
    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;

    // Normalize coordinate system to use CSS pixels
    ctx.scale(dpr, dpr);

    // Clear any previous drawings first
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    const width = rect.width;
    const height = rect.height;
    const padding = 40;
    const graphWidth = width - padding * 2;
    const graphHeight = height - padding * 2;

    // Clear canvas
    ctx.fillStyle = getComputedStyle(canvas).getPropertyValue('background-color') || '#1a1a1a';
    ctx.fillRect(0, 0, width, height);

    // Draw axes
    ctx.strokeStyle = 'rgba(128, 128, 128, 0.5)';
    ctx.lineWidth = 1;

    // Horizontal and vertical grid lines
    ctx.beginPath();
    for (let db = -60; db <= 0; db += 10) {
      const x = padding + ((db + 60) / 60) * graphWidth;
      const y = padding + graphHeight - ((db + 60) / 60) * graphHeight;

      // Vertical grid line
      ctx.moveTo(x, padding);
      ctx.lineTo(x, padding + graphHeight);

      // Horizontal grid line
      ctx.moveTo(padding, y);
      ctx.lineTo(padding + graphWidth, y);
    }
    ctx.stroke();

    // Draw unity line (input = output)
    ctx.strokeStyle = 'rgba(128, 128, 128, 0.3)';
    ctx.lineWidth = 1;
    ctx.setLineDash([5, 5]);
    ctx.beginPath();
    ctx.moveTo(padding, padding + graphHeight);
    ctx.lineTo(padding + graphWidth, padding);
    ctx.stroke();
    ctx.setLineDash([]);

    // Draw threshold line
    const threshold = parameters.threshold;
    const thresholdX = padding + ((threshold + 60) / 60) * graphWidth;
    ctx.strokeStyle = 'rgba(255, 165, 0, 0.5)';
    ctx.lineWidth = 1;
    ctx.setLineDash([3, 3]);
    ctx.beginPath();
    ctx.moveTo(thresholdX, padding);
    ctx.lineTo(thresholdX, padding + graphHeight);
    ctx.stroke();
    ctx.setLineDash([]);

    // Draw transfer curve
    ctx.strokeStyle = '#3b82f6'; // Primary blue
    ctx.lineWidth = 2;
    ctx.beginPath();

    for (let inputDb = -60; inputDb <= 0; inputDb += 0.5) {
      let outputDb = inputDb;

      if (effectType === 'compressor' || effectType === 'limiter') {
        const ratio = parameters.type === 'limiter' ? 100 : (parameters as CompressorParameters).ratio;
        const knee = parameters.type === 'limiter' ? 0 : (parameters as CompressorParameters).knee;
        const makeupGain = (parameters as CompressorParameters | LimiterParameters).makeupGain;

        if (inputDb > threshold) {
          const overThreshold = inputDb - threshold;

          // Soft knee calculation
          if (knee > 0 && overThreshold < knee / 2) {
            const kneeRatio = overThreshold / (knee / 2);
            const compressionAmount = (1 - 1 / ratio) * kneeRatio;
            outputDb = inputDb - overThreshold * compressionAmount;
          } else {
            // Above knee - full compression
            outputDb = threshold + overThreshold / ratio;
          }

          outputDb += makeupGain;
        } else {
          outputDb += makeupGain;
        }
      } else if (effectType === 'gate') {
        const { ratio, knee } = parameters as GateParameters;

        if (inputDb < threshold) {
          const belowThreshold = threshold - inputDb;

          // Soft knee calculation
          if (knee > 0 && belowThreshold < knee / 2) {
            const kneeRatio = belowThreshold / (knee / 2);
            const expansionAmount = (ratio - 1) * kneeRatio;
            outputDb = inputDb - belowThreshold * expansionAmount;
          } else {
            // Below knee - full expansion
            outputDb = threshold - belowThreshold * ratio;
          }
        }
      }

      // Clamp output
      outputDb = Math.max(-60, Math.min(0, outputDb));

      const x = padding + ((inputDb + 60) / 60) * graphWidth;
      const y = padding + graphHeight - ((outputDb + 60) / 60) * graphHeight;

      if (inputDb === -60) {
        ctx.moveTo(x, y);
      } else {
        ctx.lineTo(x, y);
      }
    }

    ctx.stroke();

    // Draw axis labels
    ctx.fillStyle = 'rgba(156, 163, 175, 0.8)';
    ctx.font = '10px sans-serif';
    ctx.textAlign = 'center';

    // X-axis label
    ctx.fillText('Input Level (dB)', width / 2, height - 5);

    // Y-axis label (rotated)
    ctx.save();
    ctx.translate(10, height / 2);
    ctx.rotate(-Math.PI / 2);
    ctx.fillText('Output Level (dB)', 0, 0);
    ctx.restore();

    // Tick labels
    ctx.textAlign = 'center';
    for (let db = -60; db <= 0; db += 20) {
      const x = padding + ((db + 60) / 60) * graphWidth;
      ctx.fillText(db.toString(), x, height - 20);
    }

  }, [parameters, effectType]);

  const handleApply = () => {
    onApply(parameters);
    onClose();
  };

  const handlePresetClick = (preset: EffectPreset) => {
    setParameters((prev) => ({
      ...prev,
      ...preset.parameters,
    }));
  };

  return (
    <Modal
      open={open}
      onClose={onClose}
      title={EFFECT_LABELS[effectType] || 'Dynamics Processing'}
      description={EFFECT_DESCRIPTIONS[effectType]}
      size="lg"
      footer={
        <>
          <Button variant="outline" onClick={onClose}>
            Cancel
          </Button>
          <Button onClick={handleApply}>
            Apply Effect
          </Button>
        </>
      }
    >
      <div className="space-y-4">
        {/* Transfer Curve Visualization */}
        <div className="space-y-2">
          <label className="text-sm font-medium text-foreground">
            Transfer Curve
          </label>
          <canvas
            ref={canvasRef}
            className="w-full h-64 border border-border rounded bg-background"
          />
          <p className="text-xs text-muted-foreground">
            Shows input vs output levels. Threshold (orange line), ratio, knee, and makeup gain affect this curve.
            Attack and release control timing (not shown here).
          </p>
        </div>

        {/* Presets */}
        {presets.length > 0 && (
          <div className="space-y-2">
            <label className="text-sm font-medium text-foreground">
              Presets
            </label>
            <div className="grid grid-cols-2 gap-2">
              {presets.map((preset) => (
                <Button
                  key={preset.name}
                  variant="outline"
                  size="sm"
                  onClick={() => handlePresetClick(preset)}
                  className="justify-start"
                >
                  {preset.name}
                </Button>
              ))}
            </div>
          </div>
        )}

        {/* Threshold Parameter */}
        <div className="space-y-2">
          <label className="text-sm font-medium text-foreground flex justify-between">
            <span>Threshold</span>
            <span className="text-muted-foreground font-mono">
              {parameters.threshold.toFixed(1)} dB
            </span>
          </label>
          <Slider
            value={[parameters.threshold]}
            onValueChange={([value]) =>
              setParameters((prev) => ({ ...prev, threshold: value }))
            }
            min={-60}
            max={0}
            step={0.5}
            className="w-full"
          />
          <div className="flex justify-between text-xs text-muted-foreground">
            <span>-60 dB</span>
            <span>0 dB</span>
          </div>
        </div>

        {/* Ratio Parameter (Compressor and Gate only) */}
        {(effectType === 'compressor' || effectType === 'gate') && (
          <div className="space-y-2">
            <label className="text-sm font-medium text-foreground flex justify-between">
              <span>Ratio</span>
              <span className="text-muted-foreground font-mono">
                {(parameters as CompressorParameters | GateParameters).ratio.toFixed(1)}:1
              </span>
            </label>
            <Slider
              value={[(parameters as CompressorParameters | GateParameters).ratio]}
              onValueChange={([value]) =>
                setParameters((prev) => ({ ...prev, ratio: value }))
              }
              min={1}
              max={20}
              step={0.5}
              className="w-full"
            />
            <div className="flex justify-between text-xs text-muted-foreground">
              <span>1:1 (None)</span>
              <span>20:1 (Hard)</span>
            </div>
          </div>
        )}

        {/* Attack Parameter */}
        <div className="space-y-2">
          <label className="text-sm font-medium text-foreground flex justify-between">
            <span>Attack</span>
            <span className="text-muted-foreground font-mono">
              {parameters.attack.toFixed(2)} ms
            </span>
          </label>
          <Slider
            value={[Math.log10(parameters.attack)]}
            onValueChange={([value]) =>
              setParameters((prev) => ({ ...prev, attack: Math.pow(10, value) }))
            }
            min={-1}
            max={2}
            step={0.01}
            className="w-full"
          />
          <div className="flex justify-between text-xs text-muted-foreground">
            <span>0.1 ms (Fast)</span>
            <span>100 ms (Slow)</span>
          </div>
        </div>

        {/* Release Parameter */}
        <div className="space-y-2">
          <label className="text-sm font-medium text-foreground flex justify-between">
            <span>Release</span>
            <span className="text-muted-foreground font-mono">
              {parameters.release.toFixed(1)} ms
            </span>
          </label>
          <Slider
            value={[Math.log10(parameters.release)]}
            onValueChange={([value]) =>
              setParameters((prev) => ({ ...prev, release: Math.pow(10, value) }))
            }
            min={1}
            max={3}
            step={0.01}
            className="w-full"
          />
          <div className="flex justify-between text-xs text-muted-foreground">
            <span>10 ms (Fast)</span>
            <span>1000 ms (Slow)</span>
          </div>
        </div>

        {/* Knee Parameter (Compressor and Gate only) */}
        {(effectType === 'compressor' || effectType === 'gate') && (
          <div className="space-y-2">
            <label className="text-sm font-medium text-foreground flex justify-between">
              <span>Knee</span>
              <span className="text-muted-foreground font-mono">
                {(parameters as CompressorParameters | GateParameters).knee.toFixed(1)} dB
              </span>
            </label>
            <Slider
              value={[(parameters as CompressorParameters | GateParameters).knee]}
              onValueChange={([value]) =>
                setParameters((prev) => ({ ...prev, knee: value }))
              }
              min={0}
              max={12}
              step={0.5}
              className="w-full"
            />
            <div className="flex justify-between text-xs text-muted-foreground">
              <span>0 dB (Hard)</span>
              <span>12 dB (Soft)</span>
            </div>
          </div>
        )}

        {/* Makeup Gain Parameter (Compressor and Limiter only) */}
        {(effectType === 'compressor' || effectType === 'limiter') && (
          <div className="space-y-2">
            <label className="text-sm font-medium text-foreground flex justify-between">
              <span>Makeup Gain</span>
              <span className="text-muted-foreground font-mono">
                {(parameters as CompressorParameters | LimiterParameters).makeupGain > 0 ? '+' : ''}
                {(parameters as CompressorParameters | LimiterParameters).makeupGain.toFixed(1)} dB
              </span>
            </label>
            <Slider
              value={[(parameters as CompressorParameters | LimiterParameters).makeupGain]}
              onValueChange={([value]) =>
                setParameters((prev) => ({ ...prev, makeupGain: value }))
              }
              min={0}
              max={24}
              step={0.5}
              className="w-full"
            />
            <div className="flex justify-between text-xs text-muted-foreground">
              <span>0 dB</span>
              <span>+24 dB</span>
            </div>
          </div>
        )}
      </div>
    </Modal>
  );
}
