"use client";

import { useState, useRef, useCallback, useEffect } from "react";

interface VoiceRecorderProps {
  onVoiceReady: (audioUrl: string) => void;
  disabled?: boolean;
}

export default function VoiceRecorder({
  onVoiceReady,
  disabled,
}: VoiceRecorderProps) {
  const [recording, setRecording] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [duration, setDuration] = useState(0);
  const [bars, setBars] = useState<number[]>(Array(16).fill(4));
  const [micError, setMicError] = useState<string | null>(null);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<Blob[]>([]);
  const streamRef = useRef<MediaStream | null>(null);
  const analyserRef = useRef<AnalyserNode | null>(null);
  const animFrameRef = useRef<number>(0);
  const timerRef = useRef<ReturnType<typeof setInterval>>(undefined);

  // Clean up on unmount
  useEffect(() => {
    return () => {
      if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
      if (timerRef.current) clearInterval(timerRef.current);
      if (streamRef.current) {
        streamRef.current.getTracks().forEach((t) => t.stop());
      }
    };
  }, []);

  const startRecording = useCallback(async () => {
    setMicError(null);
    if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
      setMicError("Voice recording isn't supported on this browser.");
      return;
    }
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      streamRef.current = stream;

      // Set up analyser for waveform
      const audioCtx = new AudioContext();
      const source = audioCtx.createMediaStreamSource(stream);
      const analyser = audioCtx.createAnalyser();
      analyser.fftSize = 64;
      source.connect(analyser);
      analyserRef.current = analyser;

      const mimeType = MediaRecorder.isTypeSupported("audio/webm;codecs=opus")
        ? "audio/webm;codecs=opus"
        : "audio/webm";

      const mediaRecorder = new MediaRecorder(stream, { mimeType });
      mediaRecorderRef.current = mediaRecorder;
      chunksRef.current = [];

      mediaRecorder.ondataavailable = (e) => {
        if (e.data.size > 0) chunksRef.current.push(e.data);
      };

      mediaRecorder.onstop = async () => {
        // Stop visualizer
        if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
        if (timerRef.current) clearInterval(timerRef.current);

        // Stop stream
        stream.getTracks().forEach((t) => t.stop());
        streamRef.current = null;

        const blob = new Blob(chunksRef.current, { type: mimeType });
        if (blob.size === 0) return;

        // Upload
        setUploading(true);
        try {
          const formData = new FormData();
          formData.append("file", blob, `voice-${Date.now()}.webm`);
          const res = await fetch("/api/upload/voice", {
            method: "POST",
            body: formData,
          });
          if (res.ok) {
            const data = await res.json();
            if (data.url) onVoiceReady(data.url);
          }
        } catch (err) {
          console.error("Voice upload failed:", err);
        } finally {
          setUploading(false);
          setDuration(0);
          setBars(Array(16).fill(4));
        }
      };

      mediaRecorder.start(250);
      setRecording(true);
      setDuration(0);

      // Duration timer
      timerRef.current = setInterval(() => {
        setDuration((d) => d + 1);
      }, 1000);

      // Waveform animation
      const updateBars = () => {
        if (!analyserRef.current) return;
        const data = new Uint8Array(analyserRef.current.frequencyBinCount);
        analyserRef.current.getByteFrequencyData(data);
        const barCount = 16;
        const step = Math.floor(data.length / barCount);
        const newBars = Array.from({ length: barCount }, (_, i) => {
          const val = data[i * step] || 0;
          return Math.max(4, (val / 255) * 32);
        });
        setBars(newBars);
        animFrameRef.current = requestAnimationFrame(updateBars);
      };
      updateBars();
    } catch (err) {
      console.error("Microphone access denied:", err);
      const msg =
        err instanceof DOMException && err.name === "NotAllowedError"
          ? "Microphone access denied. Allow it in your browser settings to record voice messages."
          : "Couldn't access the microphone. Please try again.";
      setMicError(msg);
    }
  }, [onVoiceReady]);

  const stopRecording = useCallback(() => {
    if (
      mediaRecorderRef.current &&
      mediaRecorderRef.current.state !== "inactive"
    ) {
      mediaRecorderRef.current.stop();
    }
    setRecording(false);
  }, []);

  const formatDuration = (s: number) => {
    const m = Math.floor(s / 60);
    const sec = s % 60;
    return `${m}:${sec.toString().padStart(2, "0")}`;
  };

  if (uploading) {
    return (
      <div className="flex items-center gap-2 px-3 py-2 rounded-xl bg-surface-light border border-white/10">
        <svg
          className="w-5 h-5 animate-spin text-primary"
          fill="none"
          viewBox="0 0 24 24"
        >
          <circle
            className="opacity-25"
            cx="12"
            cy="12"
            r="10"
            stroke="currentColor"
            strokeWidth="4"
          />
          <path
            className="opacity-75"
            fill="currentColor"
            d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
          />
        </svg>
        <span className="text-xs text-text-muted">Sending voice...</span>
      </div>
    );
  }

  if (recording) {
    return (
      <div className="flex items-center gap-2 px-3 py-2 rounded-xl bg-red-500/10 border border-red-500/30">
        {/* Waveform visualization */}
        <div className="flex items-center gap-[2px] h-8">
          {bars.map((h, i) => (
            <div
              key={i}
              className="w-[3px] bg-red-400 rounded-full transition-all duration-100"
              style={{ height: `${h}px` }}
            />
          ))}
        </div>
        <span className="text-xs text-red-400 font-mono min-w-[3rem] text-center">
          {formatDuration(duration)}
        </span>
        <button
          type="button"
          onClick={stopRecording}
          className="flex items-center justify-center w-9 h-9 rounded-full bg-red-500 hover:bg-red-600 text-white transition-colors"
          title="Stop recording"
        >
          <svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
            <rect x="6" y="6" width="12" height="12" rx="2" />
          </svg>
        </button>
      </div>
    );
  }

  return (
    <div className="flex flex-col items-end gap-1">
      <button
        type="button"
        onClick={startRecording}
        disabled={disabled}
        aria-label="Record voice message"
        className="flex items-center justify-center w-11 h-11 rounded-xl bg-surface hover:bg-surface-light border border-white/10 text-text-muted hover:text-primary transition-all disabled:opacity-40 disabled:cursor-not-allowed"
        title="Send voice message"
      >
        <svg
          className="w-5 h-5"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
        >
          <path
            strokeLinecap="round"
            strokeLinejoin="round"
            strokeWidth={2}
            d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"
          />
        </svg>
      </button>
      {micError && (
        <p role="alert" className="text-[11px] text-red-400 max-w-[14rem] text-right leading-tight">
          {micError}
        </p>
      )}
    </div>
  );
}
