import { useState, useRef, useCallback } from "react";
import { useToast } from "./Toast";

// Ambient sound types with their oscillator configs
const AMBIENT_SOUNDS = [
  { id: "rain", label: "Rain", icon: "🌧", type: "brown" as const, freq: 0, filterFreq: 800 },
  { id: "wind", label: "Wind", icon: "💨", type: "brown" as const, freq: 0, filterFreq: 400 },
  { id: "fire", label: "Fire", icon: "🔥", type: "brown" as const, freq: 0, filterFreq: 200 },
  { id: "ocean", label: "Ocean", icon: "🌊", type: "sine" as const, freq: 80, filterFreq: 1200 },
  { id: "forest", label: "Forest", icon: "🌲", type: "brown" as const, freq: 0, filterFreq: 3000 },
  { id: "tavern", label: "Tavern", icon: "🍺", type: "brown" as const, freq: 0, filterFreq: 600 },
  { id: "thunder", label: "Thunder", icon: "⛈", type: "sawtooth" as const, freq: 40, filterFreq: 200 },
  { id: "cave", label: "Cave", icon: "🪨", type: "sine" as const, freq: 55, filterFreq: 150 },
];

// Sound effect one-shots
const SFX_SOUNDS = [
  { id: "sword", label: "Sword", icon: "⚔" },
  { id: "bow", label: "Bow", icon: "🏹" },
  { id: "spell", label: "Spell", icon: "✨" },
  { id: "door", label: "Door", icon: "🚪" },
  { id: "coins", label: "Coins", icon: "💰" },
  { id: "horn", label: "Horn", icon: "📯" },
  { id: "dice", label: "Dice", icon: "🎲" },
  { id: "footsteps", label: "Steps", icon: "👣" },
];

