"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { AgentChat, type AgentChatMessageActions } from "@/components/app/agent-chat";
import { AgentThreadRail } from "@/components/app/agent-thread-rail";
import type { AgentDefinition } from "@/lib/sag/agents";
import {
  loadThreads,
  saveThread,
  deleteThread,
  renameThread,
  summarizeThreadTitle,
  type AgentMessage,
  type AgentThread,
} from "@/lib/agents/threads";

interface AgentChatWithThreadsProps {
  agent: AgentDefinition;
  agentSlug: string;
  /**
   * Optional render slot forwarded to the inner `AgentChat`. Use this to add
   * per-message actions (e.g. the Marketing Agent's "Send to social
   * composer" button on assistant replies).
   */
  messageActions?: AgentChatMessageActions;
  /**
   * When true, the inner `AgentChat` renders the LLM Council veto-check
   * toggle. Forwarded as-is. See `AgentChat` for behavior.
   */
  enableCouncilVeto?: boolean;
}

function newThreadShell(agentSlug: string): AgentThread {
  const now = new Date().toISOString();
  return {
    id: typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `t_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
    agentSlug,
    title: "New chat",
    messages: [],
    createdAt: now,
    updatedAt: now,
  };
}

export function AgentChatWithThreads({
  agent,
  agentSlug,
  messageActions,
  enableCouncilVeto,
}: AgentChatWithThreadsProps) {
  const [threads, setThreads] = useState<AgentThread[]>([]);
  const [activeThreadId, setActiveThreadId] = useState<string | null>(null);
  const [hydrated, setHydrated] = useState(false);
  const [showRail, setShowRail] = useState(false);

  // Debounce queue for saves.
  const saveTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());

  // Hydrate from localStorage on mount. Deferred to avoid synchronous setState-in-effect
  // and to ensure window.localStorage is only read on the client.
  useEffect(() => {
    const handle = setTimeout(() => {
      const existing = loadThreads(agentSlug);
      if (existing.length > 0) {
        setThreads(existing);
        setActiveThreadId(existing[0].id);
      } else {
        const fresh = newThreadShell(agentSlug);
        setThreads([fresh]);
        setActiveThreadId(fresh.id);
      }
      setHydrated(true);
    }, 0);
    return () => clearTimeout(handle);
  }, [agentSlug]);

  // Cancel pending saves on unmount.
  useEffect(() => {
    const timers = saveTimers.current;
    return () => {
      timers.forEach((t) => clearTimeout(t));
      timers.clear();
    };
  }, []);

  const activeThread = useMemo(
    () => threads.find((t) => t.id === activeThreadId) ?? null,
    [threads, activeThreadId]
  );

  const scheduleSave = useCallback((thread: AgentThread) => {
    const existing = saveTimers.current.get(thread.id);
    if (existing) clearTimeout(existing);
    const handle = setTimeout(() => {
      // Only persist threads that contain at least one message.
      if (thread.messages.length > 0) {
        saveThread(thread);
      }
      saveTimers.current.delete(thread.id);
    }, 500);
    saveTimers.current.set(thread.id, handle);
  }, []);

  const handleMessagesChange = useCallback(
    (msgs: AgentMessage[]) => {
      if (!activeThreadId) return;
      setThreads((prev) => {
        const idx = prev.findIndex((t) => t.id === activeThreadId);
        if (idx < 0) return prev;
        const current = prev[idx];
        const wasFresh = current.messages.length === 0 && current.title === "New chat";
        const nextThread: AgentThread = {
          ...current,
          messages: msgs,
          title: wasFresh ? summarizeThreadTitle(msgs) : current.title,
          updatedAt: new Date().toISOString(),
        };
        const nextList = [...prev];
        nextList[idx] = nextThread;
        scheduleSave(nextThread);
        return nextList;
      });
    },
    [activeThreadId, scheduleSave]
  );

  function handleSelectThread(threadId: string) {
    setActiveThreadId(threadId);
    setShowRail(false);
  }

  function handleNewThread() {
    // If there is already an empty fresh thread, reuse it instead of stacking duplicates.
    const emptyFresh = threads.find((t) => t.messages.length === 0);
    if (emptyFresh) {
      setActiveThreadId(emptyFresh.id);
      setShowRail(false);
      return;
    }
    const fresh = newThreadShell(agentSlug);
    setThreads((prev) => [fresh, ...prev]);
    setActiveThreadId(fresh.id);
    setShowRail(false);
  }

  function handleRenameThread(threadId: string, title: string) {
    renameThread(threadId, title);
    setThreads((prev) =>
      prev.map((t) =>
        t.id === threadId ? { ...t, title, updatedAt: new Date().toISOString() } : t
      )
    );
  }

  function handleDeleteThread(threadId: string) {
    deleteThread(threadId);
    setThreads((prev) => {
      const remaining = prev.filter((t) => t.id !== threadId);
      if (threadId === activeThreadId) {
        if (remaining.length > 0) {
          setActiveThreadId(remaining[0].id);
        } else {
          const fresh = newThreadShell(agentSlug);
          setActiveThreadId(fresh.id);
          return [fresh];
        }
      }
      return remaining;
    });
  }

  if (!hydrated) {
    return <div className="flex-1 bg-muted/20" />;
  }

  return (
    <div className="flex-1 flex flex-col lg:flex-row min-h-0">
      {/* Mobile/tablet disclosure */}
      <div className="lg:hidden border-b bg-background px-4 py-2">
        <button
          type="button"
          onClick={() => setShowRail((v) => !v)}
          className="text-sm font-medium text-muted-foreground hover:text-foreground"
        >
          Threads {showRail ? "▴" : "▾"}
        </button>
      </div>

      <div className={`${showRail ? "block" : "hidden"} lg:block lg:h-auto`}>
        <AgentThreadRail
          threads={threads}
          activeThreadId={activeThreadId}
          onSelectThread={handleSelectThread}
          onNewThread={handleNewThread}
          onRenameThread={handleRenameThread}
          onDeleteThread={handleDeleteThread}
        />
      </div>

      <AgentChat
        agent={agent}
        threadId={activeThread?.id}
        initialMessages={activeThread?.messages ?? []}
        onMessagesChange={handleMessagesChange}
        messageActions={messageActions}
        enableCouncilVeto={enableCouncilVeto}
      />
    </div>
  );
}
