"use client";

import { useEffect, useRef, useState } from "react";
import { Drawer } from "vaul";
// import CategorySelector from "./CategorySelector";
import ChatMessages from "./ChatMessages";
import ChatInput from "./ChatInput";
import ChatHistory from "./ChatHistory";
import Image from "next/image";
import {
  AlertCircle,
  History,
  Loader2,
  RefreshCw,
  TriangleAlert,
  X,
  XCircle,
} from "lucide-react";

type Role = "user" | "assistant" | "system";

export interface ChatSource {
  title: string;
  link: string;
  relevance_rank: number;
}

export interface ChatMessage {
  id: string;
  role: Role;
  content: string;
  sources?: ChatSource[];
}

// const CATEGORIES = [
//   { id: "operation manual", label: "Operation Manual" },
//   { id: "marketing", label: "Marketing" },
// ];

type UiNoticeType = "error" | "warning" | "info";

interface UiNotice {
  type: UiNoticeType;
  title: string;
  message: string;
}

export default function ChatWidget({
  embedded = false,
}: {
  embedded?: boolean;
}) {
  const [isOpen, setIsOpen] = useState(false);
  const [category, setCategory] = useState<string | null>(null);
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [isStreaming, setIsStreaming] = useState(false);
  const [sessionId, setSessionId] = useState<string>("");
  const [hasUnread, setHasUnread] = useState(false);
  const [threadId, setThreadId] = useState<string | null>(null);
  const [showThreadHistory, setShowThreadHistory] = useState(false);
  const [isLoadingThread, setIsLoadingThread] = useState(false);
  const [isCreatingThread, setIsCreatingThread] = useState(false);
  const [userId, setUserId] = useState<string>("dummy-user-001");
  const [authToken, setAuthToken] = useState<string | null>(null);
  const [uiNotice, setUiNotice] = useState<UiNotice | null>(null);

  const streamIntervalRef = useRef<number | null>(null);
  const isFirstMessageRef = useRef(true);

  useEffect(() => {
    if (!sessionId) setSessionId(crypto.randomUUID());
  }, [sessionId]);

  useEffect(() => {
    const handleMessage = (event: MessageEvent) => {
      if (event.data.type === "CHATBOT_OPEN") {
        setIsOpen(true);
        if (event.data.userId) {
          setUserId(event.data.userId);
        }
        setAuthToken(event.data.token || null);
      } else if (event.data.type === "CHATBOT_CLOSE") {
        setIsOpen(false);
      }
    };

    window.addEventListener("message", handleMessage);
    return () => window.removeEventListener("message", handleMessage);
  }, []);

  useEffect(() => {
    if (isOpen) {
      setHasUnread(false);
    }
  }, [isOpen]);

  const authHeaders = (): Record<string, string> => ({
    ...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
  });

  const showNotice = (type: UiNoticeType, title: string, message: string) => {
    setUiNotice({ type, title, message });
  };

  const clearNotice = () => {
    setUiNotice(null);
  };

  const getErrorMessageFromResponse = async (
    response: Response,
    fallback: string,
  ) => {
    try {
      const data = await response.json();

      return (
        data?.message ||
        data?.error ||
        data?.detail ||
        data?.errors?.[0]?.message ||
        fallback
      );
    } catch {
      return fallback;
    }
  };

  const createThread = async (): Promise<string | null> => {
    try {
      setIsCreatingThread(true);
      clearNotice();

      const response = await fetch(`/api/threads?user_id=${userId}`, {
        method: "POST",
        headers: authHeaders(),
      });

      if (!response.ok) {
        const message = await getErrorMessageFromResponse(
          response,
          "We could not start a new conversation right now. Please try again.",
        );

        showNotice("error", "Unable to start conversation", message);
        return null;
      }

      const data = await response.json();

      const createdThreadId =
        data.thread_id ||
        data.id ||
        data._id ||
        (data.thread &&
          (data.thread.id || data.thread.thread_id || data.thread._id)) ||
        null;

      if (!createdThreadId) {
        showNotice(
          "error",
          "Conversation setup failed",
          "The server responded, but no valid thread was returned. Please try again.",
        );
        return null;
      }

      return createdThreadId;
    } catch (error) {
      console.error("Error creating thread:", error);
      showNotice(
        "error",
        "Connection problem",
        "Unable to connect right now. Please check your internet or try again shortly.",
      );
      return null;
    } finally {
      setIsCreatingThread(false);
    }
  };

  const loadThreadMessages = async (selectedThreadId: string) => {
    try {
      clearNotice();
      setMessages([]);
      setIsLoadingThread(true);

      const response = await fetch(
        `/api/threads/${selectedThreadId}/messages?user_id=${userId}&limit=50`,
        {
          method: "GET",
          headers: authHeaders(),
        },
      );

      if (!response.ok) {
        const message = await getErrorMessageFromResponse(
          response,
          "We could not load this conversation.",
        );

        showNotice("error", "Unable to load history", message);
        return;
      }

      const data = await response.json();

      if (data.messages && Array.isArray(data.messages)) {
        const historyMessages: ChatMessage[] = [];
        let detectedCategory: string | null = null;

        data.messages.forEach((msg: any) => {
          const timestamp = msg.timestamp || Date.now();

          // Each record packs one full turn: `message` is the user's text
          // and `response` is the assistant's reply (message_type is not a
          // reliable discriminator — the backend sets it to "assistant" on
          // both fields).
          const userText = msg.message ?? msg.question;
          const assistantText = msg.response ?? msg.answer;

          if (userText) {
            historyMessages.push({
              id: `user-${timestamp}-${Math.random()}`,
              role: "user",
              content: userText,
            });
          }

          if (assistantText) {
            historyMessages.push({
              id: `assistant-${timestamp}-${Math.random()}`,
              role: "assistant",
              content: assistantText,
              sources: Array.isArray(msg.sources) ? msg.sources : [],
            });

            if (!detectedCategory && msg.category) {
              detectedCategory = msg.category;
            }
          }
        });

        setMessages(historyMessages);

        if (detectedCategory) {
          const mappedCategory =
            detectedCategory === "operation-manual"
              ? "operation manual"
              : detectedCategory;
          setCategory(mappedCategory);
        }

        isFirstMessageRef.current = false;
      }
    } catch (error) {
      console.error("Error loading thread messages:", error);
      showNotice(
        "error",
        "History loading failed",
        "Something went wrong while loading this conversation. Please try again.",
      );
    } finally {
      setIsLoadingThread(false);
    }
  };

  const clearStreamInterval = () => {
    if (streamIntervalRef.current !== null) {
      window.clearInterval(streamIntervalRef.current);
      streamIntervalRef.current = null;
    }
  };

  const handleToggle = () => {
    if (embedded) {
      window.parent.postMessage({ type: "CLOSE_CHATBOT" }, "*");
    } else {
      setIsOpen((prev) => !prev);
    }
  };

  const handleNewChat = () => {
    clearStreamInterval();
    clearNotice();
    setMessages([]);
    setCategory(null);
    setIsStreaming(false);
    setThreadId(null);
    setSessionId(crypto.randomUUID());
    isFirstMessageRef.current = true;
  };

  const handleStop = () => {
    if (!isStreaming) return;
    clearStreamInterval();
    setIsStreaming(false);

    showNotice(
      "info",
      "Response stopped",
      "The reply was stopped. You can send a new message any time.",
    );
  };

  const handleSend = async (prompt: string) => {
    if (!prompt.trim() || isStreaming) return;

    clearNotice();

    const trimmedPrompt = prompt.trim();

    const userMessage: ChatMessage = {
      id: crypto.randomUUID(),
      role: "user",
      content: trimmedPrompt,
    };

    const assistantMessage: ChatMessage = {
      id: crypto.randomUUID(),
      role: "assistant",
      content: "",
      sources: [],
    };

    setMessages((prev) => [...prev, userMessage, assistantMessage]);
    setIsStreaming(true);

    try {
      const response = await fetch("/api/ask-question", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          ...authHeaders(),
        },
        body: JSON.stringify({
          question: trimmedPrompt,
          user_id: userId,
          thread_id: threadId,
        }),
      });

      if (!response.ok) {
        const message = await getErrorMessageFromResponse(
          response,
          "Sorry, I couldn’t get a response right now. Please try again.",
        );

        showNotice("error", "Response failed", message);

        setMessages((prev) =>
          prev.map((m) =>
            m.id === assistantMessage.id ? { ...m, content: message } : m,
          ),
        );

        setIsStreaming(false);
        return;
      }

      const data = await response.json();

      if (data?.thread_id && !threadId) {
        setThreadId(data.thread_id);
      }

      const fullText =
        data?.answer ||
        data?.response ||
        data?.result ||
        "Sorry, I couldn't understand the response.";

      const incomingSources: ChatSource[] = Array.isArray(data?.sources)
        ? [...data.sources].sort(
            (a, b) => (a?.relevance_rank ?? 999) - (b?.relevance_rank ?? 999),
          )
        : [];

      let index = 0;
      clearStreamInterval();

      streamIntervalRef.current = window.setInterval(() => {
        index += 4;

        setMessages((prev) =>
          prev.map((m) =>
            m.id === assistantMessage.id
              ? {
                  ...m,
                  content: fullText.slice(0, index),
                  sources: incomingSources,
                }
              : m,
          ),
        );

        if (index >= fullText.length) {
          clearStreamInterval();
          setIsStreaming(false);

          if (!embedded && !isOpen) {
            setHasUnread(true);
          }
        }
      }, 18);
    } catch (error) {
      console.error("Error sending message:", error);
      clearStreamInterval();
      setIsStreaming(false);

      const fallbackMessage =
        "Something went wrong while contacting the server. Please try again.";

      showNotice("error", "Server communication failed", fallbackMessage);

      setMessages((prev) =>
        prev.map((m) =>
          m.id === assistantMessage.id ? { ...m, content: fallbackMessage } : m,
        ),
      );
    }
  };

  const handleRegenerate = (_assistantId: string) => {
    const lastUser = [...messages].reverse().find((m) => m.role === "user");

    if (!lastUser) {
      showNotice(
        "warning",
        "Nothing to regenerate",
        "There is no previous user message available to regenerate.",
      );
      return;
    }

    handleSend(lastUser.content);
  };

  const handleSelectThread = async (selectedThreadId: string) => {
    setThreadId(selectedThreadId);
    setShowThreadHistory(false);
    await loadThreadMessages(selectedThreadId);
  };

  const handleDeleteThread = (deletedThreadId: string) => {
    if (threadId === deletedThreadId) {
      handleNewChat();
    }
  };

  const canSend = !isStreaming && !isCreatingThread;

  const noticeStyles = {
    error: "border-red-200 bg-red-50 text-red-800",
    warning: "border-amber-200 bg-amber-50 text-amber-800",
    info: "border-sky-200 bg-sky-50 text-sky-800",
  };

  const noticeIcon = {
    error: <XCircle className="h-4 w-4 shrink-0 mt-0.5" />,
    warning: <TriangleAlert className="h-4 w-4 shrink-0 mt-0.5" />,
    info: <AlertCircle className="h-4 w-4 shrink-0 mt-0.5" />,
  };

  return (
    <>
      {!embedded && (
        <button
          onClick={handleToggle}
          className="fixed bottom-6 right-6 z-50 h-14 w-14 rounded-full bg-[var(--ye-highlight)] shadow-lg flex items-center justify-center"
        >
          <Image src="/favicon.ico" alt="YE" width={24} height={24} />
          {hasUnread && (
            <span className="absolute top-2 right-2 h-3 w-3 rounded-full bg-red-500" />
          )}
        </button>
      )}

      <div
        className={`fixed inset-0 z-40 flex items-center justify-center transition-all ${
          embedded || isOpen ? "pointer-events-auto" : "pointer-events-none"
        }`}
        style={{
          backgroundColor:
            embedded || isOpen ? "rgba(0, 0, 0, 0.3)" : "rgba(0, 0, 0, 0)",
          transition: "background-color 0.5s ease-out",
          visibility: embedded || isOpen ? "visible" : "hidden",
        }}
      >
        <div
          className={`relative bg-white flex flex-col
            h-[100dvh] w-full
            md:h-[102vh] md:w-[475px] md:rounded-3xl md:border md:shadow-xl
            ${embedded || isOpen ? "chatbot-open" : "chatbot-close"}`}
        >
          <div
            className="flex items-center justify-between px-4 py-3 border-b shrink-0"
            style={{ backgroundColor: "var(--ye-primary)" }}
          >
            <div className="flex items-center gap-2">
              <Image src="/favicon.ico" alt="YE" width={18} height={18} />
              <div>
                <p className="text-sm font-semibold text-white">
                  Young Engineers Assistant
                </p>
                <p className="text-[11px] text-white/90">
                  Ask me anything about the portal
                </p>
              </div>
            </div>

            <div className="flex items-center gap-2">
              <Drawer.Root
                open={showThreadHistory}
                onOpenChange={setShowThreadHistory}
                direction="left"
              >
                <Drawer.Trigger asChild>
                  <button
                    className="text-xs px-3 py-1 rounded-full bg-white flex items-center justify-center hover:bg-gray-100"
                    title="View conversation history"
                  >
                    <History className="h-4 w-4" />
                  </button>
                </Drawer.Trigger>

                <Drawer.Portal>
                  <Drawer.Overlay className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50" />

                  <Drawer.Content
                    className="
                      fixed top-0 left-0 z-50 h-full w-[85vw] md:w-[380px]
                      bg-white flex flex-col
                      md:rounded-r-3xl shadow-2xl
                      outline-none
                    "
                  >
                    <div className="flex items-center justify-between px-4 py-3 border-b bg-slate-50 shrink-0">
                      <div className="flex items-center gap-2">
                        <History className="h-5 w-5 text-gray-700" />
                        <h2 className="text-sm font-semibold text-gray-800">
                          Conversation History
                        </h2>
                      </div>
                      <Drawer.Close asChild>
                        <button className="h-8 w-8 rounded-full hover:bg-gray-200 flex items-center justify-center transition-colors">
                          <X className="h-4 w-4" />
                        </button>
                      </Drawer.Close>
                    </div>

                    <div className="flex-1 overflow-hidden">
                      <ChatHistory
                        userId={userId}
                        authToken={authToken}
                        currentThreadId={threadId || undefined}
                        onSelectThread={handleSelectThread}
                        onDeleteThread={handleDeleteThread}
                      />
                    </div>
                  </Drawer.Content>
                </Drawer.Portal>
              </Drawer.Root>

              <button
                onClick={handleNewChat}
                className="text-xs px-3 py-1 rounded-full bg-white flex items-center justify-center hover:bg-gray-100"
              >
                New
              </button>
              <button
                onClick={handleToggle}
                className="h-6 w-6 rounded-full bg-white flex items-center justify-center hover:bg-gray-100"
              >
                ✕
              </button>
            </div>
          </div>

          {/* Category selector hidden for now — may re-enable later
          <div className="sticky top-0 z-10 bg-slate-50 border-b px-4 py-2 shrink-0">
            <CategorySelector
              categories={CATEGORIES}
              value={category}
              onChange={setCategory}
              disabled={isStreaming || isCreatingThread}
            />
          </div>
          */}

          {(isCreatingThread || isLoadingThread) && (
            <div className="mx-4 mt-3 rounded-xl border border-slate-200 bg-slate-50 px-3 py-2">
              <div className="flex items-center gap-2 text-sm text-slate-700">
                <Loader2 className="h-4 w-4 animate-spin" />
                <span>
                  {isCreatingThread
                    ? "Starting your conversation..."
                    : "Loading conversation history..."}
                </span>
              </div>
            </div>
          )}

          {uiNotice && (
            <div className="mx-4 mt-3">
              <div
                className={`rounded-xl border px-4 py-3 shadow-sm ${noticeStyles[uiNotice.type]}`}
              >
                <div className="flex items-start gap-3">
                  {noticeIcon[uiNotice.type]}

                  <div className="min-w-0 flex-1">
                    <div className="text-sm font-semibold">
                      {uiNotice.title}
                    </div>
                    <div className="mt-1 text-sm leading-5 opacity-90">
                      {uiNotice.message}
                    </div>

                    <div className="mt-3 flex items-center gap-2">
                      <button
                        onClick={clearNotice}
                        className="inline-flex items-center rounded-full border border-current/15 bg-white/60 px-3 py-1 text-xs font-medium hover:bg-white"
                      >
                        Dismiss
                      </button>

                      <button
                        onClick={() => {
                          clearNotice();
                          if (threadId) {
                            loadThreadMessages(threadId);
                          }
                        }}
                        className="inline-flex items-center gap-1 rounded-full border border-current/15 bg-white/60 px-3 py-1 text-xs font-medium hover:bg-white"
                      >
                        <RefreshCw className="h-3.5 w-3.5" />
                        Retry
                      </button>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          )}

          <div className="flex-1 overflow-y-auto chat-scrollbar">
            <ChatMessages
              messages={messages}
              isStreaming={isStreaming}
              category={category}
              onRegenerate={handleRegenerate}
              isLoadingHistory={isLoadingThread}
              isLoadingThread={isLoadingThread}
            />
          </div>

          <div className="shrink-0">
            <ChatInput
              onSend={handleSend}
              disabled={!canSend}
              isStreaming={isStreaming}
              onStop={handleStop}
            />
          </div>
        </div>
      </div>
    </>
  );
}