export function Soundboard() {
  const [activeAmbients, setActiveAmbients] = useState<Set<string>>(new Set());
  const [volume, setVolume] = useState(0.5);
  const audioCtxRef = useRef<AudioContext | null>(null);
  const nodesRef = useRef<Map<string, { source: OscillatorNode | AudioBufferSourceNode; gain: GainNode; filter: BiquadFilterNode }>>(new Map());
  const { addToast } = useToast();

  const getAudioCtx = useCallback(() => {
    if (!audioCtxRef.current) {
      audioCtxRef.current = new AudioContext();
    }
    return audioCtxRef.current;
  }, []);

  const toggleAmbient = useCallback((id: string) => {
    setActiveAmbients((prev) => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
        // Stop the sound
        const nodes = nodesRef.current.get(id);
        if (nodes) {
          nodes.gain.gain.linearRampToValueAtTime(0, audioCtxRef.current!.currentTime + 0.5);
          setTimeout(() => {
            nodes.source.stop();
            nodesRef.current.delete(id);
          }, 600);
        }
      } else {
        next.add(id);
        // Start the sound
        const sound = AMBIENT_SOUNDS.find((s) => s.id === id);
        if (!sound) return next;

        const ctx = getAudioCtx();
        const gainNode = ctx.createGain();
        gainNode.gain.value = 0; // Start silent, fade in
        gainNode.gain.linearRampToValueAtTime(volume, ctx.currentTime + 1);

        const filter = ctx.createBiquadFilter();
        filter.type = "lowpass";
        filter.frequency.value = sound.filterFreq;

        let source: OscillatorNode | AudioBufferSourceNode;

        if (sound.type === "brown") {
          // Brown noise via buffer
          const bufferSize = ctx.sampleRate * 2;
          const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
          const data = buffer.getChannelData(0);
          let last = 0;
          for (let i = 0; i < bufferSize; i++) {
            const white = Math.random() * 2 - 1;
            data[i] = (last + 0.02 * white) / 1.02;
            last = data[i];
            data[i] *= 3.5; // Normalize
          }
          source = ctx.createBufferSource();
          source.buffer = buffer;
          source.loop = true;
        } else {
          // Oscillator
          source = ctx.createOscillator();
          source.type = sound.type;
          source.frequency.value = sound.freq;
        }

        source.connect(filter);
        filter.connect(gainNode);
        gainNode.connect(ctx.destination);
        source.start();

        nodesRef.current.set(id, { source, gain: gainNode, filter });
      }
      return next;
    });
  }, [volume, getAudioCtx]);

  const playSfx = useCallback((id: string) => {
    const ctx = getAudioCtx();
    const sfx = SFX_SOUNDS.find((s) => s.id === id);
    if (!sfx) return;

    // Create simple synthesized sound effects
    const gain = ctx.createGain();
    gain.gain.value = volume;
    gain.connect(ctx.destination);

    switch (id) {
      case "sword": {
        const osc = ctx.createOscillator();
        osc.type = "sawtooth";
        osc.frequency.setValueAtTime(800, ctx.currentTime);
        osc.frequency.exponentialRampToValueAtTime(200, ctx.currentTime + 0.15);
        gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.2);
        osc.connect(gain);
        osc.start(ctx.currentTime);
        osc.stop(ctx.currentTime + 0.2);
        break;
      }
      case "bow": {
        const osc = ctx.createOscillator();
        osc.type = "sine";
        osc.frequency.setValueAtTime(1200, ctx.currentTime);
        osc.frequency.exponentialRampToValueAtTime(100, ctx.currentTime + 0.3);
        gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.3);
        osc.connect(gain);
        osc.start(ctx.currentTime);
        osc.stop(ctx.currentTime + 0.3);
        break;
      }
      case "spell": {
        const osc = ctx.createOscillator();
        osc.type = "sine";
        osc.frequency.setValueAtTime(300, ctx.currentTime);
        osc.frequency.linearRampToValueAtTime(900, ctx.currentTime + 0.4);
        osc.frequency.linearRampToValueAtTime(300, ctx.currentTime + 0.8);
        gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.8);
        osc.connect(gain);
        osc.start(ctx.currentTime);
        osc.stop(ctx.currentTime + 0.8);
        break;
      }
      case "door": {
        const bufferSize = ctx.sampleRate * 0.3;
        const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
        const data = buffer.getChannelData(0);
        for (let i = 0; i < bufferSize; i++) {
          data[i] = (Math.random() * 2 - 1) * Math.exp(-i / (ctx.sampleRate * 0.05));
        }
        const source = ctx.createBufferSource();
        source.buffer = buffer;
        const filter = ctx.createBiquadFilter();
        filter.type = "lowpass";
        filter.frequency.value = 500;
        source.connect(filter);
        filter.connect(gain);
        source.start(ctx.currentTime);
        break;
      }
      case "coins": {
        for (let i = 0; i < 5; i++) {
          const osc = ctx.createOscillator();
          const coinGain = ctx.createGain();
          osc.type = "sine";
          osc.frequency.value = 2000 + Math.random() * 2000;
          coinGain.gain.setValueAtTime(volume * 0.3, ctx.currentTime + i * 0.08);
          coinGain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + i * 0.08 + 0.15);
          osc.connect(coinGain);
          coinGain.connect(ctx.destination);
          osc.start(ctx.currentTime + i * 0.08);
          osc.stop(ctx.currentTime + i * 0.08 + 0.15);
        }
        break;
      }
      case "horn": {
        const osc = ctx.createOscillator();
        osc.type = "sawtooth";
        osc.frequency.value = 220;
        const filter = ctx.createBiquadFilter();
        filter.type = "lowpass";
        filter.frequency.setValueAtTime(400, ctx.currentTime);
        filter.frequency.linearRampToValueAtTime(2000, ctx.currentTime + 0.1);
        gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.6);
        osc.connect(filter);
        filter.connect(gain);
        osc.start(ctx.currentTime);
        osc.stop(ctx.currentTime + 0.6);
        break;
      }
      case "dice": {
        for (let i = 0; i < 8; i++) {
          const bufferSize = ctx.sampleRate * 0.04;
          const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
          const data = buffer.getChannelData(0);
          for (let j = 0; j < bufferSize; j++) {
            data[j] = (Math.random() * 2 - 1) * Math.exp(-j / (ctx.sampleRate * 0.01));
          }
          const source = ctx.createBufferSource();
          source.buffer = buffer;
          const hitGain = ctx.createGain();
          hitGain.gain.value = volume * 0.3;
          source.connect(hitGain);
          hitGain.connect(ctx.destination);
          source.start(ctx.currentTime + i * 0.03 + Math.random() * 0.02);
        }
        break;
      }
      case "footsteps": {
        for (let i = 0; i < 4; i++) {
          const bufferSize = ctx.sampleRate * 0.05;
          const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
          const data = buffer.getChannelData(0);
          for (let j = 0; j < bufferSize; j++) {
            data[j] = (Math.random() * 2 - 1) * Math.exp(-j / (ctx.sampleRate * 0.015));
          }
          const source = ctx.createBufferSource();
          source.buffer = buffer;
          const stepGain = ctx.createGain();
          stepGain.gain.value = volume * 0.2;
          const filter = ctx.createBiquadFilter();
          filter.type = "lowpass";
          filter.frequency.value = 300;
          source.connect(filter);
          filter.connect(stepGain);
          stepGain.connect(ctx.destination);
          source.start(ctx.currentTime + i * 0.4);
        }
        break;
      }
    }

    addToast(`${sfx.icon} ${sfx.label}`, "info");
  }, [volume, getAudioCtx, addToast]);

  return (
    <div className="flex flex-col gap-4">
      {/* Volume */}
      <div className="flex items-center gap-3">
        <span className="text-[var(--color-text-secondary)] text-xs font-medium w-16">Volume</span>
        <input
          type="range"
          min={0}
          max={1}
          step={0.05}
          value={volume}
          onChange={(e) => setVolume(parseFloat(e.target.value))}
          className="flex-1 accent-[var(--color-gold-bright)]"
        />
        <span className="text-[var(--color-text-dim)] text-xs font-mono w-8 text-right">
          {Math.round(volume * 100)}%
        </span>
      </div>

      {/* Ambient sounds */}
      <div>
        <h3 className="text-[var(--color-text-secondary)] text-xs font-medium mb-2 uppercase tracking-wider">
          🎧 Ambient Loops
        </h3>
        <div className="grid grid-cols-4 gap-2">
          {AMBIENT_SOUNDS.map((sound) => (
            <button
              key={sound.id}
              onClick={() => toggleAmbient(sound.id)}
              className={`rounded-xl p-3 flex flex-col items-center gap-1.5 cursor-pointer transition-all ${
                activeAmbients.has(sound.id)
                  ? "glass-card-active scale-[1.02]"
                  : "bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] hover:border-[var(--color-gold-bright)] hover:scale-[1.02]"
              }`}
            >
              <span className="text-2xl">{sound.icon}</span>
              <span className="text-[10px] text-[var(--color-text-secondary)]">{sound.label}</span>
              {activeAmbients.has(sound.id) && (
                <span className="w-1.5 h-1.5 rounded-full bg-[var(--color-success)] animate-pulse" />
              )}
            </button>
          ))}
        </div>
      </div>

      {/* Sound effects */}
      <div>
        <h3 className="text-[var(--color-text-secondary)] text-xs font-medium mb-2 uppercase tracking-wider">
          ⚔ Sound Effects
        </h3>
        <div className="grid grid-cols-4 gap-2">
          {SFX_SOUNDS.map((sfx) => (
            <button
              key={sfx.id}
              onClick={() => playSfx(sfx.id)}
              className="rounded-xl p-3 flex flex-col items-center gap-1.5 bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] hover:border-[var(--color-gold-bright)] hover:scale-[1.02] transition-all cursor-pointer active:scale-95"
            >
              <span className="text-2xl">{sfx.icon}</span>
              <span className="text-[10px] text-[var(--color-text-secondary)]">{sfx.label}</span>
            </button>
          ))}
        </div>
      </div>

      {/* Stop all */}
      {activeAmbients.size > 0 && (
        <button
          onClick={() => {
            nodesRef.current.forEach((nodes) => {
              try {
                nodes.gain.gain.linearRampToValueAtTime(0, audioCtxRef.current!.currentTime + 0.5);
                setTimeout(() => { try { nodes.source.stop(); } catch {} }, 600);
              } catch {}
            });
            nodesRef.current.clear();
            setActiveAmbients(new Set());
          }}
          className="rounded-lg bg-[var(--color-danger)]/20 border border-[var(--color-danger)]/40 text-[var(--color-danger)] px-4 py-2 text-xs font-semibold hover:bg-[var(--color-danger)]/30 transition-colors cursor-pointer"
        >
          ⏹ Stop All
        </button>
      )}
    </div>
  );
}