import { useState, useEffect, useRef } from "react";
import { useNavigate } from "react-router";
import {
  Send,
  Plus,
  Trash2,
  LogOut,
  Menu,
  X,
  MessageSquare,
  User,
  Bot,
  Loader2,
  Database,
  Eraser,
} from "lucide-react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import type { Components } from "react-markdown";
import KnowledgeManagement from "./KnowledgeManagement";
import PhaseToggle, { type Phase } from "./interview/PhaseToggle";
import InterviewPanel from "./interview/InterviewPanel";
import InterviewResultView from "./interview/InterviewResultView";
import NewChatOnboarding from "./NewChatOnboarding";
import type { InterviewResult } from "../../services/interviewApi";
import { getInterviewResult } from "../../services/interviewApi";
import {
  getRooms,
  getRoom,
  createRoom,
  deleteRoom,
  clearRoomMessages,
  streamChat,
  type ChatSource,
} from "../../services/api";

interface StoredUser {
  user_id: string;
  email: string;
  name: string;
  loginTime: string;
}

interface Message {
  id: string;
  role: "user" | "assistant";
  content: string;
  timestamp: number;
  sources?: ChatSource[];
}

interface ChatRoom {
  id: string;
  title: string;
  messages: Message[];
  createdAt: string;
  updatedAt: string | null;
  messagesLoaded: boolean;
}

// Preprocess markdown to ensure tables are properly separated from surrounding text
function preprocessMarkdown(content: string): string {
  // Step 1: Split concatenated table rows — "| val ||" means end of row + start of next
  let result = content.replace(/\|\|/g, "|\n|");

  // Step 2: Per-line — if a line has non-pipe text before a pipe table row, split them
  const lines = result.split("\n");
  const processed = lines.map((line) => {
    const tableStart = line.indexOf("|");
    if (tableStart > 0) {
      const tableContent = line.slice(tableStart);
      // Confirm it looks like a table row (at least 2 pipes)
      if ((tableContent.match(/\|/g) ?? []).length >= 2) {
        return line.slice(0, tableStart).trimEnd() + "\n\n" + tableContent;
      }
    }
    return line;
  });
  result = processed.join("\n");

  // Step 3: Ensure blank line before table rows preceded by non-table text (not another row ending with |)
  result = result.replace(/([^|\n])\n(\|)/g, "$1\n\n$2");

  return result;
}

// Markdown component overrides for clean rendering inside chat bubbles
const markdownComponents: Components = {
  p: ({ children }) => (
    <p className="text-sm mb-2 last:mb-0 leading-relaxed">{children}</p>
  ),
  h1: ({ children }) => (
    <h1 className="text-lg font-bold mb-3 mt-4 first:mt-0">{children}</h1>
  ),
  h2: ({ children }) => (
    <h2 className="text-base font-bold mb-2 mt-3 first:mt-0">{children}</h2>
  ),
  h3: ({ children }) => (
    <h3 className="text-sm font-semibold mb-2 mt-2 first:mt-0">{children}</h3>
  ),
  ul: ({ children }) => (
    <ul className="list-disc pl-5 mb-2 space-y-1 text-sm">{children}</ul>
  ),
  ol: ({ children }) => (
    <ol className="list-decimal pl-5 mb-2 space-y-1 text-sm">{children}</ol>
  ),
  li: ({ children }) => <li className="text-sm leading-relaxed">{children}</li>,
  code: ({ children, className }) => {
    const isBlock = className?.startsWith("language-");
    if (isBlock) {
      return (
        <code className="block text-xs font-mono text-slate-100 leading-relaxed">
          {children}
        </code>
      );
    }
    return (
      <code className="bg-slate-100 text-pink-600 px-1.5 py-0.5 rounded text-xs font-mono">
        {children}
      </code>
    );
  },
  pre: ({ children }) => (
    <pre className="bg-slate-900 rounded-lg p-3 mb-2 mt-1 overflow-x-auto text-xs">
      {children}
    </pre>
  ),
  blockquote: ({ children }) => (
    <blockquote className="border-l-4 border-slate-300 pl-3 text-slate-500 italic mb-2 text-sm">
      {children}
    </blockquote>
  ),
  table: ({ children }) => (
    <div className="overflow-x-auto mb-2">
      <table className="w-full text-sm border-collapse">{children}</table>
    </div>
  ),
  th: ({ children }) => (
    <th className="border border-slate-200 px-3 py-1.5 bg-slate-100 font-medium text-left text-xs">
      {children}
    </th>
  ),
  td: ({ children }) => (
    <td className="border border-slate-200 px-3 py-1.5 text-xs">{children}</td>
  ),
  a: ({ children, href }) => (
    <a
      href={href}
      target="_blank"
      rel="noopener noreferrer"
      className="text-blue-600 underline hover:text-blue-800"
    >
      {children}
    </a>
  ),
  strong: ({ children }) => (
    <strong className="font-semibold">{children}</strong>
  ),
  hr: () => <hr className="border-slate-200 my-3" />,
};

