import { useState, useRef, useEffect } from "react";
import { createSocket } from "../api";

export default function Recorder({ onResult }) {
  const [recording, setRecording] = useState(false);
  const [status, setStatus] = useState("idle"); // idle | recording | analyzing | error
  const [bars, setBars] = useState(new Array(30).fill(3));

  const mediaRecorderRef = useRef(null);
  const socketRef = useRef(null);
  const analyserRef = useRef(null);
  const animFrameRef = useRef(null);
  const chunksRef = useRef([]);

  const audioChunksRef = useRef([]);
  const processorRef = useRef(null);
  const streamRef = useRef(null);

  // Clean up on unmount
  useEffect(() => {
    return () => {
      stopVisualization();
      if (socketRef.current) socketRef.current.close();
    };
  }, []);

  const startVisualization = (stream) => {
    const ctx = new AudioContext();
    const source = ctx.createMediaStreamSource(stream);
    const analyser = ctx.createAnalyser();
    analyser.fftSize = 64;
    source.connect(analyser);
    analyserRef.current = analyser;

    const data = new Uint8Array(analyser.frequencyBinCount);
    const tick = () => {
      analyser.getByteFrequencyData(data);
      const slice = Array.from(data).slice(0, 30);
      setBars(slice.map((v) => Math.max(3, (v / 255) * 60)));
      animFrameRef.current = requestAnimationFrame(tick);
    };
    tick();
  };

  const stopVisualization = () => {
    if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
    setBars(new Array(30).fill(3));
  };

  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });

      // Connect WebSocket
      socketRef.current = createSocket(
        (data) => {
          setStatus("idle");
          onResult(data);
        },
        () => setStatus("error")
      );

      startVisualization(stream);
      //chunksRef.current = [];

      //const mr = new MediaRecorder(stream, { mimeType: "audio/webm" });
      //mr.ondataavailable = (e) => {
        //if (e.data.size > 0) chunksRef.current.push(e.data);
      //};
      //mr.onstop = () => {
      //  const blob = new Blob(chunksRef.current, { type: "audio/webm" });
      //  setStatus("analyzing");
      //  socketRef.current.sendAudio(blob);
      //  stream.getTracks().forEach((t) => t.stop());
      //  stopVisualization();
      //};

      //mediaRecorderRef.current = mr;
      //mr.start();
      const audioContext = new AudioContext({ sampleRate: 16000 });
      const source = audioContext.createMediaStreamSource(stream);
      const processor = audioContext.createScriptProcessor(4096, 1, 1);

      processorRef.current = processor;
      streamRef.current = stream;
      audioChunksRef.current = []; // reset buffer

      source.connect(processor);
      processor.connect(audioContext.destination);

      processor.onaudioprocess = (event) => {
        const input = event.inputBuffer.getChannelData(0);

        const buffer = new ArrayBuffer(input.length * 2);
        const view = new DataView(buffer);

        for (let i = 0; i < input.length; i++) {
          let s = Math.max(-1, Math.min(1, input[i]));
          view.setInt16(i * 2, s * 0x7fff, true);
        }

        //STORE instead of sending
        audioChunksRef.current.push(buffer);
      };
      setRecording(true);
      setStatus("recording");
    } catch (err) {
      console.error("Microphone access denied", err);
      setStatus("error");
    }
  };

  const stopRecording = () => {
    setRecording(false);
    setStatus("analyzing");

    stopVisualization();

    //Stop audio processing
    if (processorRef.current) {
      processorRef.current.disconnect();
    }

    if (streamRef.current) {
      streamRef.current.getTracks().forEach((t) => t.stop());
    }

    //Merge all chunks into ONE buffer
    const totalLength = audioChunksRef.current.reduce(
      (sum, buf) => sum + buf.byteLength,
      0
    );

    const combined = new Uint8Array(totalLength);
    let offset = 0;

    audioChunksRef.current.forEach((buf) => {
      combined.set(new Uint8Array(buf), offset);
      offset += buf.byteLength;
    });

    //Send once
    socketRef.current.sendAudio(combined.buffer);
  };

  const statusText = {
    idle:      "Press to start recording",
    recording: "Recording... press to stop",
    analyzing: "Analyzing emotion...",
    error:     "Error — check mic & backend",
  }[status];

  return (
    <div style={styles.wrapper}>
      {/* Waveform */}
      <div style={styles.waveform}>
        {bars.map((h, i) => (
          <div
            key={i}
            style={{
              ...styles.bar,
              height: `${h}px`,
              backgroundColor: recording ? "#6366f1" : "#334155",
              transition: recording ? "height 0.05s" : "height 0.3s",
            }}
          />
        ))}
      </div>

      {/* Mic button */}
      <button
        onClick={recording ? stopRecording : startRecording}
        disabled={status === "analyzing"}
        style={{
          ...styles.btn,
          backgroundColor: recording ? "#ef4444" : "#6366f1",
          transform: recording ? "scale(1.08)" : "scale(1)",
        }}
      >
        {recording ? "⏹" : "🎤"}
      </button>

      <p style={styles.status}>{statusText}</p>
    </div>
  );
}

const styles = {
  wrapper: {
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    gap: "16px",
    width: "100%",
  },
  waveform: {
    display: "flex",
    alignItems: "center",
    gap: "3px",
    height: "64px",
    width: "100%",
    justifyContent: "center",
  },
  bar: {
    width: "6px",
    borderRadius: "3px",
    minHeight: "3px",
  },
  btn: {
    width: "72px",
    height: "72px",
    borderRadius: "50%",
    border: "none",
    fontSize: "28px",
    cursor: "pointer",
    transition: "background-color 0.2s, transform 0.2s",
    boxShadow: "0 4px 20px rgba(99,102,241,0.4)",
  },
  status: {
    color: "#94a3b8",
    fontSize: "14px",
    margin: 0,
  },
};