import { type FormEvent, useEffect, useRef, useState } from "react";
import { useAction, useQuery } from "convex/react";
import { MessageCircle, Send, Loader2 } from "lucide-react";
import { api } from "../../convex/_generated/api";
import { useAccountFilterId } from "@/components/layout/AccountFilter";
import { useFilters } from "@/context/FilterContext";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";
import { ChatHistory, type ChatHistoryItem } from "@/components/chat/ChatHistory";
import { toast } from "sonner";

type ToolTrace = {
  name: string;
  inputSummary: string;
  resultSummary: string;
};
type UserChatMessage = { role: "user"; content: string };
type AssistantChatMessage = {
  role: "assistant";
  content: string;
  toolTrace?: ToolTrace[];
};
type ChatMessage = UserChatMessage | AssistantChatMessage;
type ChatSession = {
  id: string;
  title: string;
  createdAt: number;
  updatedAt: number;
  messages: ChatMessage[];
};

const STORAGE_KEY = "savings-chat-sessions";
const initialAssistantMessage: ChatMessage = {
  role: "assistant",
  content: "Frag mich zu deinen Umsätzen – ich werte sie im aktuellen Zeitraum aus.",
};
const fallbackMessages = [initialAssistantMessage];

function normalizeToolTrace(value: unknown): ToolTrace[] | undefined {
  if (!Array.isArray(value)) return undefined;
  const trace = value.flatMap((item) => {
    if (!item || typeof item !== "object") return [];
    const candidate = item as Record<string, unknown>;
    if (
      typeof candidate.name !== "string" ||
      typeof candidate.inputSummary !== "string" ||
      typeof candidate.resultSummary !== "string"
    ) {
      return [];
    }

    return [
      {
        name: candidate.name,
        inputSummary: candidate.inputSummary,
        resultSummary: candidate.resultSummary,
      },
    ];
  });

  return trace.length > 0 ? trace : undefined;
}

function normalizeMessage(value: unknown): ChatMessage | null {
  if (!value || typeof value !== "object") return null;
  const candidate = value as Record<string, unknown>;
  if (typeof candidate.content !== "string") return null;
  if (candidate.role === "user") {
    return { role: "user", content: candidate.content };
  }
  if (candidate.role === "assistant") {
    const toolTrace = normalizeToolTrace(candidate.toolTrace);
    return toolTrace
      ? { role: "assistant", content: candidate.content, toolTrace }
      : { role: "assistant", content: candidate.content };
  }

  return null;
}

function isChatMessage(value: ChatMessage | null): value is ChatMessage {
  return value !== null;
}

function normalizeSession(value: unknown): ChatSession | null {
  if (!value || typeof value !== "object") return null;
  const candidate = value as Record<string, unknown>;
  if (
    typeof candidate.id !== "string" ||
    typeof candidate.title !== "string" ||
    typeof candidate.createdAt !== "number" ||
    typeof candidate.updatedAt !== "number" ||
    !Array.isArray(candidate.messages)
  ) {
    return null;
  }

  const messages = candidate.messages.map(normalizeMessage);
  if (!messages.every(isChatMessage)) return null;

  return {
    id: candidate.id,
    title: candidate.title,
    createdAt: candidate.createdAt,
    updatedAt: candidate.updatedAt,
    messages,
  };
}

function createSession(): ChatSession {
  const now = Date.now();
  const randomId =
    typeof crypto !== "undefined" && "randomUUID" in crypto
      ? crypto.randomUUID()
      : `${now}-${Math.random().toString(36).slice(2)}`;

  return {
    id: randomId,
    title: "Neuer Chat",
    createdAt: now,
    updatedAt: now,
    messages: [initialAssistantMessage],
  };
}

function loadSessions(): ChatSession[] {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return [createSession()];
    const parsed: unknown = JSON.parse(raw);
    if (!Array.isArray(parsed) || parsed.length === 0) return [createSession()];
    const sessions = parsed.map(normalizeSession);
    if (sessions.some((session) => session === null)) return [createSession()];
    return sessions as ChatSession[];
  } catch {
    return [createSession()];
  }
}

function titleFromMessages(messages: ChatMessage[]) {
  const firstUserMessage = messages.find((message) => message.role === "user")?.content.trim();
  if (!firstUserMessage) return "Neuer Chat";
  return firstUserMessage.length > 44 ? `${firstUserMessage.slice(0, 44)}…` : firstUserMessage;
}

