import { useCallback } from "react";
import { toast } from "sonner";
import { chatCompact, chatSend } from "@/lib/tauri";
import { useAppStore } from "@/stores/app-store";
import type { ChatMessage } from "@/types";

const EMPTY_THREAD: ChatMessage[] = [];

/// Auto-compact when serialized history exceeds this fraction of the budget.
const AUTO_COMPACT_THRESHOLD = 0.85;

function newId(prefix: string) {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
}

export function useChat(tabId: string, connectionId: string) {
  const messages = useAppStore((s) => s.chatThreads[tabId] ?? EMPTY_THREAD);
  const pending = useAppStore((s) => Boolean(s.chatPending[tabId]));
  const usage = useAppStore((s) => s.chatUsage[tabId]);
  const appendChatMessages = useAppStore((s) => s.appendChatMessages);
  const replaceChatThread = useAppStore((s) => s.replaceChatThread);
  const clearChatThread = useAppStore((s) => s.clearChatThread);
  const setChatPending = useAppStore((s) => s.setChatPending);
  const setChatUsage = useAppStore((s) => s.setChatUsage);

  const compact = useCallback(async (): Promise<boolean> => {
    const state = useAppStore.getState();
    if (state.chatPending[tabId]) {
      toast.message("Wait for the agent to finish first.");
      return false;
    }
    const history = state.chatThreads[tabId] ?? [];
    if (history.length === 0) {
      toast.message("Nothing to compact yet.");
      return false;
    }

    const beforeCount = history.length;
    setChatPending(tabId, true);
    try {
      const turn = await chatCompact(connectionId, history);
      const afterCount = turn.messages.length;
      // Backend returns the same thread untouched when there's nothing older
      // than the last user turn; surface that instead of silently no-op.
      if (afterCount >= beforeCount) {
        toast.message("Nothing to compact (no older history beyond the last question).");
        return false;
      }
      replaceChatThread(tabId, turn.messages);
      setChatUsage(tabId, turn.usage);
      const removed = beforeCount - afterCount + 1; // +1: original older replaced by single summary
      toast.success(`Compacted ${removed} earlier message${removed === 1 ? "" : "s"}.`);
      return true;
    } catch (err) {
      const text = `Compact failed: ${String(err)}`;
      toast.error("Compact failed", { description: String(err) });
      appendChatMessages(tabId, [
        {
          id: newId("err"),
          role: "assistant",
          text,
          created_at: Date.now(),
        },
      ]);
      return false;
    } finally {
      setChatPending(tabId, false);
    }
  }, [
    tabId,
    connectionId,
    appendChatMessages,
    replaceChatThread,
    setChatPending,
    setChatUsage,
  ]);

  const send = useCallback(
    async (text: string) => {
      const trimmed = text.trim();
      if (!trimmed) return;

      // Slash commands
      if (trimmed === "/clear") {
        clearChatThread(tabId);
        return;
      }
      if (trimmed === "/compact") {
        await compact();
        return;
      }

      const state = useAppStore.getState();
      if (state.chatPending[tabId]) return;

      // Auto-compact when prior turn pushed usage past threshold.
      const lastUsage = state.chatUsage[tabId];
      if (
        lastUsage &&
        lastUsage.budget_chars > 0 &&
        lastUsage.used_chars / lastUsage.budget_chars > AUTO_COMPACT_THRESHOLD &&
        (state.chatThreads[tabId]?.length ?? 0) > 1
      ) {
        const ok = await compact();
        if (!ok) return; // compact failed; bail out so the user can retry manually
      }

      const after = useAppStore.getState();
      if (after.chatPending[tabId]) return;
      const history = after.chatThreads[tabId] ?? [];
      const userMsg: ChatMessage = {
        id: newId("user"),
        role: "user",
        text: trimmed,
        created_at: Date.now(),
      };
      appendChatMessages(tabId, [userMsg]);
      setChatPending(tabId, true);
      try {
        const turn = await chatSend(connectionId, [...history, userMsg]);
        appendChatMessages(tabId, turn.messages);
        setChatUsage(tabId, turn.usage);
      } catch (err) {
        appendChatMessages(tabId, [
          {
            id: newId("err"),
            role: "assistant",
            text: `Error: ${String(err)}`,
            created_at: Date.now(),
          },
        ]);
      } finally {
        setChatPending(tabId, false);
      }
    },
    [
      tabId,
      connectionId,
      appendChatMessages,
      clearChatThread,
      compact,
      setChatPending,
      setChatUsage,
    ]
  );

  const clear = useCallback(() => clearChatThread(tabId), [tabId, clearChatThread]);

  return { messages, pending, usage, send, clear, compact };
}
