import React, { useState, useEffect, useRef } from "react";
import { FiSend, FiUser } from "react-icons/fi";
import { FaMicrophone, FaStop } from "react-icons/fa";
import { motion, AnimatePresence } from "framer-motion";
import { v4 as uuidv4 } from "uuid";
import { API_LLM, API_TTS, WS_URL } from "../config/api";

export default function AssistantChat({ onAudioGenerated, audioRef }) {
  const [messages, setMessages] = useState([]);
  const [inputText, setInputText] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [recording, setRecording] = useState(false);
  const [transcript, setTranscript] = useState("");
  const [responseText, setResponseText] = useState("");
  const [isProcessing, setIsProcessing] = useState(false);
  const [history, setHistory] = useState([]);
  const [userId] = useState(uuidv4());

  const audioContextRef = useRef(null);
  const mediaStreamRef = useRef(null);
  const wsRef = useRef(null);
  const messagesEndRef = useRef(null);
  const isStoppingRef = useRef(false);
  const workletNodeRef = useRef(null);

  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
    return () => stopRecording();
  }, [messages]);

  const sendMessage = async () => {
    const userMsg = inputText.trim();
    if (!userMsg || isLoading) return;

    setIsLoading(true);
    setMessages((prev) => [...prev, { sender: "user", text: userMsg, timestamp: new Date() }]);
    setInputText("");

    try {
      const updatedHistory = [...history, { role: "user", content: userMsg }];

      const llmResp = await fetch(API_LLM, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ text: userMsg, user_id: userId, history: updatedHistory }),
      });
      const llmData = await llmResp.json();

      if (!llmResp.ok) {
        throw new Error(llmData.detail || "Erreur serveur LLM");
      }

      const assistantText = llmData?.response || "Je n'ai pas compris.";
      const lang = llmData?.lang || "fr";
      const newHistory = llmData?.history || updatedHistory;

      console.log("Requête texte envoyée:", { text: userMsg, user_id: userId, history: updatedHistory });
      console.log("Réponse LLM reçue:", llmData);

      setMessages((prev) => [...prev, { sender: "assistant", text: assistantText, timestamp: new Date() }]);
      setHistory(newHistory);

      const ttsResp = await fetch(API_TTS, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ text: assistantText, lang }),
      });
      const ttsData = await ttsResp.json();
      const audioUrl = ttsData?.url;

      if (audioUrl) {
        onAudioGenerated?.(audioUrl);
        if (audioRef?.current) {
          audioRef.current.src = audioUrl;
          audioRef.current.crossOrigin = "anonymous";
          await audioRef.current.play().catch((err) => {
            console.warn("Erreur lecture audio:", err);
          });
        }
      }
    } catch (err) {
      console.warn("Erreur LLM/TTS:", err);
      setMessages((prev) => [...prev, { sender: "assistant", text: "Erreur serveur.", timestamp: new Date() }]);
    } finally {
      setIsLoading(false);
    }
  };

  const handleKeyDown = (e) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      sendMessage();
    }
  };

  const startRecording = async () => {
    if (recording || isProcessing) return;
    isStoppingRef.current = false;

    try {
      setTranscript("");
      setResponseText("");
      setIsProcessing(true);

      const audioContext = new (window.AudioContext || window.webkitAudioContext)({
        sampleRate: 16000,
      });
      audioContextRef.current = audioContext;

      const stream = await navigator.mediaDevices.getUserMedia({
        audio: { channelCount: 1, echoCancellation: true, noiseSuppression: true, autoGainControl: true },
      });
      mediaStreamRef.current = stream;

      const source = audioContext.createMediaStreamSource(stream);
      await audioContext.audioWorklet.addModule("/pcm-worklet.js").catch((err) => {
        throw new Error("Échec chargement pcm-worklet.js: " + err.message);
      });
      const recorderNode = new AudioWorkletNode(audioContext, "pcm-processor", {
        processorOptions: {
          sampleRate: 16000,
          inputSampleRate: audioContext.sampleRate,
          chunkSize: 1024,
          silenceThreshold: 0.01,
          silenceWindow: 3,
        },
      });
      workletNodeRef.current = recorderNode;
      source.connect(recorderNode);

      const ws = new WebSocket(`${WS_URL}/live_stream/${userId}?room_id=room1`);
      ws.binaryType = "arraybuffer";
      wsRef.current = ws;

      ws.onopen = () => {
        ws.send(JSON.stringify({ type: "start", sampleRate: 16000, format: "pcm16", channels: 1 }));
        setRecording(true);
        setIsProcessing(false);
      };

      ws.onmessage = async (event) => {
        const msg = event.data;
        console.log("WebSocket message:", msg);
        if (typeof msg === "string") {
          const langRegex = new RegExp(`${userId}\\((fr|en|ar)\\): (.+)`);
          const match = msg.match(langRegex);
          if (match) {
            const trans = match[2].trim();
            if (trans) {
              setTranscript((prev) => prev + trans + " ");
              setMessages((prev) => [...prev, { sender: "user", text: trans, timestamp: new Date() }]);
              setHistory((prev) => [...prev, { role: "user", content: trans }]);
            }
          } else if (msg.startsWith("Système: ")) {
            const resp = msg.replace("Système: ", "").trim();
            if (resp) {
              setResponseText((prev) => prev + resp + " ");
              setMessages((prev) => [...prev, { sender: "assistant", text: resp, timestamp: new Date() }]);
              setHistory((prev) => [...prev, { role: "assistant", content: resp }]);
            }
          } else {
            try {
              const data = JSON.parse(msg);
              if (data.type === "pong") return;
              if (data.type === "stopped") {
                safeStopRecording();
                return;
              }
              if (data.type === "error" && data.message?.trim()) {
                console.error("Erreur WebSocket:", data.message); // Log l'erreur dans la console
                setMessages((prev) => [...prev, { sender: "assistant", text: data.message.trim(), timestamp: new Date() }]);
                setHistory((prev) => [...prev, { role: "assistant", content: data.message.trim() }]);
              } else if (data.message?.trim()) {
                setResponseText((prev) => prev + data.message + " ");
                setMessages((prev) => [...prev, { sender: "assistant", text: data.message.trim(), timestamp: new Date() }]);
                setHistory((prev) => [...prev, { role: "assistant", content: data.message.trim() }]);
              }
            } catch {}
          }
        } else if (msg instanceof ArrayBuffer || msg instanceof Blob) {
          const blob = msg instanceof Blob ? msg : new Blob([msg], { type: "audio/wav" });
          const url = URL.createObjectURL(blob);
          if (audioRef?.current) {
            audioRef.current.src = url;
            await audioRef.current.play().catch((err) => {
              console.warn("Erreur lecture audio:", err);
            });
          }
        }
      };

      ws.onclose = (e) => {
        if (!isStoppingRef.current && e.code !== 1000) {
          setTimeout(startRecording, 1000);
        }
        safeStopRecording();
      };

      ws.onerror = (err) => {
        console.warn("Erreur WebSocket:", err);
        safeStopRecording();
      };

      recorderNode.port.onmessage = (e) => {
        const { buffer } = e.data || {};
        if (buffer && ws.readyState === WebSocket.OPEN && !isStoppingRef.current) {
          ws.send(buffer);
        }
      };

      wsRef.current.pingInterval = setInterval(() => {
        if (ws.readyState === WebSocket.OPEN) {
          ws.send(JSON.stringify({ type: "ping" }));
        }
      }, 20000);
    } catch (err) {
      console.warn("Erreur enregistrement:", err);
      console.error("Micro inaccessible:", err?.message || "Erreur inconnue");
      safeStopRecording();
    }
  };

  const safeStopRecording = () => {
    if (isStoppingRef.current) return;
    isStoppingRef.current = true;

    try {
      workletNodeRef.current?.port?.postMessage({ type: "flush" });
    } catch {}

    try {
      if (wsRef.current?.readyState === WebSocket.OPEN) {
        wsRef.current.send(JSON.stringify({ type: "stop" }));
      }
    } catch {}

    if (wsRef.current?.pingInterval) clearInterval(wsRef.current.pingInterval);

    try {
      mediaStreamRef.current?.getTracks()?.forEach((t) => t.stop());
    } catch {}
    mediaStreamRef.current = null;

    try {
      audioContextRef.current?.close();
    } catch {}
    audioContextRef.current = null;

    if (transcript.trim() && !messages.some((msg) => msg.sender === "user" && msg.text === transcript.trim())) {
      setMessages((prev) => [...prev, { sender: "user", text: transcript.trim(), timestamp: new Date() }]);
      setHistory((prev) => [...prev, { role: "user", content: transcript.trim() }]);
    }

    setRecording(false);
    setIsProcessing(false);
    setTranscript("");
    setResponseText("");

    workletNodeRef.current = null;
    wsRef.current = null;
  };

  const stopRecording = () => {
    if (wsRef.current?.readyState === WebSocket.OPEN) {
      wsRef.current.send(JSON.stringify({ type: "stop" }));
    }
  };

  const formatTime = (date) => date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });

  return (
    <div className="flex flex-col h-full">
      <div className="flex-1 overflow-y-auto p-3 space-y-3 bg-gray-50/50 rounded-2xl shadow-inner">
        <AnimatePresence initial={false}>
          {messages.map((msg, idx) => (
            <motion.div
              key={idx}
              initial={{ opacity: 0, y: 10 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0 }}
              className={`flex flex-col ${msg.sender === "user" ? "items-end" : "items-start"}`}
            >
              <div className="flex items-center mb-1">
                <div
                  className={`w-8 h-8 rounded-full flex items-center justify-center mr-2 ${
                    msg.sender === "user" ? "bg-blue-100 text-blue-600" : "bg-indigo-100 text-indigo-600"
                  }`}
                >
                  {msg.sender === "user" ? <FiUser size={16} /> : <div className="w-4 h-4 bg-indigo-600 rounded-full" />}
                </div>
                <span className="text-xs text-gray-500">
                  {msg.sender === "user" ? "Vous" : "Assistant"} • {formatTime(msg.timestamp)}
                </span>
              </div>
              <div
                className={`p-4 rounded-2xl max-w-[85%] shadow-md ${
                  msg.sender === "user" ? "bg-blue-500 text-white" : "bg-white text-gray-800"
                }`}
              >
                {msg.text}
              </div>
            </motion.div>
          ))}
        </AnimatePresence>
        <div ref={messagesEndRef} />
      </div>

      <div className="flex items-center space-x-2 mt-3">
        <div className="flex-1 flex bg-white/80 backdrop-blur-sm rounded-xl border border-gray-200 overflow-hidden">
          <input
            type="text"
            className="flex-1 px-4 py-3 focus:outline-none bg-transparent"
            placeholder="Écrivez votre message..."
            value={inputText}
            onChange={(e) => setInputText(e.target.value)}
            onKeyDown={handleKeyDown}
            disabled={isLoading || recording}
          />
          <button
            className={`flex items-center justify-center w-14 transition-colors ${
              isLoading || !inputText.trim()
                ? "bg-gray-300 text-gray-500"
                : "bg-gradient-to-r from-blue-500 to-indigo-600 text-white hover:from-blue-600 hover:to-indigo-700"
            }`}
            onClick={sendMessage}
            disabled={isLoading || !inputText.trim() || recording}
          >
            {isLoading ? (
              <div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" />
            ) : (
              <FiSend size={20} />
            )}
          </button>
        </div>

        <button
          onClick={recording ? stopRecording : startRecording}
          disabled={isProcessing}
          className={`w-16 h-16 rounded-full shadow-xl transition transform hover:scale-105 
            ${
              recording
                ? "bg-gradient-to-r from-blue-500 to-indigo-600 text-white"
                : "bg-gradient-to-r from-red-500 to-red-600 text-white"
            }
            flex items-center justify-center`}
        >
          {recording ? (
            <FaStop size={24} />
          ) : isProcessing ? (
            <div className="w-6 h-6 border-2 border-white border-t-transparent rounded-full animate-spin" />
          ) : (
            <FaMicrophone size={24} />
          )}
        </button>
      </div>
    </div>
  );
}