export function SavingsChatPage() {
  const { from, to, monthBasis } = useFilters();
  const accountId = useAccountFilterId();

  const [draft, setDraft] = useState("");
  const [sessions, setSessions] = useState<ChatSession[]>(loadSessions);
  const [activeSessionId, setActiveSessionId] = useState(() => sessions[0]?.id ?? "");
  const [isSubmitting, setIsSubmitting] = useState(false);
  const listRef = useRef<HTMLDivElement | null>(null);
  const activeSession = sessions.find((session) => session.id === activeSessionId) ?? sessions[0];
  const messages = activeSession?.messages ?? fallbackMessages;

  const context = useQuery(api.savingsChat.getContext, {
    from,
    to,
    accountId,
    basis: monthBasis,
  });
  const ask = useAction(api.savingsChat.ask);

  const buttonDisabled = isSubmitting || draft.trim().length === 0;

  const formatAmount = (amount: number) =>
    new Intl.NumberFormat("de-DE", {
      style: "currency",
      currency: "EUR",
    }).format(amount);

  const getContextSummary = () => {
    if (!context) return "Lade Kontext…";
    return `${context.totals.transactionCount} Umsätze · Einnahmen ${formatAmount(
      context.totals.income,
    )} · Ausgaben ${formatAmount(context.totals.expenses)}`;
  };

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

  useEffect(() => {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(sessions));
  }, [sessions]);

  const updateSession = (id: string, nextMessages: ChatMessage[]) => {
    const now = Date.now();
    setSessions((prev) =>
      prev.map((session) =>
        session.id === id
          ? {
              ...session,
              title: titleFromMessages(nextMessages),
              updatedAt: now,
              messages: nextMessages,
            }
          : session,
      ),
    );
  };

  const createNewChat = () => {
    const session = createSession();
    setSessions((prev) => [session, ...prev]);
    setActiveSessionId(session.id);
    setDraft("");
  };

  const deleteChat = (id: string) => {
    const remaining = sessions.filter((session) => session.id !== id);
    const nextSessions = remaining.length > 0 ? remaining : [createSession()];
    setSessions(nextSessions);
    if (id === activeSessionId) setActiveSessionId(nextSessions[0].id);
  };

  const historyItems: ChatHistoryItem[] = sessions
    .map((session) => ({
      id: session.id,
      title: session.title,
      updatedAt: session.updatedAt,
      messageCount: session.messages.length,
    }))
    .sort((a, b) => b.updatedAt - a.updatedAt);

  const submit = async (event: FormEvent) => {
    event.preventDefault();
    const content = draft.trim();
    if (!content || isSubmitting) return;

    const submittedSessionId = activeSessionId;
    const typedNextMessages: ChatMessage[] = [...messages, { role: "user", content }];
    updateSession(submittedSessionId, typedNextMessages);
    setDraft("");
    setIsSubmitting(true);

    try {
      const response = await ask({
        messages: typedNextMessages.map((message) => ({
          role: message.role,
          content: message.content,
        })),
        from,
        to,
        accountId,
        basis: monthBasis,
      }) as { answer: string; toolTrace?: unknown };

      updateSession(submittedSessionId, [
        ...typedNextMessages,
        {
          role: "assistant",
          content: response.answer,
          toolTrace: normalizeToolTrace(response.toolTrace),
        },
      ]);
    } catch (error) {
      console.error(error);
      toast.error("Antwort konnte nicht geladen werden.");
      updateSession(submittedSessionId, [
        ...typedNextMessages,
        {
          role: "assistant",
          content: "Ich konnte gerade keine Antwort erzeugen. Bitte später erneut versuchen.",
        },
      ]);
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <div className="grid gap-4 xl:grid-cols-[280px_minmax(0,1fr)]">
      <ChatHistory
        items={historyItems}
        activeId={activeSessionId}
        onSelect={setActiveSessionId}
        onCreate={createNewChat}
        onDelete={deleteChat}
      />

      <div className="min-w-0 space-y-4">
        <div className="mb-2 flex items-center gap-2">
          <MessageCircle className="h-5 w-5" />
          <h1 className="text-lg font-semibold">Talk to your savings account</h1>
        </div>

      <Card>
        <CardHeader>
          <CardTitle>Kontext der Auswertung</CardTitle>
        </CardHeader>
        <CardContent className="space-y-1 text-sm">
          <p>Zeitraum: {from} bis {to}</p>
          <p>Basis: {monthBasis === "effective" ? "Effektiv" : "Buchungstag"}</p>
          <p>
            Konto: {context?.accountName ?? "Alle Konten"} (Basis-Saldo{" "}
            {context ? formatAmount(context.totals.balance) : "—"})
          </p>
          <p>
            {context ? getContextSummary() : "Lade Kontext…"}
          </p>
        </CardContent>
      </Card>

      <Card>
        <CardContent className="p-4">
          <div className="h-[52vh] overflow-y-auto" ref={listRef}>
            <div className="space-y-3">
              {messages.map((message, index) => (
                <div
                  key={`${message.role}-${index}`}
                  className={`rounded-lg border p-3 ${
                    message.role === "user" ? "bg-muted/50" : "bg-background"
                  }`}
                >
                  <p className="text-xs uppercase text-muted-foreground">{message.role}</p>
                  <p className="whitespace-pre-wrap text-sm">{message.content}</p>
                  {message.role === "assistant" && message.toolTrace && message.toolTrace.length > 0 && (
                    <div className="mt-3 rounded-md border bg-muted/30 p-2">
                      <p className="text-xs font-medium text-muted-foreground">
                        Verwendete Werkzeuge
                      </p>
                      <div className="mt-2 space-y-2">
                        {message.toolTrace.map((tool, toolIndex) => (
                          <div key={`${tool.name}-${toolIndex}`} className="text-xs">
                            <p className="font-medium">{tool.name}</p>
                            <p className="text-muted-foreground">{tool.resultSummary}</p>
                          </div>
                        ))}
                      </div>
                    </div>
                  )}
                </div>
              ))}
              {isSubmitting && (
                <div className="flex items-center gap-2 text-sm text-muted-foreground">
                  <Loader2 className="h-4 w-4 animate-spin" />
                  Denk mit der KI nach…
                </div>
              )}
            </div>
          </div>
        </CardContent>
      </Card>

      <form className="flex gap-2" onSubmit={submit}>
        <Input
          value={draft}
          onChange={(event) => setDraft(event.target.value)}
          placeholder="Welche Auswertung soll ich machen?"
          disabled={isSubmitting}
          autoFocus
        />
        <Button type="submit" disabled={buttonDisabled}>
          <Send className="h-4 w-4" />
          Senden
        </Button>
      </form>

      <Separator />
      <p className="text-xs text-muted-foreground">
        Antwortmodell: {context ? "Server-seitig bereit" : "…"}
      </p>
      </div>
    </div>
  );
}
