"use client";

import { useEffect, useRef, useState } from "react";
import { useAudioRecorder } from "@/lib/useAudioRecorder";
import { RecordingControls } from "@/components/RecordingControls";

export default function SynthBox() {
  const [audioContext, setAudioContext] = useState<AudioContext | null>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [position, setPosition] = useState({ x: 50, y: 50 }); // Percentage
  const [gameStarted, setGameStarted] = useState(false);
  const [currentNoteIndex, setCurrentNoteIndex] = useState(0); // 0-6 for C major scale notes

  const oscillatorRef = useRef<OscillatorNode | null>(null);
  const gainNodeRef = useRef<GainNode | null>(null);
  const filterNodeRef = useRef<BiquadFilterNode | null>(null);
  const containerRef = useRef<HTMLDivElement>(null);

  // Audio recording
  const recorder = useAudioRecorder({ audioContext });

  useEffect(() => {
    // Initialize AudioContext on user interaction with explicit sample rate
    const initAudio = () => {
      if (!audioContext) {
        // Force 48kHz to match most MediaRecorder implementations
        const ctx = new AudioContext({ sampleRate: 48000 });
        setAudioContext(ctx);
        console.log(`AudioContext initialized at ${ctx.sampleRate}Hz`);
      }
    };

    document.addEventListener("click", initAudio, { once: true });
    document.addEventListener("touchstart", initAudio, { once: true });

    return () => {
      document.removeEventListener("click", initAudio);
      document.removeEventListener("touchstart", initAudio);
    };
  }, [audioContext]);

  // Space bar for recording control
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === " ") {
        e.preventDefault();
        if (recorder.recordingState === "idle" || recorder.recordingState === "recorded") {
          recorder.startRecording();
        } else if (recorder.recordingState === "recording") {
          recorder.stopRecording();
        }
      }
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [recorder]);

  const startSynth = () => {
    if (!audioContext || oscillatorRef.current) return;

    // Notify parent that game started
    if (!gameStarted) {
      setGameStarted(true);
      window.parent?.postMessage(
        {
          type: "game:start",
          slug: "synth-box",
        },
        "*"
      );
    }

    // Create oscillator
    const oscillator = audioContext.createOscillator();
    const gainNode = audioContext.createGain();
    const filter = audioContext.createBiquadFilter();

    oscillator.type = "sawtooth"; // Rich synth sound
    filter.type = "lowpass";

    // Connect: oscillator -> filter -> gain -> destination
    oscillator.connect(filter);
    filter.connect(gainNode);
    gainNode.connect(audioContext.destination);

    // Also connect to recorder
    recorder.connectToRecording(gainNode);

    oscillator.start();

    oscillatorRef.current = oscillator;
    gainNodeRef.current = gainNode;
    filterNodeRef.current = filter;

    updateSynthParams(position.x, position.y);
  };

  const stopSynth = () => {
    if (oscillatorRef.current) {
      oscillatorRef.current.stop();
      oscillatorRef.current = null;
      gainNodeRef.current = null;
      filterNodeRef.current = null;
    }
  };

  // Helper: Convert frequency to MIDI note number
  const freqToMidi = (freq: number) => {
    return 12 * Math.log2(freq / 440) + 69;
  };

  // Helper: Convert MIDI note to frequency
  const midiToFreq = (midi: number) => {
    return 440 * Math.pow(2, (midi - 69) / 12);
  };

  // Helper: Get color for current note (rainbow across C major scale)
  const getNoteColor = (noteIndex: number): { from: string; to: string } => {
    const colors = [
      { from: 'rgb(239, 68, 68)', to: 'rgb(185, 28, 28)' },   // C - Red
      { from: 'rgb(251, 146, 60)', to: 'rgb(194, 65, 12)' },  // D - Orange
      { from: 'rgb(250, 204, 21)', to: 'rgb(161, 98, 7)' },   // E - Yellow
      { from: 'rgb(34, 197, 94)', to: 'rgb(21, 128, 61)' },   // F - Green
      { from: 'rgb(6, 182, 212)', to: 'rgb(14, 116, 144)' },  // G - Cyan
      { from: 'rgb(59, 130, 246)', to: 'rgb(29, 78, 216)' },  // A - Blue
      { from: 'rgb(168, 85, 247)', to: 'rgb(109, 40, 217)' }, // B - Purple
    ];
    return colors[noteIndex % colors.length];
  };

  // Helper: Snap to C major scale
  const snapToMajorScale = (midiNote: number): { midi: number; noteIndex: number } => {
    const majorScaleIntervals = [0, 2, 4, 5, 7, 9, 11]; // C major scale intervals (C, D, E, F, G, A, B)
    const octave = Math.floor(midiNote / 12);
    const noteInOctave = Math.round(midiNote % 12);

    // Find closest note in major scale
    let closestIndex = 0;
    let closestInterval = majorScaleIntervals[0];
    let minDistance = Math.abs(majorScaleIntervals[0] - noteInOctave);

    majorScaleIntervals.forEach((interval, index) => {
      const distance = Math.abs(interval - noteInOctave);
      if (distance < minDistance) {
        minDistance = distance;
        closestInterval = interval;
        closestIndex = index;
      }
    });

    return {
      midi: octave * 12 + closestInterval,
      noteIndex: closestIndex // 0=C, 1=D, 2=E, 3=F, 4=G, 5=A, 6=B
    };
  };

  const updateSynthParams = (x: number, y: number) => {
    if (!audioContext || !oscillatorRef.current) return;

    // Y-axis controls frequency (100Hz to 800Hz) - lower Y = higher pitch
    const minFreq = 100;
    const maxFreq = 800;
    const rawFreq = maxFreq - ((maxFreq - minFreq) * (y / 100));

    // Convert to MIDI, snap to major scale, convert back
    const midiNote = freqToMidi(rawFreq);
    const { midi: snappedMidi, noteIndex } = snapToMajorScale(midiNote);

    // Update current note index for color changes
    setCurrentNoteIndex(noteIndex);

    // Add slight detuning (+- 5 cents for humanization)
    const detuningCents = (Math.random() - 0.5) * 10; // +- 5 cents
    const detuningSemitones = detuningCents / 100;
    const frequency = midiToFreq(snappedMidi + detuningSemitones);

    // X-axis controls filter cutoff (100Hz to 5000Hz) - higher X = higher filter
    const minCutoff = 100;
    const maxCutoff = 5000;
    const cutoff = minCutoff + (maxCutoff - minCutoff) * (x / 100);

    oscillatorRef.current.frequency.setValueAtTime(
      frequency,
      audioContext.currentTime
    );

    if (filterNodeRef.current) {
      filterNodeRef.current.frequency.setValueAtTime(
        cutoff,
        audioContext.currentTime
      );
    }

    if (gainNodeRef.current) {
      gainNodeRef.current.gain.setValueAtTime(0.3, audioContext.currentTime);
    }
  };

  const handleMove = (clientX: number, clientY: number) => {
    if (!containerRef.current) return;

    const rect = containerRef.current.getBoundingClientRect();
    const x = ((clientX - rect.left) / rect.width) * 100;
    const y = ((clientY - rect.top) / rect.height) * 100;

    const clampedX = Math.max(0, Math.min(100, x));
    const clampedY = Math.max(0, Math.min(100, y));

    setPosition({ x: clampedX, y: clampedY });
    updateSynthParams(clampedX, clampedY);
  };

  const handleMouseDown = (e: React.MouseEvent) => {
    e.preventDefault();
    setIsDragging(true);
    startSynth();
    handleMove(e.clientX, e.clientY);
  };

  const handleMouseMove = (e: React.MouseEvent) => {
    if (!isDragging) return;
    handleMove(e.clientX, e.clientY);
  };

  const handleMouseUp = () => {
    setIsDragging(false);
    stopSynth();
  };

  const handleTouchStart = (e: React.TouchEvent) => {
    e.preventDefault();
    setIsDragging(true);
    startSynth();
    const touch = e.touches[0];
    handleMove(touch.clientX, touch.clientY);
  };

  const handleTouchMove = (e: React.TouchEvent) => {
    if (!isDragging) return;
    e.preventDefault();
    const touch = e.touches[0];
    handleMove(touch.clientX, touch.clientY);
  };

  const handleTouchEnd = (e: React.TouchEvent) => {
    e.preventDefault();
    setIsDragging(false);
    stopSynth();
  };

  // Frequency and filter values for display
  const freq = Math.round(100 + (700 * position.x) / 100);
  const cutoff = Math.round(5000 - (4900 * position.y) / 100);

  return (
    <div className="min-h-screen bg-gradient-to-br from-indigo-900 via-purple-900 to-pink-900 flex flex-col items-center justify-center p-4">
      <style jsx global>{`
        * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
        }
        body {
          font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
          overflow: hidden;
          user-select: none;
          -webkit-user-select: none;
          touch-action: none;
        }
      `}</style>

      <div className="text-center mb-8 pointer-events-none">
        <h1 className="text-5xl font-bold text-white mb-2 drop-shadow-lg">
          🎛️ Synth Box
        </h1>
        <p className="text-white/80 text-lg">
          Drag the box: Y = pitch (major scale), X = filter • Space to record
        </p>
        {!audioContext && (
          <p className="text-yellow-300 text-sm mt-2">
            👆 Click anywhere to enable sound
          </p>
        )}
      </div>

      <RecordingControls
        recordingState={recorder.recordingState}
        recordedAudioUrl={recorder.recordedAudioUrl}
        onStartRecording={recorder.startRecording}
        onStopRecording={recorder.stopRecording}
        onClearRecording={recorder.clearRecording}
        disabled={!audioContext}
      />

      <div
        ref={containerRef}
        className="relative w-full max-w-xs md:max-w-sm aspect-square bg-black/30 backdrop-blur-sm rounded-3xl shadow-2xl overflow-hidden cursor-crosshair mx-auto"
        onMouseDown={handleMouseDown}
        onMouseMove={handleMouseMove}
        onMouseUp={handleMouseUp}
        onMouseLeave={handleMouseUp}
        onTouchStart={handleTouchStart}
        onTouchMove={handleTouchMove}
        onTouchEnd={handleTouchEnd}
      >
        {/* Grid background */}
        <div className="absolute inset-0 grid grid-cols-8 grid-rows-6 opacity-20">
          {Array.from({ length: 48 }).map((_, i) => (
            <div key={i} className="border border-white/20" />
          ))}
        </div>

        {/* Draggable box */}
        <div
          className="absolute w-20 h-20 -ml-10 -mt-10 pointer-events-none transition-transform"
          style={{
            left: `${position.x}%`,
            top: `${position.y}%`,
            transform: isDragging ? "scale(1.2)" : "scale(1)",
          }}
        >
          <div
            className="w-full h-full rounded-2xl shadow-2xl transition-all"
            style={{
              background: isDragging
                ? `linear-gradient(to bottom right, ${getNoteColor(currentNoteIndex).from}, ${getNoteColor(currentNoteIndex).to})`
                : 'linear-gradient(to bottom right, rgb(96, 165, 250), rgb(147, 51, 234))',
              boxShadow: isDragging
                ? "0 0 60px rgba(236, 72, 153, 0.8), 0 0 30px rgba(168, 85, 247, 0.6)"
                : "0 0 30px rgba(168, 85, 247, 0.5)",
            }}
          />
        </div>

        {/* Axis labels */}
        <div className="absolute bottom-4 left-4 text-white/60 text-sm font-mono pointer-events-none">
          X: Filter →
        </div>
        <div className="absolute top-4 left-4 text-white/60 text-sm font-mono pointer-events-none transform -rotate-90 origin-left">
          Y: Pitch ↓
        </div>
      </div>

      <div className="mt-8 text-center pointer-events-none">
        <div className="flex gap-8 justify-center">
          <div className="text-white">
            <div className="text-sm text-white/60 font-mono">Frequency</div>
            <div className="text-3xl font-bold font-mono">{freq} Hz</div>
          </div>
          <div className="text-white">
            <div className="text-sm text-white/60 font-mono">Filter Cutoff</div>
            <div className="text-3xl font-bold font-mono">{cutoff} Hz</div>
          </div>
        </div>
        <p className="text-white/60 text-sm mt-4">
          {isDragging ? "🔊 Playing..." : "Click and drag to play"}
        </p>
      </div>
    </div>
  );
}
