"use client";

import { createContext, useContext, useState, useRef, useCallback, useEffect } from "react";
import { createStompClient } from "@/lib/chatSocket";
import { useAuth } from "@/context/AuthContext";

//Chat widget context
//Manages both the AI chat and the live support chat
const ChatWidgetContext = createContext(null);
const API_BASE = "";

//Provides chat state and actions for the floating chat widget
export function ChatWidgetProvider({ children }) {
  const { user } = useAuth();
  const [isOpen, setIsOpen] = useState(false);
  const [view, setView] = useState("ai"); // "ai" | "history" | "live"

  //AI chat messages, loaded from localStorage so they survive page refreshes
  const [aiMessages, setAiMessages] = useState(() => {
    try {
      const saved = localStorage.getItem("fc_aiMessages");
      return saved ? JSON.parse(saved) : [];
    } catch { return []; }
  });
  const [aiSending, setAiSending] = useState(false);
  const [aiError, setAiError] = useState(null);

  //Save AI messages to localStorage whenever they change
  useEffect(() => {
    localStorage.setItem("fc_aiMessages", JSON.stringify(aiMessages));
  }, [aiMessages]);

  //Ref to the latest messages so the send function always sees current state
  const aiMessagesRef = useRef(aiMessages);
  useEffect(() => { aiMessagesRef.current = aiMessages; }, [aiMessages]);

  //Sends a message to the AI and appends the response to the chat
  const sendAiMessage = useCallback(async (text, token) => {
    if (!text.trim() || !token) return;
    const userMsg = { role: "user", content: text, id: Date.now() };
    setAiMessages((prev) => [...prev, userMsg]);
    setAiSending(true);
    setAiError(null);
    try {
      const history = aiMessagesRef.current.map((m) => ({ role: m.role, content: m.content }));
      const res = await fetch(`${API_BASE}/api/v1/ai-chat/message`, {
        method: "POST",
        headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
        body: JSON.stringify({ message: text, history }),
      });
      const data = await res.json();
      if (!res.ok || !data.success) { setAiError(data.error || "Failed to get a response."); return; }
      setAiMessages((prev) => [...prev, { role: "assistant", content: data.message, id: Date.now() + 1 }]);
    } catch {
      setAiError("Network error. Please try again.");
    } finally {
      setAiSending(false);
    }
  }, []);

  //Live chat state
  const [conversations, setConversations] = useState([]);
  const [convsLoading, setConvsLoading] = useState(false);
  const [activeConvId, setActiveConvId] = useState(null);
  const [activeConv, setActiveConv] = useState(null);
  const [liveMessages, setLiveMessages] = useState([]);
  const [liveSending, setLiveSending] = useState(false);
  const [switchingToHuman, setSwitchingToHuman] = useState(false);

  const stompRef = useRef(null);
  const activeConvIdRef = useRef(null);
  const tokenRef = useRef(null);

  //Disconnects the WebSocket if it is active
  const disconnectStomp = useCallback(() => {
    if (stompRef.current) {
      stompRef.current.deactivate();
      stompRef.current = null;
    }
  }, []);

  //Clears all chat state when the user logs out or switches accounts
  const prevUserIdRef = useRef(user?.id);
  useEffect(() => {
    const currentId = user?.id ?? null;
    const prevId = prevUserIdRef.current;
    prevUserIdRef.current = currentId;
    if (prevId !== null && prevId !== currentId) {
      setAiMessages([]);
      localStorage.removeItem("fc_aiMessages");
      setConversations([]);
      setActiveConvId(null);
      setActiveConv(null);
      setLiveMessages([]);
      disconnectStomp();
      setView("ai");
      setIsOpen(false);
    }
  }, [user?.id, disconnectStomp]);

  //Subscribes to incoming messages and conversation updates for a given chat
  const subscribeToConversation = useCallback((client, convId) => {
    client.subscribe(`/topic/chat/conversations/${convId}`, (frame) => {
      try {
        const msg = JSON.parse(frame.body);
        setLiveMessages((prev) => prev.some((m) => m.id === msg.id) ? prev : [...prev, msg]);
      } catch { /* silent */ }
    });
    client.subscribe(`/user/queue/chat/conversations`, (frame) => {
      try {
        const conv = JSON.parse(frame.body);
        if (conv.id === convId) setActiveConv(conv);
      } catch { /* silent */ }
    });
  }, []);

  const loadConversations = useCallback(async (token) => {
    if (!token) return;
    setConvsLoading(true);
    try {
      const res = await fetch(`${API_BASE}/api/v1/chat/conversations?mine=true`, {
        headers: { Authorization: `Bearer ${token}` },
      });
      if (!res.ok) return;
      const data = await res.json();
      setConversations(Array.isArray(data) ? data : (data.content ?? []));
    } catch { /* silent */ } finally {
      setConvsLoading(false);
    }
  }, []);

  const openLiveConversation = useCallback(async (convId, token) => {
    if (!convId || !token) return;
    disconnectStomp();
    tokenRef.current = token;
    setActiveConvId(convId);
    activeConvIdRef.current = convId;
    setLiveMessages([]);
    setView("live");

    try {
      const res = await fetch(`${API_BASE}/api/v1/chat/conversations/${convId}`, {
        headers: { Authorization: `Bearer ${token}` },
      });
      if (res.ok) setActiveConv(await res.json());
    } catch { /* silent */ }

    try {
      const res = await fetch(`${API_BASE}/api/v1/chat/conversations/${convId}/messages`, {
        headers: { Authorization: `Bearer ${token}` },
      });
      if (res.ok) {
        const data = await res.json();
        if (Array.isArray(data)) setLiveMessages(data);
      }
    } catch { /* silent */ }

    const client = createStompClient(token);
    client.onConnect = () => subscribeToConversation(client, convId);
    stompRef.current = client;
    client.activate();
  }, [disconnectStomp, subscribeToConversation]);

  const sendLiveMessage = useCallback(async (text, token, convId) => {
    if (!text.trim() || liveSending || !token || !convId) return;
    setLiveSending(true);
    try {
      const res = await fetch(`${API_BASE}/api/v1/chat/conversations/${convId}/messages`, {
        method: "POST",
        headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
        body: JSON.stringify({ content: text }),
      });
      if (res.ok) {
        const msg = await res.json();
        setLiveMessages((prev) => prev.some((m) => m.id === msg.id) ? prev : [...prev, msg]);
      }
    } catch { /* silent */ } finally {
      setLiveSending(false);
    }
  }, [liveSending]);

  //Creates a new live chat conversation and requests a human agent
  const startLiveChat = useCallback(async (token) => {
    if (!token || switchingToHuman) return;
    setSwitchingToHuman(true);
    try {
      const res = await fetch(`${API_BASE}/api/v1/chat/conversations`, {
        method: "POST",
        headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
        body: JSON.stringify({ message: "Hi, I'd like to speak with a support agent." }),
      });
      if (!res.ok) return;
      const conv = await res.json();
      await fetch(`${API_BASE}/api/v1/chat/conversations/${conv.id}/request-human`, {
        method: "POST", headers: { Authorization: `Bearer ${token}` },
      });
      setConversations((prev) => [conv, ...prev.filter((c) => c.id !== conv.id)]);
      await openLiveConversation(conv.id, token);
    } catch { /* silent */ } finally {
      setSwitchingToHuman(false);
    }
  }, [switchingToHuman, openLiveConversation]);

  useEffect(() => {
    if (!isOpen || view !== "live") {
      disconnectStomp();
    } else if (isOpen && view === "live" && activeConvIdRef.current && tokenRef.current && !stompRef.current) {
      const convId = activeConvIdRef.current;
      const token = tokenRef.current;
      const client = createStompClient(token);
      client.onConnect = () => subscribeToConversation(client, convId);
      stompRef.current = client;
      client.activate();
    }
  }, [isOpen, view, disconnectStomp, subscribeToConversation]);

  useEffect(() => {
    return () => disconnectStomp();
  }, [disconnectStomp]);

  const toggleOpen = useCallback(() => setIsOpen((o) => !o), []);
  const openView = useCallback((v) => setView(v), []);

  return (
    <ChatWidgetContext.Provider value={{
      isOpen, toggleOpen,
      view, openView,
      aiMessages, aiSending, aiError, setAiError, sendAiMessage,
      conversations, convsLoading, loadConversations,
      activeConvId, activeConv, liveMessages, liveSending,
      openLiveConversation, sendLiveMessage,
      startLiveChat, switchingToHuman,
    }}>
      {children}
    </ChatWidgetContext.Provider>
  );
}

//Hook to access chat widget state - must be used inside a ChatWidgetProvider
export function useChatWidget() {
  const ctx = useContext(ChatWidgetContext);
  if (!ctx) throw new Error("useChatWidget must be used within ChatWidgetProvider");
  return ctx;
}
