import { useEffect, useMemo, useRef, useState } from "react";
import { formatDurationHHMMSS } from "@/lib/format";
import { apiRequest, queryClient, uploadAudio } from "@/lib/queryClient";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useApp } from "@/lib/app-context";
import type { Recording, InsertRecording } from "@shared/schema";
import { useLocation } from "wouter";
import { Play, Pause, ChevronLeft, ChevronRight, AlertCircle } from "lucide-react";
import { createRecorder } from "@/lib/recorder";
import type { RecorderResult } from "@/lib/recorder";
import { BeatPlayer, type Beat } from "@/lib/beat-player";

type RecState = "idle" | "recording" | "paused";

const KEYS = ["off", "C", "Cm", "D", "Dm", "E", "Em", "F", "Fm", "G", "Gm", "A", "Am", "B", "Bm"];

type Channel = { id: string; label: string; sub: string; accent?: "red" | "amber" };
const CHANNELS: Channel[] = [
  { id: "beat",  label: "BEAT", sub: "ch.1" },
  { id: "voice", label: "VOC",  sub: "ch.2", accent: "red" },
  { id: "pitch", label: "PTCH", sub: "ch.3" },
  { id: "tune",  label: "TUNE", sub: "ch.4" },
  { id: "fx",    label: "FX",   sub: "ch.5" },
  { id: "mast",  label: "MAST", sub: "out",  accent: "amber" },
];