// Typing indicator — three bouncing dots
function useLoadingMessages() {
  const [messages, setMessages] = useState<string[]>([]);

  useEffect(() => {
    fetch("/loading-messages.yaml")
      .then((r) => r.text())
      .then((text) => {
        const parsed = text
          .split("\n")
          .filter((l) => l.trimStart().startsWith("- "))
          .map((l) => l.replace(/^\s*- /, "").trim())
          .filter(Boolean);
        if (parsed.length > 0) setMessages(parsed);
      })
      .catch(() => {});
  }, []);

  return messages;
}

function TypingIndicator() {
  const messages = useLoadingMessages();
  const [index, setIndex] = useState(0);

  useEffect(() => {
    if (messages.length === 0) return;
    setIndex(Math.floor(Math.random() * messages.length));
    const id = setInterval(() => {
      setIndex((prev) => {
        let next: number;
        do { next = Math.floor(Math.random() * messages.length); } while (messages.length > 1 && next === prev);
        return next;
      });
    }, 300);
    return () => clearInterval(id);
  }, [messages]);

  if (messages.length === 0) {
    return (
      <div className="flex gap-1.5 items-center py-1 px-0.5">
        <span className="w-2 h-2 bg-slate-400 rounded-full animate-bounce" style={{ animationDelay: "0ms", animationDuration: "1s" }} />
        <span className="w-2 h-2 bg-slate-400 rounded-full animate-bounce" style={{ animationDelay: "200ms", animationDuration: "1s" }} />
        <span className="w-2 h-2 bg-slate-400 rounded-full animate-bounce" style={{ animationDelay: "400ms", animationDuration: "1s" }} />
      </div>
    );
  }

  return (
    <div className="flex items-center gap-2 py-1 px-0.5 text-sm text-slate-400 italic">
      <span className="inline-block w-2 h-2 rounded-full bg-slate-400 animate-pulse" />
      <span>{messages[index]}…</span>
    </div>
  );
}

