import { useState, useRef, useEffect, useImperativeHandle, forwardRef, useCallback } from "react";
import { cn } from "@/lib/utils";
import { XIcon, SendIcon, Loader2Icon, CalendarIcon } from "lucide-react";
import { API_ORIGIN } from "@/service/apiClient";
import { getAccessToken } from "@/auth-state";
import ReactMarkdown, { Components } from "react-markdown";
import remarkGfm from "remark-gfm";
import remarkBreaks from "remark-breaks";
import { useDateFilterNavigation } from "@/hooks";

type Message = {
  role: "user" | "ai";
  content: string;
};

type ChatbotPanelProps = {
  className?: string;
  variant?: "inline" | "widget";
  onClose?: () => void;
  hideHeader?: boolean;
};

export type ChatbotPanelHandle = {
  clearMessages: () => Promise<void>;
};

const ChatbotPanel = forwardRef<ChatbotPanelHandle, ChatbotPanelProps>(({ className, onClose, hideHeader = false }, ref) => {
  const [messages, setMessages] = useState<Message[]>([]);
  const [historyCursor, setHistoryCursor] = useState<number | null>(null);
  const [isHistoryLoading, setIsHistoryLoading] = useState(false);
  const [input, setInput] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const scrollRef = useRef<HTMLDivElement>(null);

  // Auto-scroll to bottom when messages change
  useEffect(() => {
    if (scrollRef.current) {
      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
    }
  }, [messages]);

  const mapHistoryToMessages = (items: any[]): Message[] => {
    return items.map((item) => {
      if (item.is_human) {
        return { role: "user" as const, content: String(item.message ?? "") };
      }
      // AI messages may be stored as JSON — extract ai_response text
      let content = String(item.message ?? "");
      try {
        const parsed = JSON.parse(content);
        if (parsed && typeof parsed === "object" && parsed.ai_response) {
          content = parsed.ai_response;
        }
      } catch {
        // Not JSON, use as-is
      }
      return { role: "ai" as const, content };
    });
  };

  const loadHistory = async (isRefresh: boolean) => {
    if (isHistoryLoading) return;
    setIsHistoryLoading(true);

    try {
      const token = getAccessToken();
      const cursor = isRefresh ? null : historyCursor;
      const url = `${API_ORIGIN}/api/history/me?limit=20${cursor ? `&before_id=${cursor}` : ""}`;

      const headers: Record<string, string> = {};
      if (token) headers["Authorization"] = `Bearer ${token}`;

      const res = await fetch(url, { headers });
      if (!res.ok) throw new Error("Failed to load history");
      const data = await res.json();

      const items: any[] = Array.isArray(data.data) ? data.data : Array.isArray(data) ? data : [];
      const nextCursor: number | null = data.next_cursor ?? null;

      if (items.length === 0) {
        if (isRefresh && messages.length === 0) {
          // No history at all -> show default greeting
          setMessages([{ role: "ai", content: "Xin chào! Mình là CuCu Assistant 😊 Bạn muốn tìm ghi chú gì hôm nay?" }]);
        }
        setHistoryCursor(null);
        return;
      }

      // API trả về DESC theo id, ta đảo để oldest -> newest trong batch
      const batchMessages = mapHistoryToMessages([...items].reverse());

      if (isRefresh) {
        setMessages(batchMessages);
      } else {
        // Load older: prepend vào đầu
        setMessages((prev) => [...batchMessages, ...prev]);
      }

      setHistoryCursor(nextCursor);
    } catch (error) {
      console.error("Failed to load history:", error);
      if (isRefresh && messages.length === 0) {
        setMessages([{ role: "ai", content: "Xin chào! Mình là CuCu Assistant 😊 Bạn muốn tìm ghi chú gì hôm nay?" }]);
      }
    } finally {
      setIsHistoryLoading(false);
    }
  };

  const clearMessages = async () => {
    try {
      const token = getAccessToken();
      const headers: Record<string, string> = {};
      if (token) headers["Authorization"] = `Bearer ${token}`;

      const res = await fetch(`${API_ORIGIN}/api/history/me`, {
        method: "DELETE",
        headers,
      });
      if (!res.ok) throw new Error("Failed to clear history");

      setMessages([{ role: "ai", content: "Đã xóa lịch sử chat! Mình có thể giúp gì cho bạn?" }]);
      setHistoryCursor(null);
    } catch (error) {
      console.error("Failed to clear history:", error);
    }
  };

  useImperativeHandle(ref, () => ({
    clearMessages,
  }));

  // Load initial history on mount
  useEffect(() => {
    void loadHistory(true);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const handleSendMessage = async () => {
    if (!input.trim() || isLoading) return;

    const userMessage = input.trim();
    setInput("");
    setMessages((prev) => [...prev, { role: "user", content: userMessage }]);
    setIsLoading(true);

    // Add empty AI message placeholder for streaming
    const aiMsgIndex = messages.length + 1; // +1 for user msg just added
    setMessages((prev) => [...prev, { role: "ai", content: "" }]);

    try {
      const token = getAccessToken();
      const headers: Record<string, string> = { "Content-Type": "application/json" };
      if (token) headers["Authorization"] = `Bearer ${token}`;

      const response = await fetch(`${API_ORIGIN}/api/agent/chat/stream`, {
        method: "POST",
        headers,
        body: JSON.stringify({ user_query: userMessage })
      });

      if (!response.ok || !response.body) throw new Error("Failed to get response from AI");

      const reader = response.body.getReader();
      const decoder = new TextDecoder();
      let buffer = "";

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        buffer += decoder.decode(value, { stream: true });
        const lines = buffer.split("\n");
        // Keep the last incomplete line in the buffer
        buffer = lines.pop() || "";

        for (const line of lines) {
          const trimmed = line.trim();
          if (!trimmed.startsWith("data: ")) continue;

          try {
            const data = JSON.parse(trimmed.slice(6));

            if (data.token) {
              // Append token to the last AI message
              setMessages((prev) => {
                const updated = [...prev];
                const lastMsg = updated[updated.length - 1];
                if (lastMsg && lastMsg.role === "ai") {
                  updated[updated.length - 1] = {
                    ...lastMsg,
                    content: lastMsg.content + data.token,
                  };
                }
                return updated;
              });
            }

            if (data.done) {
              // Final event — replace with full response (in case of parse differences)
              if (data.ai_response) {
                setMessages((prev) => {
                  const updated = [...prev];
                  const lastMsg = updated[updated.length - 1];
                  if (lastMsg && lastMsg.role === "ai") {
                    updated[updated.length - 1] = {
                      ...lastMsg,
                      content: data.ai_response,
                    };
                  }
                  return updated;
                });
              }
            }

            if (data.error) {
              throw new Error(data.error);
            }
          } catch (parseErr) {
            // Skip malformed SSE lines
            console.warn("SSE parse error:", parseErr);
          }
        }
      }
    } catch (error) {
      console.error("Chat error:", error);
      setMessages((prev) => {
        const updated = [...prev];
        const lastMsg = updated[updated.length - 1];
        if (lastMsg && lastMsg.role === "ai" && !lastMsg.content) {
          // Replace empty placeholder with error
          updated[updated.length - 1] = {
            ...lastMsg,
            content: "Xin lỗi, mình đang gặp sự cố kết nối. Vui lòng thử lại.",
          };
        }
        return updated;
      });
    } finally {
      setIsLoading(false);
    }
  };

  // ─── Clickable dates in AI responses ───
  const navigateToDate = useDateFilterNavigation();

  const renderTextWithClickableDates = useCallback(
    (text: string) => {
      // Match dates in format YYYY-MM-DD (standalone or inside parentheses)
      const dateRegex = /(\d{4}-\d{2}-\d{2})/g;
      const parts = text.split(dateRegex);

      if (parts.length === 1) return text; // No dates found

      return parts.map((part, idx) => {
        if (dateRegex.test(part)) {
          // Reset lastIndex since we're reusing regex
          dateRegex.lastIndex = 0;
          return (
            <button
              key={idx}
              onClick={() => navigateToDate(part)}
              className="inline-flex items-center gap-0.5 text-primary hover:underline cursor-pointer font-medium"
              title={`Xem ghi chú ngày ${part}`}
              type="button"
            >
              <CalendarIcon className="size-3 inline" />
              {part}
            </button>
          );
        }
        return part;
      });
    },
    [navigateToDate],
  );

  const markdownComponents: Components = {
    // Override text rendering in paragraphs, list items, strong, etc.
    p: ({ children, ...props }) => (
      <p {...props}>
        {Array.isArray(children)
          ? children.map((child, i) =>
            typeof child === "string" ? <span key={i}>{renderTextWithClickableDates(child)}</span> : child,
          )
          : typeof children === "string"
            ? renderTextWithClickableDates(children)
            : children}
      </p>
    ),
    li: ({ children, ...props }) => (
      <li {...props}>
        {Array.isArray(children)
          ? children.map((child, i) =>
            typeof child === "string" ? <span key={i}>{renderTextWithClickableDates(child)}</span> : child,
          )
          : typeof children === "string"
            ? renderTextWithClickableDates(children)
            : children}
      </li>
    ),
    strong: ({ children, ...props }) => (
      <strong {...props}>
        {typeof children === "string" ? renderTextWithClickableDates(children) : children}
      </strong>
    ),
  };

  return (
    <div className={cn("w-full h-full flex flex-col bg-background border rounded-lg overflow-hidden shadow-sm", className)}>
      {/* Header */}
      {!hideHeader && (
        <div className="flex items-center justify-between p-4 border-b bg-muted/30">
          <h2 className="font-semibold text-sm">CuCu Assistant</h2>
          {onClose && (
            <button onClick={onClose} className="p-1 hover:bg-muted rounded-md transition-colors">
              <XIcon className="size-4" />
            </button>
          )}
        </div>
      )}

      {/* Messages */}
      <div ref={scrollRef} className="flex-1 overflow-y-auto p-4 space-y-4">
        {/* Load older history */}
        {historyCursor && (
          <div className="flex justify-center mb-2">
            <button
              type="button"
              onClick={() => void loadHistory(false)}
              className="text-xs px-3 py-1 rounded-full border border-border text-muted-foreground hover:bg-muted/60 transition-colors"
              disabled={isHistoryLoading}
            >
              {isHistoryLoading ? "Loading..." : "Load older messages"}
            </button>
          </div>
        )}

        {messages.map((msg, i) => (
          <div
            key={i}
            data-testid={msg.role === "ai" ? "ai-message" : "user-message"}
            className={cn("flex", msg.role === "user" ? "justify-end" : "justify-start")}
          >
            <div className={cn(
              "max-w-[85%] p-3 rounded-2xl text-sm shadow-sm",
              msg.role === "user"
                ? "bg-primary text-primary-content rounded-tr-none"
                : "bg-muted text-foreground rounded-tl-none border"
            )}>
              {msg.role === "ai" ? (
                <div className="markdown-content max-w-none break-words text-inherit">
                  <ReactMarkdown remarkPlugins={[remarkGfm, remarkBreaks]} components={markdownComponents}>
                    {msg.content}
                  </ReactMarkdown>
                </div>
              ) : (
                msg.content
              )}
            </div>
          </div>
        ))}
        {isLoading && (
          <div className="flex justify-start">
            <div className="bg-muted p-3 rounded-2xl rounded-tl-none border flex items-center gap-2">
              <Loader2Icon className="size-3 animate-spin" />
              <span className="text-xs">Typing...</span>
            </div>
          </div>
        )}
      </div>

      {/* Input */}
      <div className="p-4 border-t bg-background">
        <form
          onSubmit={(e) => { e.preventDefault(); handleSendMessage(); }}
          className="flex items-center gap-2"
        >
          <input
            data-testid="chat-input"
            value={input}
            onChange={(e) => setInput(e.target.value)}
            placeholder="Hỏi CuCu gì đó..."
            className="flex-1 bg-muted/50 border-none focus:ring-1 focus:ring-primary rounded-xl px-4 py-2 text-sm outline-none transition-all"
            disabled={isLoading}
          />
          <button
            data-testid="chat-send"
            type="submit"
            disabled={!input.trim() || isLoading}
            className="p-2 bg-primary text-primary-content rounded-xl hover:opacity-90 disabled:opacity-50 transition-all flex items-center justify-center"
          >
            {isLoading ? <Loader2Icon className="size-4 animate-spin" /> : <SendIcon className="size-4" />}
          </button>
        </form>
      </div>
    </div>
  );
});

ChatbotPanel.displayName = "ChatbotPanel";

export default ChatbotPanel;