export default function RecordPage() {
  const [state, setState] = useState<RecState>("idle");
  const [seconds, setSeconds] = useState(0);
  const [beatIdx, setBeatIdx] = useState(0);
  const [beatPlaying, setBeatPlaying] = useState(false);
  const [levels, setLevels] = useState<number[]>([75, 80, 50, 50, 30, 85]);
  const [pitchSemi, setPitchSemi] = useState(50);
  const [keyIdx, setKeyIdx] = useState(1);
  const [autotuneOn, setAutotuneOn] = useState(false);
  const [cuesActive, setCuesActive] = useState<Record<number, number>>({});
  const [markers, setMarkers] = useState<number[]>([]);
  const [vuLevel, setVuLevel] = useState(0); // 0..1 — live mic peak
  const [permissionDenied, setPermissionDenied] = useState(false);
  const [busy, setBusy] = useState(false);

  const recorderRef = useRef<Awaited<ReturnType<typeof createRecorder>> | null>(null);
  const beatPlayerRef = useRef<BeatPlayer | null>(null);
  const { showSnackbar } = useApp();
  const [, navigate] = useLocation();

  // Load beats list from backend.
  const { data: beats = [] } = useQuery<Beat[]>({ queryKey: ["/api/beats"] });
  const beat = beats[beatIdx] || { slug: "—", title: "—", bpm: 0, key: "—", url: "", durationSec: 0 };

  const pitchVal = Math.round(((pitchSemi - 50) / 50) * 12);
  const isRec = state === "recording";

  // Init beat player once.
  useEffect(() => {
    beatPlayerRef.current = new BeatPlayer();
    return () => { beatPlayerRef.current?.stop(); beatPlayerRef.current = null; };
  }, []);

  // Keep beat volume in sync with BEAT fader (ch.0) AND master (ch.5).
  useEffect(() => {
    const beatVol = (levels[0] / 100) * (levels[5] / 100);
    beatPlayerRef.current?.setVolume(beatVol);
  }, [levels]);

  // Switch beat when user picks a different one.
  useEffect(() => {
    if (!beats.length) return;
    const b = beats[beatIdx];
    if (!b) return;
    beatPlayerRef.current?.load(b);
    if (beatPlayerRef.current && beatPlaying) {
      beatPlayerRef.current.play();
    }
  }, [beatIdx, beats, beatPlaying]);

  // Toggle beat play/pause.
  useEffect(() => {
    if (!beatPlayerRef.current) return;
    if (beatPlaying) beatPlayerRef.current.play();
    else beatPlayerRef.current.pause();
  }, [beatPlaying]);

  // Cleanup recorder on unmount.
  useEffect(() => {
    return () => { recorderRef.current?.cancel(); };
  }, []);

  const createMutation = useMutation({
    mutationFn: async (rec: InsertRecording): Promise<Recording> => {
      const res = await apiRequest("POST", "/api/recordings", rec);
      return (await res.json()) as Recording;
    },
    onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/recordings"] }); },
  });

  const startRecording = async () => {
    if (busy) return;
    setBusy(true);
    try {
      const rec = await createRecorder({
        onLevel: (l) => setVuLevel(l),
        onTime: (sec) => setSeconds(sec),
      });
      recorderRef.current = rec;
      rec.start();
      setState("recording");
      setSeconds(0);
      setMarkers([]);
      // Auto-start beat when recording starts.
      if (beats[beatIdx]) {
        await beatPlayerRef.current?.load(beats[beatIdx]);
        await beatPlayerRef.current?.play();
        setBeatPlaying(true);
      }
      setPermissionDenied(false);
    } catch (e) {
      console.error("mic error", e);
      const err = e as Error;
      if (/denied|not allowed|permission/i.test(err.message)) {
        setPermissionDenied(true);
        showSnackbar({ message: "Mikrofon-Zugriff verweigert" });
      } else {
        showSnackbar({ message: "Mikrofon nicht verfügbar" });
      }
    } finally {
      setBusy(false);
    }
  };

  const togglePauseResume = () => {
    // Hint: true pause-of-MediaRecorder needs recorder.pause(); for simplicity we treat as stop+save flow.
    // For Stufe 1 we don't expose pause — clicking the lit record button stops.
    handleStop();
  };

  const handleRecord = () => {
    if (state === "idle") {
      void startRecording();
    } else {
      togglePauseResume();
    }
  };

  const handleStop = async () => {
    if (state === "idle") return;
    const rec = recorderRef.current;
    if (!rec) { setState("idle"); return; }
    setBusy(true);
    try {
      const result: RecorderResult = await rec.stop();
      recorderRef.current = null;
      // Stop beat after save.
      beatPlayerRef.current?.stop();
      setBeatPlaying(false);

      if (result.durationSec < 0.5) {
        showSnackbar({ message: "Aufnahme zu kurz" });
        setState("idle");
        setSeconds(0);
        setMarkers([]);
        setVuLevel(0);
        return;
      }

      const dateStr = new Date().toLocaleString("de-DE", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" });
      const meta: InsertRecording = {
        title: `${beat.title || "Take"} · ${dateStr}`,
        durationSec: Math.round(result.durationSec),
        createdAt: Date.now(),
        markers: JSON.stringify(markers.map((m) => Math.round(m * 10) / 10)),
        waveform: JSON.stringify(result.waveform),
        starred: 0,
        mimeType: result.mimeType,
        fileExt: result.fileExt,
        fileSize: result.blob.size,
        beatSlug: beat.slug,
      };
      const created = await createMutation.mutateAsync(meta);
      await uploadAudio(created.id, result.blob);
      showSnackbar({
        message: "Tape gespeichert",
        actionLabel: "Öffnen",
        onAction: () => navigate(`/aufnahme/${created.id}`),
      });
      setState("idle");
      setSeconds(0);
      setMarkers([]);
      setVuLevel(0);
    } catch (e) {
      console.error(e);
      showSnackbar({ message: "Speichern fehlgeschlagen" });
      setState("idle");
    } finally {
      setBusy(false);
    }
  };

  const handleCue = (i: number) => {
    setCuesActive((p) => ({ ...p, [i]: Date.now() }));
    window.setTimeout(() => setCuesActive((p) => { const n = { ...p }; delete n[i]; return n; }), 240);
    if (state === "recording") setMarkers((m) => [...m, seconds]);
  };

  const setLevel = (idx: number, v: number) => {
    setLevels((arr) => { const next = [...arr]; next[idx] = v; return next; });
  };

  const knobRot = (v: number, max = 100) => -135 + (v / max) * 270;
  const faderTop = (v: number) => `calc(${100 - v}% - 14px)`;

  // VU meters: BEAT channel reflects beat playing, VOC channel reflects live mic peak,
  // others are decorative idle.
  const vuLevelForChannel = (i: number): number => {
    if (i === 0) return beatPlaying ? 0.4 + (levels[0] / 100) * 0.4 : 0;
    if (i === 1) return isRec ? Math.min(1, vuLevel * 1.6) : 0;
    if (i === 5) return Math.max(
      beatPlaying ? 0.4 : 0,
      isRec ? vuLevel : 0
    ) * (levels[5] / 100);
    return 0;
  };

  return (
    <div className="flex flex-col h-full overflow-y-auto no-scrollbar chassis">

      {/* === HEADER: reel + LCD + transport === */}
      <div className="px-3 pt-3 pb-2">
        <div className="panel-metal rounded-lg p-3">
          <div className="flex items-stretch gap-3">
            <div className="relative flex-shrink-0" style={{ width: 96, height: 96 }}>
              <div className={`reel w-full h-full ${beatPlaying || isRec ? "spinning" : ""}`} aria-label="Reel" data-testid="reel" />
              <div className={`rec-lamp ${isRec ? "on" : ""} absolute -top-0.5 -left-0.5`} />
            </div>

            <div className="flex-1 min-w-0 flex flex-col justify-between gap-2">
              <div className="flex items-center justify-between">
                <div>
                  <div className="text-[10px] font-mono tracking-[0.25em] text-zinc-300 font-semibold">TC-1</div>
                  <div className="etch mt-0.5">pocket studio</div>
                </div>
                <div className="lcd-screen rounded-sm px-2 py-1 text-right min-w-[88px]">
                  <div className="text-[15px] font-bold tabular-nums leading-tight" data-testid="text-timer">
                    {formatDurationHHMMSS(Math.floor(seconds))}
                  </div>
                  <div className="text-[8px] opacity-80 tracking-wider">
                    {beat.bpm} BPM · {beat.key}
                  </div>
                </div>
              </div>

              <div className="flex items-stretch gap-1.5">
                <button
                  onClick={() => setBeatIdx((i) => (i - 1 + Math.max(1, beats.length)) % Math.max(1, beats.length))}
                  className="hw-btn w-8 flex items-center justify-center"
                  aria-label="Vorheriger Beat"
                  data-testid="button-beat-prev"
                  disabled={!beats.length}
                >
                  <ChevronLeft className="w-3.5 h-3.5" />
                </button>
                <div className="flex-1 panel-metal rounded-sm px-2.5 py-1.5 flex flex-col justify-center min-w-0">
                  <div className="text-[11px] font-bold tracking-[0.08em] text-zinc-100 truncate" data-testid="text-beat-name">{beat.title}</div>
                  <div className="etch mt-0.5">beat · {beats.length ? beatIdx + 1 : 0}/{beats.length}</div>
                </div>
                <button
                  onClick={() => setBeatIdx((i) => (i + 1) % Math.max(1, beats.length))}
                  className="hw-btn w-8 flex items-center justify-center"
                  aria-label="Nächster Beat"
                  data-testid="button-beat-next"
                  disabled={!beats.length}
                >
                  <ChevronRight className="w-3.5 h-3.5" />
                </button>
                <button
                  onClick={() => setBeatPlaying((p) => !p)}
                  className={`hw-btn w-10 flex items-center justify-center ${beatPlaying ? "active" : ""}`}
                  aria-label={beatPlaying ? "Beat stoppen" : "Beat starten"}
                  data-testid="button-beat-play"
                  disabled={!beats.length}
                >
                  {beatPlaying ? <Pause className="w-3.5 h-3.5" fill="currentColor" /> : <Play className="w-3.5 h-3.5 ml-0.5" fill="currentColor" />}
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>

      {permissionDenied && (
        <div className="px-3 pb-2">
          <div className="panel-metal rounded-lg p-3 flex items-start gap-2 border border-[#FF3B30]/40">
            <AlertCircle className="w-4 h-4 text-[#FF3B30] mt-0.5 shrink-0" />
            <div className="text-[11px] text-zinc-200 leading-snug">
              Mikrofon-Zugriff verweigert. Erlaube den Zugriff in den Browser-Einstellungen und lade die Seite neu.
            </div>
          </div>
        </div>
      )}

      {/* === MIXER === */}
      <div className="px-3 pb-3">
        <div className="panel-metal rounded-lg p-3">
          <div className="flex items-center justify-between mb-2">
            <div className="etch-strong text-[10px] tracking-[0.25em] font-mono font-semibold">MIXER · 6 CH</div>
            <div className="flex items-center gap-1.5">
              <span className={`led-pill ${isRec ? "on" : beatPlaying ? "on-green" : ""}`} />
              <span className="etch">{isRec ? "rec" : beatPlaying ? "play" : "idle"}</span>
            </div>
          </div>

          <div className="grid grid-cols-6 gap-1.5 mb-2.5">
            {CHANNELS.map((ch, i) => (
              <div key={`k-${ch.id}`} className="flex flex-col items-center gap-1">
                <div className="relative" style={{ width: 30, height: 30 }}>
                  <div className="knob w-full h-full" style={{ transform: `rotate(${knobRot(levels[i] * 0.6 + 20)}deg)` }} />
                </div>
                <div className="etch text-[8px]">gain</div>
              </div>
            ))}
          </div>

          <div className="grid grid-cols-6 gap-1.5">
            {CHANNELS.map((ch, i) => {
              const lev = vuLevelForChannel(i);
              return (
                <div key={`f-${ch.id}`} className="flex flex-col items-center">
                  <div className="w-full mb-1.5 flex flex-col gap-[2px]">
                    {[0,1,2,3,4].map((seg) => {
                      const threshold = (4 - seg) / 5;
                      const on = lev > threshold;
                      const cls = seg === 0 ? "hot" : seg <= 1 ? "warm" : "";
                      return <div key={seg} className={`vu-seg ${on ? `on ${cls}` : ""}`} />;
                    })}
                  </div>

                  <div className="relative w-full flex justify-center" style={{ height: 168 }}>
                    <div className="fader-rail">
                      <div
                        className={`fader-cap ${ch.accent === "red" ? "accent" : ch.accent === "amber" ? "accent-amber" : ""}`}
                        style={{ top: faderTop(levels[i]) }}
                      />
                      <input
                        type="range" min={0} max={100} value={levels[i]}
                        onChange={(e) => setLevel(i, parseInt(e.target.value))}
                        className="absolute -left-3 -right-3 inset-y-0 opacity-0 cursor-pointer"
                        style={{ writingMode: "vertical-lr" as any, WebkitAppearance: "slider-vertical" as any, width: 54 }}
                        aria-label={`${ch.label} Fader`}
                        data-testid={`fader-${ch.id}`}
                      />
                    </div>
                  </div>

                  <div className="mt-2 text-center">
                    <div className="text-[10px] font-bold tracking-[0.08em] text-zinc-100">{ch.label}</div>
                    <div className="etch text-[8px] mt-0.5">{ch.sub}</div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>

      {/* === VOICE FX (decorative in Stufe 1) === */}
      <div className="px-3 pb-3">
        <div className="panel-metal rounded-lg p-3 relative">
          <div className="flex items-center justify-between mb-2.5">
            <div className="etch-strong text-[10px] tracking-[0.25em] font-mono font-semibold">VOICE FX</div>
            <span className="etch">preview</span>
          </div>
          <div className="grid grid-cols-3 gap-3 opacity-50">
            <div className="flex flex-col items-center gap-2">
              <div className="relative" style={{ width: 48, height: 48 }}>
                <div className="knob w-full h-full" style={{ transform: `rotate(${knobRot(pitchSemi)}deg)` }} />
                <input
                  type="range" min={0} max={100} value={pitchSemi}
                  onChange={(e) => setPitchSemi(parseInt(e.target.value))}
                  className="absolute inset-0 opacity-0 cursor-pointer rounded-full"
                  aria-label="Pitch" data-testid="knob-pitch"
                />
              </div>
              <div className="lcd-screen rounded-sm px-1.5 py-0.5 text-[10px] font-bold tabular-nums min-w-[42px] text-center">
                {pitchVal > 0 ? `+${pitchVal}` : pitchVal} st
              </div>
              <div className="etch">pitch</div>
            </div>

            <div className="flex flex-col items-center gap-2">
              <div className="relative" style={{ width: 48, height: 48 }}>
                <div className="knob w-full h-full" style={{ transform: `rotate(${-135 + (keyIdx / (KEYS.length - 1)) * 270}deg)` }} />
                <input
                  type="range" min={0} max={KEYS.length - 1} value={keyIdx}
                  onChange={(e) => setKeyIdx(parseInt(e.target.value))}
                  className="absolute inset-0 opacity-0 cursor-pointer rounded-full"
                  aria-label="Tonart" data-testid="knob-key"
                />
              </div>
              <div className="lcd-screen rounded-sm px-1.5 py-0.5 text-[10px] font-bold min-w-[42px] text-center">
                {KEYS[keyIdx]}
              </div>
              <div className="etch">key</div>
            </div>

            <div className="flex flex-col items-center gap-2">
              <button
                onClick={() => setAutotuneOn((v) => !v)}
                className={`hw-btn ${autotuneOn ? "orange" : ""} w-full h-12 flex flex-col items-center justify-center gap-1`}
                data-testid="button-autotune"
              >
                <span className={`led-pill ${autotuneOn ? "on" : ""}`} />
                <span className="text-[9px] font-bold tracking-[0.15em]">{autotuneOn ? "ON" : "OFF"}</span>
              </button>
              <div className="etch">autotune</div>
            </div>
          </div>
          <div className="etch text-[8px] text-center mt-2 opacity-70">coming soon · live-DSP in stufe 2</div>
        </div>
      </div>

      {/* === CUE PADS + TRANSPORT === */}
      <div className="px-3 pb-4">
        <div className="panel-metal rounded-lg p-3">
          <div className="flex items-center justify-between mb-2.5">
            <div className="etch-strong text-[10px] tracking-[0.25em] font-mono font-semibold">CUE PADS</div>
            <span className="etch">{markers.length} markers</span>
          </div>

          <div className="grid grid-cols-4 gap-1.5 mb-3">
            {Array.from({ length: 8 }).map((_, i) => {
              const lit = cuesActive[i] != null;
              return (
                <button
                  key={i}
                  onClick={() => handleCue(i)}
                  className={`perf-pad ${lit ? "lit" : ""} tap-target h-12 flex flex-col items-center justify-center`}
                  data-testid={`button-cue-${i + 1}`}
                  aria-label={`Cue ${i + 1}`}
                >
                  <span className="pad-lamp" />
                  <span className="text-[9px] font-mono tracking-[0.16em] text-zinc-400 uppercase">cue</span>
                  <span className="text-[13px] font-bold text-zinc-100 -mt-0.5">{i + 1}</span>
                </button>
              );
            })}
          </div>

          <div className="grid grid-cols-[1fr_auto_1fr] gap-2 items-center">
            <button
              onClick={handleStop}
              disabled={state === "idle" || busy}
              className="hw-btn h-12 flex items-center justify-center gap-2 text-[10px] font-bold tracking-[0.20em] uppercase disabled:opacity-40"
              data-testid="button-stop"
            >
              <span className="w-2.5 h-2.5 bg-current" />
              Stop
            </button>

            <button
              onClick={handleRecord}
              disabled={busy}
              className={`hw-btn orange ${isRec ? "record-pulse" : ""} h-14 w-14 rounded-full flex items-center justify-center relative disabled:opacity-50`}
              data-testid="button-record"
              aria-label={state === "idle" ? "Aufnahme starten" : "Aufnahme stoppen"}
            >
              {isRec ? (
                <span className="w-4 h-4 bg-white" />
              ) : (
                <span className="w-5 h-5 rounded-full bg-white" />
              )}
            </button>

            <button
              onClick={() => state === "recording" && setMarkers((m) => [...m, seconds])}
              disabled={state !== "recording"}
              className="hw-btn h-12 flex items-center justify-center gap-2 text-[10px] font-bold tracking-[0.20em] uppercase disabled:opacity-40"
              data-testid="button-mark"
            >
              <span className="w-1.5 h-1.5 rounded-full bg-current" />
              Mark
            </button>
          </div>

          <div className="etch text-center mt-2.5">
            {busy && state === "idle" && "öffne mikrofon..."}
            {busy && state !== "idle" && "speichere tape..."}
            {!busy && state === "idle" && "press \u25CF to record"}
            {!busy && state === "recording" && "recording \u2014 tap pads to drop markers"}
            {!busy && state === "paused" && "paused"}
          </div>
        </div>
      </div>
    </div>
  );
}