export default function Main() {
  const navigate = useNavigate();
  const [sidebarOpen, setSidebarOpen] = useState(true);
  const [chats, setChats] = useState<ChatRoom[]>([]);
  const [currentChatId, setCurrentChatId] = useState<string | null>(null);
  const [input, setInput] = useState("");
  const [isStreaming, setIsStreaming] = useState(false);
  const [streamingMsgId, setStreamingMsgId] = useState<string | null>(null);
  const [roomsLoading, setRoomsLoading] = useState(false);
  const [roomsError, setRoomsError] = useState<string | null>(null);
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const [user, setUser] = useState<StoredUser | null>(null);
  const [knowledgeOpen, setKnowledgeOpen] = useState(false);
  const [currentPhase, setCurrentPhase] = useState<Phase>("interview");
  const [interviewResult, setInterviewResult] = useState<InterviewResult | null>(null);
  const [resultModalOpen, setResultModalOpen] = useState(false);
  const abortControllerRef = useRef<AbortController | null>(null);

  useEffect(() => {
    const storedUser = localStorage.getItem("chatbot_user");
    if (storedUser) {
      const parsedUser: StoredUser = JSON.parse(storedUser);
      setUser(parsedUser);
      loadRooms(parsedUser.user_id);
    }
  }, []);

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

  useEffect(() => {
    if (!currentChatId) return;
    const chat = chats.find((c) => c.id === currentChatId);
    if (chat && !chat.messagesLoaded) {
      loadRoomMessages(currentChatId);
    }
    // Restore phase for this room
    const savedPhase = localStorage.getItem(`phase_${currentChatId}`);
    if (savedPhase === "analytics" || savedPhase === "interview") {
      setCurrentPhase(savedPhase);
    } else {
      const interviewRaw = localStorage.getItem(`interview_${currentChatId}`);
      if (interviewRaw) {
        try {
          const iv = JSON.parse(interviewRaw) as { status?: string };
          setCurrentPhase(iv.status === "completed" ? "analytics" : "interview");
        } catch {
          setCurrentPhase("interview");
        }
      } else {
        setCurrentPhase("interview");
      }
    }
    // Load persisted interview result — localStorage first, fallback ke API
    const interviewRaw2 = localStorage.getItem(`interview_${currentChatId}`);
    let localResult: InterviewResult | null = null;
    if (interviewRaw2) {
      try {
        const iv = JSON.parse(interviewRaw2) as { result?: InterviewResult };
        localResult = iv.result ?? null;
      } catch {
        localResult = null;
      }
    }
    if (localResult) {
      setInterviewResult(localResult);
    } else {
      // Coba ambil dari backend (sesi sudah selesai sebelumnya)
      getInterviewResult(currentChatId)
        .then(setInterviewResult)
        .catch(() => setInterviewResult(null));
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [currentChatId]);

  const handlePhaseChange = (phase: Phase) => {
    setCurrentPhase(phase);
    if (currentChatId) localStorage.setItem(`phase_${currentChatId}`, phase);
  };

  const handleInterviewComplete = () => {
    setCurrentPhase("analytics");
    if (currentChatId) localStorage.setItem(`phase_${currentChatId}`, "analytics");
  };

  const handleOnboardingStart = async () => {
    if (!user) return;
    const res = await createRoom(user.user_id, "New Session");
    const newRoom: ChatRoom = {
      id: res.data.id,
      title: res.data.title,
      messages: [],
      createdAt: res.data.created_at,
      updatedAt: res.data.updated_at,
      messagesLoaded: true,
    };
    setChats((prev) => [newRoom, ...prev]);
    setCurrentChatId(newRoom.id);
    setCurrentPhase("interview");
    localStorage.setItem(`phase_${newRoom.id}`, "interview");
  };

  const loadRooms = async (userId: string) => {
    setRoomsLoading(true);
    setRoomsError(null);
    try {
      const apiRooms = await getRooms(userId);
      const mapped: ChatRoom[] = apiRooms.map((r) => ({
        id: r.id,
        title: r.title,
        messages: [],
        createdAt: r.created_at,
        updatedAt: r.updated_at,
        messagesLoaded: false,
      }));
      setChats(mapped);
      if (mapped.length > 0) {
        setCurrentChatId(mapped[0].id);
      }
    } catch (err) {
      setRoomsError(
        err instanceof Error ? err.message : "Failed to load chats"
      );
    } finally {
      setRoomsLoading(false);
    }
  };

  const loadRoomMessages = async (roomId: string) => {
    try {
      const detail = await getRoom(roomId);
      const messages: Message[] = (detail?.messages ?? []).map((m) => ({
        id: m.id,
        role: m.role,
        content: m.content,
        timestamp: new Date(m.created_at).getTime(),
        sources: m.sources ?? [],
      }));
      setChats((prev) =>
        prev.map((chat) =>
          chat.id === roomId
            ? messages.length === 0 && chat.messages.length > 0
              ? { ...chat, messagesLoaded: true }
              : { ...chat, messages, messagesLoaded: true }
            : chat
        )
      );
    } catch {
      setChats((prev) =>
        prev.map((chat) =>
          chat.id === roomId ? { ...chat, messagesLoaded: true } : chat
        )
      );
    }
  };

  const currentChat = chats.find((chat) => chat.id === currentChatId);

  const createNewChat = () => {
    setCurrentChatId(null);
  };

  const deleteChat = async (chatId: string) => {
    if (!user) return;
    try {
      await deleteRoom(chatId, user.user_id);
    } catch {
      return;
    }
    const updatedChats = chats.filter((chat) => chat.id !== chatId);
    setChats(updatedChats);
    if (currentChatId === chatId) {
      setCurrentChatId(updatedChats.length > 0 ? updatedChats[0].id : null);
    }
  };

  const deleteAllChats = async () => {
    if (!user) return;
    await Promise.allSettled(
      chats.map((chat) => deleteRoom(chat.id, user.user_id))
    );
    setChats([]);
    setCurrentChatId(null);
  };

  const handleClearChat = async () => {
    if (!currentChatId || !user || isStreaming) return;
    try {
      await clearRoomMessages(currentChatId, user.user_id);
      setChats((prev) =>
        prev.map((chat) =>
          chat.id === currentChatId ? { ...chat, messages: [] } : chat
        )
      );
    } catch { /* silent */ }
  };

  const handleLogout = () => {
    localStorage.removeItem("chatbot_user");
    navigate("/login");
  };

  const handleSend = async () => {
    if (!input.trim() || isStreaming || !user) return;

    let roomId = currentChatId;

    if (!roomId) {
      try {
        const res = await createRoom(user.user_id, input.slice(0, 50));
        const newRoom: ChatRoom = {
          id: res.data.id,
          title: res.data.title,
          messages: [],
          createdAt: res.data.created_at,
          updatedAt: res.data.updated_at,
          messagesLoaded: true,
        };
        setChats((prev) => [newRoom, ...prev]);
        roomId = newRoom.id;
        setCurrentChatId(roomId);
      } catch {
        return;
      }
    }

    const userMessage: Message = {
      id: crypto.randomUUID(),
      role: "user",
      content: input,
      timestamp: Date.now(),
    };

    setChats((prev) =>
      prev.map((chat) =>
        chat.id === roomId
          ? {
              ...chat,
              messages: [...chat.messages, userMessage],
              updatedAt: new Date().toISOString(),
            }
          : chat
      )
    );

    const sentMessage = input;
    setInput("");
    setIsStreaming(true);

    const assistantMsgId = crypto.randomUUID();
    setStreamingMsgId(assistantMsgId);

    setChats((prev) =>
      prev.map((chat) =>
        chat.id === roomId
          ? {
              ...chat,
              messages: [
                ...chat.messages,
                {
                  id: assistantMsgId,
                  role: "assistant",
                  content: "",
                  timestamp: Date.now(),
                  sources: [],
                },
              ],
            }
          : chat
      )
    );

    abortControllerRef.current = new AbortController();

    try {
      const response = await streamChat(user.user_id, roomId, sentMessage);

      if (!response.body) throw new Error("No response body");

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

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

        buffer += decoder.decode(value, { stream: true });
        const lines = buffer.split(/\r?\n/);
        buffer = lines.pop() ?? "";

        for (const line of lines) {
          if (line.startsWith("event:")) {
            currentEvent = line.replace("event:", "").trim();
          } else if (line.startsWith("data:")) {
            const data = line.replace(/^data: ?/, "");

            if (currentEvent === "sources" && data) {
              try {
                const sources: ChatSource[] = JSON.parse(data);
                setChats((prev) =>
                  prev.map((chat) =>
                    chat.id === roomId
                      ? {
                          ...chat,
                          messages: chat.messages.map((m) =>
                            m.id === assistantMsgId ? { ...m, sources } : m
                          ),
                        }
                      : chat
                  )
                );
              } catch {
                // ignore malformed sources
              }
            } else if (currentEvent === "chunk" && data) {
              setChats((prev) =>
                prev.map((chat) =>
                  chat.id === roomId
                    ? {
                        ...chat,
                        messages: chat.messages.map((m) =>
                          m.id === assistantMsgId
                            ? { ...m, content: m.content + data }
                            : m
                        ),
                      }
                    : chat
                )
              );
            } else if (currentEvent === "message" && data) {
              setChats((prev) =>
                prev.map((chat) =>
                  chat.id === roomId
                    ? {
                        ...chat,
                        messages: chat.messages.map((m) =>
                          m.id === assistantMsgId
                            ? { ...m, content: data }
                            : m
                        ),
                      }
                    : chat
                )
              );
              setStreamingMsgId(null);
            } else if (currentEvent === "done") {
              streamDone = true;
              break;
            }
          }
        }
      }
      // Re-fetch from API after stream ends to get the authoritative
      // stored content — guarantees formatting matches page-refresh behavior
      await loadRoomMessages(roomId);
    } catch (err: unknown) {
      if ((err as Error).name !== "AbortError") {
        setChats((prev) =>
          prev.map((chat) =>
            chat.id === roomId
              ? {
                  ...chat,
                  messages: chat.messages.map((m) =>
                    m.id === assistantMsgId
                      ? {
                          ...m,
                          content:
                            "Sorry, I couldn't get a response. Please try again.",
                        }
                      : m
                  ),
                }
              : chat
          )
        );
      }
    } finally {
      setIsStreaming(false);
      setStreamingMsgId(null);
      abortControllerRef.current = null;
    }
  };

  const handleKeyPress = (e: React.KeyboardEvent) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      handleSend();
    }
  };

  return (
    <div className="flex h-screen bg-slate-50">
      {/* Sidebar */}
      <div
        className={`${
          sidebarOpen ? "w-64" : "w-0"
        } bg-gradient-to-b from-[#059669] to-[#047857] text-white transition-all duration-300 flex flex-col overflow-hidden`}
      >
        <div className="p-3 border-b border-white/20">
          <button
            onClick={createNewChat}
            className="w-full flex items-center justify-center gap-2 bg-white/20 hover:bg-white/30 px-3 py-2 rounded-lg transition text-sm"
          >
            <Plus className="w-4 h-4" />
            New Chat
          </button>
        </div>

        <div className="flex-1 overflow-y-auto p-2 space-y-1">
          {roomsLoading ? (
            <div className="flex justify-center py-4">
              <Loader2 className="w-4 h-4 animate-spin text-white/70" />
            </div>
          ) : roomsError ? (
            <p className="text-xs text-red-200 text-center px-2 py-2">
              {roomsError}
            </p>
          ) : (
            chats.map((chat) => (
              <div
                key={chat.id}
                className={`flex items-center gap-2 p-2 rounded-lg cursor-pointer transition group ${
                  currentChatId === chat.id
                    ? "bg-white/25"
                    : "hover:bg-white/15"
                }`}
              >
                <MessageSquare className="w-3.5 h-3.5 flex-shrink-0" />
                <div
                  className="flex-1 truncate text-sm"
                  onClick={() => setCurrentChatId(chat.id)}
                >
                  {chat.title}
                </div>
                <button
                  onClick={(e) => {
                    e.stopPropagation();
                    deleteChat(chat.id);
                  }}
                  className="opacity-0 group-hover:opacity-100 transition p-1 rounded hover:bg-white/20 cursor-pointer text-red-200 hover:text-white"
                >
                  <Trash2 className="w-3.5 h-3.5" />
                </button>
              </div>
            ))
          )}
        </div>

        <div className="border-t border-white/20 p-3 space-y-2">
          {chats.length > 0 && (
            <button
              onClick={deleteAllChats}
              className="w-full flex items-center justify-center gap-2 text-red-100 hover:text-white px-3 py-2 rounded-lg hover:bg-white/15 transition text-xs"
            >
              <Trash2 className="w-3.5 h-3.5" />
              Clear All Chats
            </button>
          )}

          <div className="flex items-center gap-2 p-2 rounded-lg bg-white/20">
            <div className="w-7 h-7 bg-white/30 rounded-full flex items-center justify-center">
              <User className="w-3.5 h-3.5" />
            </div>
            <div className="flex-1 min-w-0">
              <div className="text-xs truncate">{user?.name}</div>
              <div className="text-[10px] text-white/70 truncate">
                {user?.email}
              </div>
            </div>
            <button
              onClick={handleLogout}
              className="text-white/70 hover:text-white transition"
              title="Logout"
            >
              <LogOut className="w-3.5 h-3.5" />
            </button>
          </div>
        </div>
      </div>

      {/* Main Content */}
      <div className="flex-1 flex flex-col min-w-0 relative">

        {/* ── Subtle background — harmonizes with Login page ── */}
        <div className="absolute inset-0 pointer-events-none z-0 overflow-hidden">
          {/* Dot grid */}
          <div
            className="absolute inset-0 opacity-[0.13]"
            style={{
              backgroundImage: "radial-gradient(circle, #94a3b8 1px, transparent 1px)",
              backgroundSize: "28px 28px",
            }}
          />
          {/* Cyan orb — top right */}
          <div
            className="absolute -top-28 -right-28 w-80 h-80 rounded-full blur-3xl opacity-[0.08]"
            style={{ background: "#0ea5e9" }}
          />
          {/* Orange orb — bottom left */}
          <div
            className="absolute -bottom-28 -left-28 w-96 h-96 rounded-full blur-3xl opacity-[0.07]"
            style={{ background: "#f97316" }}
          />
          {/* Green orb — center left */}
          <div
            className="absolute top-1/2 -left-32 w-64 h-64 rounded-full blur-3xl opacity-[0.05]"
            style={{ background: "#10b981" }}
          />
          {/* Neural network — bottom right */}
          <svg
            className="absolute bottom-20 right-4 opacity-[0.07]"
            width="160" height="160" viewBox="0 0 200 200"
            fill="none" xmlns="http://www.w3.org/2000/svg"
          >
            <line x1="20" y1="150" x2="65" y2="90" stroke="#0ea5e9" strokeWidth="1.2"/>
            <line x1="20" y1="150" x2="55" y2="170" stroke="#0ea5e9" strokeWidth="1.2"/>
            <line x1="65" y1="90" x2="110" y2="125" stroke="#0ea5e9" strokeWidth="1.2"/>
            <line x1="65" y1="90" x2="130" y2="55" stroke="#10b981" strokeWidth="1.2"/>
            <line x1="110" y1="125" x2="170" y2="105" stroke="#0ea5e9" strokeWidth="1.2"/>
            <line x1="130" y1="55" x2="170" y2="105" stroke="#10b981" strokeWidth="1.2"/>
            <line x1="130" y1="55" x2="175" y2="30" stroke="#10b981" strokeWidth="1.2"/>
            <line x1="55" y1="170" x2="110" y2="125" stroke="#0ea5e9" strokeWidth="1.2"/>
            <line x1="175" y1="30" x2="170" y2="105" stroke="#10b981" strokeWidth="1.2"/>
            <circle cx="20" cy="150" r="4" fill="#0ea5e9"/>
            <circle cx="55" cy="170" r="3" fill="#0ea5e9"/>
            <circle cx="65" cy="90" r="5.5" fill="#0ea5e9"/>
            <circle cx="110" cy="125" r="4" fill="#0ea5e9"/>
            <circle cx="130" cy="55" r="5.5" fill="#10b981"/>
            <circle cx="170" cy="105" r="4" fill="#10b981"/>
            <circle cx="175" cy="30" r="3" fill="#10b981"/>
          </svg>
          {/* Neural network — top left (small) */}
          <svg
            className="absolute top-16 left-4 opacity-[0.06]"
            width="110" height="110" viewBox="0 0 180 180"
            fill="none" xmlns="http://www.w3.org/2000/svg"
          >
            <line x1="160" y1="30" x2="115" y2="80" stroke="#f97316" strokeWidth="1.2"/>
            <line x1="115" y1="80" x2="70" y2="55" stroke="#f97316" strokeWidth="1.2"/>
            <line x1="115" y1="80" x2="130" y2="135" stroke="#0ea5e9" strokeWidth="1.2"/>
            <line x1="70" y1="55" x2="25" y2="90" stroke="#f97316" strokeWidth="1.2"/>
            <line x1="25" y1="90" x2="80" y2="155" stroke="#0ea5e9" strokeWidth="1.2"/>
            <line x1="80" y1="155" x2="130" y2="135" stroke="#0ea5e9" strokeWidth="1.2"/>
            <circle cx="160" cy="30" r="4" fill="#f97316"/>
            <circle cx="115" cy="80" r="5.5" fill="#f97316"/>
            <circle cx="70" cy="55" r="4" fill="#f97316"/>
            <circle cx="130" cy="135" r="3" fill="#0ea5e9"/>
            <circle cx="25" cy="90" r="4" fill="#0ea5e9"/>
            <circle cx="80" cy="155" r="3" fill="#0ea5e9"/>
          </svg>
        </div>

        {/* Header */}
        <div className="relative z-10 bg-white border-b border-slate-200 p-3 flex items-center gap-3">
          <button
            onClick={() => setSidebarOpen(!sidebarOpen)}
            className="text-slate-600 hover:text-slate-900 transition"
          >
            {sidebarOpen ? (
              <X className="w-5 h-5" />
            ) : (
              <Menu className="w-5 h-5" />
            )}
          </button>
          <h1 className="text-base text-slate-900 flex-1 truncate min-w-0">
            {currentChat?.title || "Data Eyond"}
          </h1>
          <button
            onClick={() => setKnowledgeOpen(true)}
            className="flex items-center gap-2 bg-[#F59E0B] hover:bg-[#D97706] text-white px-3 py-2 rounded-lg transition-all duration-200 hover:scale-105 active:scale-95 cursor-pointer text-sm flex-shrink-0 shadow-sm hover:shadow-md"
          >
            <Database className="w-4 h-4" />
            Knowledge
          </button>
        </div>

        {/* Phase Toggle + Hasil Interview button — scoped per chat */}
        {currentChatId && (
          <div className="relative z-10 px-4 pt-3 pb-2 flex items-center gap-3">
            <PhaseToggle
              phase={currentPhase}
              onChange={handlePhaseChange}
            />
            {interviewResult && (
              <button
                onClick={() => setResultModalOpen(true)}
                className="flex items-center gap-1.5 px-3 py-1.5 text-xs bg-emerald-50 hover:bg-emerald-100 border border-emerald-200 text-emerald-700 rounded-full transition"
              >
                <span>📋</span>
                Hasil Interview
              </button>
            )}
            {currentPhase === "analytics" && (currentChat?.messages.length ?? 0) > 0 && (
              <button
                onClick={handleClearChat}
                disabled={isStreaming}
                title="Clear chat history"
                className="ml-auto p-1.5 rounded-lg text-slate-400 hover:text-red-500 hover:bg-red-50 transition disabled:opacity-40"
              >
                <Eraser className="w-3.5 h-3.5" />
              </button>
            )}
          </div>
        )}

        {/* Interview Panel */}
        {currentChatId && currentPhase === "interview" && (
          <div className="relative z-10 flex-1 flex flex-col min-h-0">
            <InterviewPanel
              roomId={currentChatId}
              userId={user?.user_id ?? ""}
              onComplete={handleInterviewComplete}
              onResultReady={setInterviewResult}
            />
          </div>
        )}

        {/* New Chat Onboarding — muncul saat tidak ada room dipilih */}
        {!currentChatId && (
          <div className="relative z-10 flex-1 flex flex-col min-h-0">
            <NewChatOnboarding onStart={handleOnboardingStart} />
          </div>
        )}

        {/* Analytics Messages */}
        <div className={`relative z-10 flex-1 overflow-y-auto p-4 space-y-4 ${!currentChatId || (currentChatId && currentPhase === "interview") ? "hidden" : ""}`}>
          {currentChat?.messages.length === 0 && (
            <div className="flex items-center justify-center h-full">
              <div className="text-center">
                <MessageSquare className="w-12 h-12 text-slate-300 mx-auto mb-3" />
                <h2 className="text-base text-slate-600 mb-1">
                  Start a conversation
                </h2>
                <p className="text-sm text-slate-400">
                  Send a message to begin chatting
                </p>
              </div>
            </div>
          )}

          {currentChat?.messages.map((message) => (
            <div
              key={message.id}
              className={`flex ${
                message.role === "user" ? "justify-end" : "justify-start"
              }`}
            >
              {/* Avatar for assistant */}
              {message.role === "assistant" && (
                <div className="w-7 h-7 rounded-full bg-gradient-to-br from-[#059669] to-[#047857] flex items-center justify-center flex-shrink-0 mt-0.5 mr-2">
                  <Bot className="w-3.5 h-3.5 text-white" />
                </div>
              )}

              <div
                className={`max-w-2xl px-4 py-3 rounded-2xl ${
                  message.role === "user"
                    ? "bg-[#3B82F6] text-white rounded-tr-sm shadow-sm"
                    : "bg-[#F3F4F6] border-0 text-slate-900 rounded-tl-sm shadow-sm"
                }`}
              >
                {message.role === "user" ? (
                  <p className="text-sm whitespace-pre-wrap break-words leading-relaxed">
                    {message.content}
                  </p>
                ) : message.content === "" && streamingMsgId === message.id ? (
                  // Waiting for first chunk — show typing indicator
                  <TypingIndicator />
                ) : (
                  // Render markdown for assistant messages
                  <div className="text-slate-900">
                    <ReactMarkdown
                      remarkPlugins={[remarkGfm, remarkMath]}
                      rehypePlugins={[rehypeKatex]}
                      components={markdownComponents}
                    >
                      {streamingMsgId === message.id
                        ? message.content
                        : preprocessMarkdown(message.content)}
                    </ReactMarkdown>
                  </div>
                )}

                {/* Sources */}
                {message.role === "assistant" &&
                  message.sources &&
                  message.sources.length > 0 && (
                    <div className="mt-2 pt-2 border-t border-slate-100">
                      <p className="text-[10px] text-slate-400 mb-1.5">
                        Sources:
                      </p>
                      <div className="flex flex-wrap gap-1">
                        {message.sources.map((src, i) => (
                          <span
                            key={i}
                            className="text-[10px] bg-slate-100 text-slate-600 px-2 py-0.5 rounded-full border border-slate-200"
                            title={
                              src.page_label
                                ? `Page ${src.page_label}`
                                : undefined
                            }
                          >
                            📄 {src.filename}
                            {src.page_label ? ` p.${src.page_label}` : ""}
                          </span>
                        ))}
                      </div>
                    </div>
                  )}
              </div>
            </div>
          ))}


          <div ref={messagesEndRef} />
        </div>

        {/* Input Area — hidden when interview phase active or no room selected */}
        <div className={`relative z-10 bg-white border-t border-slate-200 p-3 shadow-[0_-2px_10px_rgba(0,0,0,0.06)] ${!currentChatId || (currentChatId && currentPhase === "interview") ? "hidden" : ""}`}>
          <div className="max-w-4xl mx-auto">
            <div className="flex gap-2 items-end">
              <textarea
                value={input}
                onChange={(e) => setInput(e.target.value)}
                onKeyDown={handleKeyPress}
                placeholder="Ask me anything... (Enter to send, Shift+Enter for newline)"
                rows={1}
                className="flex-1 px-3 py-2 text-sm rounded-lg border border-slate-300 focus:outline-none focus:ring-2 focus:ring-[#3B82F6] focus:border-transparent resize-none max-h-32"
                disabled={isStreaming}
              />
              <button
                onClick={handleSend}
                disabled={!input.trim() || isStreaming}
                className="bg-[#3B82F6] hover:bg-[#2563EB] text-white p-2.5 rounded-lg transition-all duration-200 hover:scale-105 disabled:opacity-50 disabled:cursor-not-allowed flex-shrink-0"
              >
                {isStreaming ? (
                  <Loader2 className="w-4 h-4 animate-spin" />
                ) : (
                  <Send className="w-4 h-4" />
                )}
              </button>
            </div>
          </div>
        </div>
      </div>

      {/* Knowledge Management Modal */}
      <KnowledgeManagement
        open={knowledgeOpen}
        onClose={() => setKnowledgeOpen(false)}
      />

      {/* Interview Result Modal */}
      {resultModalOpen && interviewResult && (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40 backdrop-blur-sm"
          onClick={() => setResultModalOpen(false)}
        >
          <div
            className="bg-white rounded-2xl shadow-2xl w-full max-w-2xl max-h-[85vh] flex flex-col overflow-hidden"
            onClick={(e) => e.stopPropagation()}
          >
            <div className="flex items-center justify-between px-5 py-4 border-b border-slate-200">
              <h2 className="text-base font-semibold text-slate-800">Hasil Interview</h2>
              <button
                onClick={() => setResultModalOpen(false)}
                className="text-slate-400 hover:text-slate-600 transition p-1 rounded-lg hover:bg-slate-100"
              >
                <X className="w-4 h-4" />
              </button>
            </div>
            <div className="overflow-y-auto flex-1">
              <InterviewResultView result={interviewResult} />
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
