﻿import { useEffect, useMemo, useRef, useState } from "react";

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

type ChatMessage = {
  id: string;
  role: Role;
  content: string;
  createdAt: number;
};

type StatusEvent = {
  message: string;
};

const SHORTCUTS = [
  { combo: "Ctrl+Enter", action: "Send" },
  { combo: "Ctrl+K", action: "Focus input" },
  { combo: "Esc", action: "Clear" }
];

function useSessionId() {
  const [sessionId] = useState(() => {
    const cached = localStorage.getItem("novachat_session");
    if (cached) return cached;
    const created = crypto.randomUUID();
    localStorage.setItem("novachat_session", created);
    return created;
  });
  return sessionId;
}

export default function App() {
  const sessionId = useSessionId();
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [input, setInput] = useState("");
  const [status, setStatus] = useState("Idle");
  const [isStreaming, setIsStreaming] = useState(false);
  const [theme, setTheme] = useState(() => localStorage.getItem("novachat_theme") ?? "dark");
  const inputRef = useRef<HTMLTextAreaElement | null>(null);
  const bottomRef = useRef<HTMLDivElement | null>(null);
  const streamRef = useRef<EventSource | null>(null);

  useEffect(() => {
    document.documentElement.dataset.theme = theme;
    localStorage.setItem("novachat_theme", theme);
  }, [theme]);

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

  useEffect(() => {
    const handler = (event: KeyboardEvent) => {
      if (event.ctrlKey && event.key.toLowerCase() === "k") {
        event.preventDefault();
        inputRef.current?.focus();
      }
      if (event.ctrlKey && event.key === "Enter") {
        event.preventDefault();
        handleSend();
      }
      if (event.key === "Escape") {
        setInput("");
      }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  });

  const groupedMessages = useMemo(() => {
    const groups: ChatMessage[][] = [];
    messages.forEach((msg) => {
      const lastGroup = groups[groups.length - 1];
      if (lastGroup && lastGroup[lastGroup.length - 1].role === msg.role) {
        lastGroup.push(msg);
      } else {
        groups.push([msg]);
      }
    });
    return groups;
  }, [messages]);

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

    const userMessage: ChatMessage = {
      id: `user_${Date.now()}`,
      role: "user",
      content: trimmed,
      createdAt: Date.now()
    };

    setMessages((prev) => [...prev, userMessage]);
    setInput("");
    setIsStreaming(true);
    setStatus("Connecting...");

    streamRef.current?.close();
    const url = new URL("/api/chat/stream", window.location.origin);
    url.searchParams.set("sessionId", sessionId);
    url.searchParams.set("message", trimmed);

    const stream = new EventSource(url);
    streamRef.current = stream;

    let assistantId = `assistant_${Date.now()}`;

    const appendAssistant = (token: string) => {
      setMessages((prev) => {
        const next = [...prev];
        const existing = next.find((msg) => msg.id === assistantId);
        if (existing) {
          existing.content += token;
          return [...next];
        }
        return [...next, { id: assistantId, role: "assistant", content: token, createdAt: Date.now() }];
      });
    };

    stream.addEventListener("status", (event) => {
      const data = JSON.parse((event as MessageEvent).data) as StatusEvent;
      setStatus(data.message);
    });

    stream.addEventListener("delta", (event) => {
      const data = JSON.parse((event as MessageEvent).data) as { token: string };
      appendAssistant(data.token);
      setStatus("Responding...");
    });

    stream.addEventListener("done", () => {
      setIsStreaming(false);
      setStatus("Idle");
      stream.close();
    });

    stream.addEventListener("error", (event) => {
      setIsStreaming(false);
      setStatus("Connection error");
      stream.close();
    });
  };

  return (
    <div className="app">
      <header className="topbar">
        <div className="brand">
          <div className="brand-mark" />
          <div>
            <div className="brand-title">NovaChat</div>
            <div className="brand-subtitle">Real-time intelligence engine</div>
          </div>
        </div>
        <div className="topbar-actions">
          <button className="ghost" onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
            {theme === "dark" ? "Light" : "Dark"} mode
          </button>
          <button className="ghost" onClick={() => setMessages([])}>
            New session
          </button>
        </div>
      </header>

      <main className="layout">
        <section className="chat">
          <div className="chat-header">
            <div>
              <div className="chat-title">Control Room</div>
              <div className="chat-subtitle">Ultra-low latency responses with live web search.</div>
            </div>
            <div className="status">
              <span className={isStreaming ? "pulse" : "dot"} />
              {status}
            </div>
          </div>

          <div className="chat-body">
            {groupedMessages.length === 0 ? (
              <div className="empty">
                <h2>Ask anything. Get fast, grounded answers.</h2>
                <p>Type a request and NovaChat will decide when to pull live web sources.</p>
                <div className="shortcut-grid">
                  {SHORTCUTS.map((shortcut) => (
                    <div key={shortcut.combo} className="shortcut-card">
                      <div className="shortcut-combo">{shortcut.combo}</div>
                      <div className="shortcut-action">{shortcut.action}</div>
                    </div>
                  ))}
                </div>
              </div>
            ) : (
              groupedMessages.map((group) => (
                <div key={group[0].id} className={`message-group ${group[0].role}`}>
                  <div className="message-meta">{group[0].role === "user" ? "You" : "Nova"}</div>
                  <div className="message-stack">
                    {group.map((msg) => (
                      <div key={msg.id} className="message-bubble">
                        {msg.content}
                      </div>
                    ))}
                  </div>
                </div>
              ))
            )}
            {isStreaming && (
              <div className="typing">
                <span />
                <span />
                <span />
              </div>
            )}
            <div ref={bottomRef} />
          </div>

          <div className="chat-input">
            <textarea
              ref={inputRef}
              placeholder="Ask NovaChat to research, summarize, or build something..."
              value={input}
              onChange={(event) => setInput(event.target.value)}
              rows={2}
            />
            <div className="input-actions">
              <div className="input-hint">Session: {sessionId.slice(0, 8)}</div>
              <button className="primary" onClick={handleSend} disabled={isStreaming || !input.trim()}>
                {isStreaming ? "Streaming..." : "Send"}
              </button>
            </div>
          </div>
        </section>

        <aside className="sidebar">
          <div className="card">
            <h3>Live Ops</h3>
            <p>Search cache and streaming are running in parallel for zero-lag delivery.</p>
            <div className="metric">
              <span>Latency target</span>
              <strong>&lt; 800ms</strong>
            </div>
            <div className="metric">
              <span>Streaming</span>
              <strong>Token-by-token</strong>
            </div>
          </div>
          <div className="card">
            <h3>Search Stack</h3>
            <p>Multi-source fetch, extraction, ranking, and summarization pipeline.</p>
            <div className="badge-row">
              <span>DuckDuckGo</span>
              <span>Readability</span>
              <span>LRU Cache</span>
            </div>
          </div>
          <div className="card">
            <h3>Controls</h3>
            <p>NovaChat automatically decides when to search the web.</p>
            <button className="ghost full" onClick={() => setStatus("Manual search mode coming soon")}>Enable manual search</button>
          </div>
        </aside>
      </main>
    </div>
  );
}
