import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useServerFn } from "@tanstack/react-start";
import { useState, useEffect, useRef, useMemo } from "react";
import { z } from "zod";
import ReactMarkdown from "react-markdown";
import { supabase } from "@/integrations/supabase/client";
import { chatWithCoach, clearCoach, titleConversation, cleanupCoachHistory } from "@/lib/ai.functions";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import {
  Loader2, Send, Sparkles, Trash2, Plus, Search, Pin, PinOff, Archive,
  ArchiveRestore, MessagesSquare, X, Brain, ChevronLeft,
} from "lucide-react";
import { Link } from "@tanstack/react-router";
import { DisclaimerNote } from "@/components/legal/DisclaimerNote";


export const Route = createFileRoute("/_authenticated/coach")({
  validateSearch: z.object({ c: z.string().optional() }),
  head: () => ({
    meta: [
      { title: "Coach — PRUDENTIA" },
      { name: "description", content: "Chat with your AI financial coach. Persistent, searchable conversations with pinning and archiving." },
      { property: "og:title", content: "Coach — PRUDENTIA" },
      { property: "og:description", content: "Your AI financial coach with full conversation history." },
    ],
  }),
  component: CoachPage,
});

type Conversation = {
  id: string; title: string; pinned: boolean; archived: boolean;
  last_message_at: string; created_at: string;
};

function CoachPage() {
  const { user } = Route.useRouteContext();
  const { c: activeId } = Route.useSearch();
  const navigate = useNavigate({ from: "/coach" });
  const qc = useQueryClient();

  const chatFn = useServerFn(chatWithCoach);
  const clearFn = useServerFn(clearCoach);
  const titleFn = useServerFn(titleConversation);
  const cleanupFn = useServerFn(cleanupCoachHistory);

  const [input, setInput] = useState("");
  const [sending, setSending] = useState(false);
  const [drawer, setDrawer] = useState(false);
  const [query, setQuery] = useState("");
  const [showArchived, setShowArchived] = useState(false);
  const scrollRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLTextAreaElement>(null);

  const convQ = useQuery({
    queryKey: ["conversations", user.id],
    queryFn: async () =>
      ((await supabase.from("ai_conversations").select("*").eq("user_id", user.id)
        .order("pinned", { ascending: false })
        .order("last_message_at", { ascending: false })).data ?? []) as Conversation[],
  });

  const messagesQ = useQuery({
    queryKey: ["chats", user.id, activeId ?? "new"],
    enabled: !!activeId,
    queryFn: async () =>
      (await supabase.from("ai_chats").select("*")
        .eq("user_id", user.id)
        .eq("conversation_id", activeId!)
        .order("created_at", { ascending: true })).data ?? [],
  });

  // Search across every message of every conversation
  const searchQ = useQuery({
    queryKey: ["chat-search", user.id, query],
    enabled: query.trim().length > 1,
    queryFn: async () =>
      (await supabase.from("ai_chats").select("id, content, role, conversation_id, created_at")
        .eq("user_id", user.id)
        .ilike("content", `%${query.trim()}%`)
        .order("created_at", { ascending: false })
        .limit(30)).data ?? [],
  });

  const conversations = convQ.data ?? [];
  const visibleConversations = useMemo(() => {
    const list = conversations.filter((c) => (showArchived ? c.archived : !c.archived));
    const q = query.trim().toLowerCase();
    return q ? list.filter((c) => c.title.toLowerCase().includes(q)) : list;
  }, [conversations, showArchived, query]);

  const messages = messagesQ.data ?? [];
  const activeConv = conversations.find((c) => c.id === activeId);

  useEffect(() => {
    scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" });
  }, [messages, sending]);

  useEffect(() => {
    if (!drawer) inputRef.current?.focus();
  }, [drawer, activeId, sending]);

  // Retention housekeeping: drop stale archived, unpinned threads once per session
  useEffect(() => {
    const flag = `aura-cleanup-${user.id}-${new Date().toDateString()}`;
    if (typeof window === "undefined" || window.localStorage.getItem(flag)) return;
    window.localStorage.setItem(flag, "1");
    cleanupFn({ data: { retentionDays: 30 } })
      .then((r) => { if (r.removed) qc.invalidateQueries({ queryKey: ["conversations", user.id] }); })
      .catch(() => {});
  }, [user.id, cleanupFn, qc]);

  async function send() {
    const text = input.trim();
    if (!text || sending) return;
    setInput(""); setSending(true);
    const isFirst = !activeId;
    try {
      const res = await chatFn({ data: { message: text, conversationId: activeId } });
      if (!activeId) navigate({ search: { c: res.conversationId } });
      qc.invalidateQueries({ queryKey: ["chats", user.id, res.conversationId] });
      qc.invalidateQueries({ queryKey: ["conversations", user.id] });
      if (isFirst) {
        titleFn({ data: { conversationId: res.conversationId } })
          .then(() => qc.invalidateQueries({ queryKey: ["conversations", user.id] }))
          .catch(() => {});
      }
    } catch (e: any) {
      setInput(text);
      toast.error(e?.message ?? "Failed to send");
    } finally { setSending(false); }
  }

  async function patchConv(id: string, patch: Partial<Conversation>) {
    const { error } = await supabase.from("ai_conversations").update(patch).eq("id", id);
    if (error) return toast.error(error.message);
    qc.invalidateQueries({ queryKey: ["conversations", user.id] });
  }

  async function deleteConv(id: string) {
    const { error } = await supabase.from("ai_conversations").delete().eq("id", id);
    if (error) return toast.error(error.message);
    if (id === activeId) navigate({ search: {} });
    qc.invalidateQueries({ queryKey: ["conversations", user.id] });
    toast.success("Conversation deleted");
  }

  async function togglePinMessage(id: string, pinned: boolean) {
    const { error } = await supabase.from("ai_chats").update({ pinned: !pinned }).eq("id", id);
    if (error) return toast.error(error.message);
    qc.invalidateQueries({ queryKey: ["chats", user.id, activeId ?? "new"] });
  }

  async function clearEverything() {
    await clearFn();
    navigate({ search: {} });
    qc.invalidateQueries({ queryKey: ["conversations", user.id] });
    toast.success("History cleared");
  }

  return (
    <div className="flex flex-col h-[calc(100dvh-6rem)] relative">
      <header className="flex items-end justify-between px-5 pt-8 pb-4">
        <div className="min-w-0">
          <p className="text-[11px] text-muted-foreground uppercase tracking-widest">Companion</p>
          <h1 className="text-2xl font-semibold flex items-center gap-2 truncate">
            <span className="text-gradient-brand">Coach</span>
          </h1>
          {activeConv && <p className="text-[11px] text-muted-foreground truncate mt-0.5">{activeConv.title}</p>}
        </div>
        <div className="flex items-center gap-2">
          <Link to="/intelligence" className="size-9 rounded-full glass grid place-items-center" aria-label="Intelligence">
            <Brain className="size-4" />
          </Link>
          <button onClick={() => navigate({ search: {} })} className="size-9 rounded-full glass grid place-items-center" aria-label="New conversation">
            <Plus className="size-4" />
          </button>
          <button onClick={() => setDrawer(true)} className="size-9 rounded-full glass grid place-items-center relative" aria-label="Conversation history">
            <MessagesSquare className="size-4" />
            {conversations.length > 0 && (
              <span className="absolute -top-0.5 -right-0.5 min-w-4 h-4 px-1 rounded-full bg-electric text-primary-foreground text-[9px] grid place-items-center font-semibold">
                {conversations.filter((c) => !c.archived).length}
              </span>
            )}
          </button>
        </div>
      </header>

      <div ref={scrollRef} className="flex-1 overflow-y-auto px-4 space-y-4 pb-4">
        {!activeId && (
          <div className="mt-10 text-center">
            <div className="mx-auto size-12 rounded-2xl bg-gradient-to-br from-electric to-purple grid place-items-center glow-electric mb-3">
              <Sparkles className="size-5 text-primary-foreground" />
            </div>
            <p className="text-sm text-muted-foreground">Ask about spending, goals, big decisions.</p>
            <div className="flex flex-col gap-2 mt-5 max-w-xs mx-auto">
              {["Where am I overspending?", "How can I hit my goals faster?", "Am I saving enough for retirement?"].map((s) => (
                <button key={s} onClick={() => setInput(s)} className="glass rounded-2xl px-4 py-2.5 text-sm text-left text-foreground/90">{s}</button>
              ))}
            </div>
            {conversations.filter((c) => !c.archived).length > 0 && (
              <button onClick={() => setDrawer(true)} className="mt-6 text-xs text-electric">
                Open your {conversations.filter((c) => !c.archived).length} saved conversation(s)
              </button>
            )}
          </div>
        )}

        {messages.map((m: any) => (
          <div key={m.id} className={`group flex ${m.role === "user" ? "justify-end" : "justify-start"} animate-aura-fade`}>
            <div className="max-w-[88%] space-y-1">
              <div
                className={
                  m.role === "user"
                    ? "rounded-2xl px-4 py-2.5 text-sm leading-relaxed whitespace-pre-wrap bg-gradient-to-br from-electric to-purple text-primary-foreground"
                    : "text-sm leading-relaxed text-foreground/95 markdown-chat"
                }
              >
                {m.role === "user" ? m.content : <ReactMarkdown>{m.content}</ReactMarkdown>}
              </div>
              <div className={`flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity ${m.role === "user" ? "justify-end" : ""}`}>
                {m.pinned && <Pin className="size-3 text-electric" />}
                <button onClick={() => togglePinMessage(m.id, m.pinned)} className="text-[10px] text-muted-foreground hover:text-electric">
                  {m.pinned ? "Unpin" : "Pin"}
                </button>
                <button
                  onClick={() => { navigator.clipboard?.writeText(m.content); toast.success("Copied"); }}
                  className="text-[10px] text-muted-foreground hover:text-foreground"
                >
                  Copy
                </button>
              </div>
            </div>
          </div>
        ))}

        {sending && (
          <div className="flex justify-start">
            <div className="text-sm text-muted-foreground flex items-center gap-2">
              <Loader2 className="size-3 animate-spin" /> Thinking…
            </div>
          </div>
        )}
      </div>

      <div className="px-4 pb-2">
        <div className="glass rounded-3xl flex items-end gap-2 pl-4 pr-1.5 py-1.5">
          <textarea
            ref={inputRef}
            value={input}
            rows={1}
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send(); } }}
            placeholder={activeId ? "Continue the conversation…" : "Ask your coach…"}
            className="flex-1 bg-transparent outline-none text-sm py-2 resize-none max-h-32"
          />
          <Button
            size="sm"
            onClick={send}
            disabled={sending || !input.trim()}
            className="rounded-full size-9 shrink-0 p-0 bg-gradient-to-br from-electric to-purple text-primary-foreground grid place-items-center"
            aria-label="Send"
          >
            {sending ? <Loader2 className="size-4 animate-spin" /> : <Send className="size-4" />}
          </Button>
        </div>
        <DisclaimerNote className="px-2 pt-2" />
      </div>


      {/* History drawer */}
      {drawer && (
        <div className="fixed inset-0 z-50 flex">
          <button className="absolute inset-0 bg-background/70 backdrop-blur-sm" aria-label="Close history" onClick={() => setDrawer(false)} />
          <div className="relative ml-auto h-full w-full max-w-sm glass rounded-l-3xl p-4 flex flex-col animate-aura-slide-up">
            <div className="flex items-center justify-between">
              <h2 className="text-sm font-semibold flex items-center gap-2"><ChevronLeft className="size-4" /> History</h2>
              <button onClick={() => setDrawer(false)} className="size-8 rounded-full glass grid place-items-center" aria-label="Close">
                <X className="size-4" />
              </button>
            </div>

            <div className="mt-3 glass rounded-full flex items-center gap-2 px-3 py-2">
              <Search className="size-3.5 text-muted-foreground" />
              <input
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                placeholder="Search conversations and messages"
                className="flex-1 bg-transparent outline-none text-xs"
              />
              {query && <button onClick={() => setQuery("")} aria-label="Clear search"><X className="size-3.5 text-muted-foreground" /></button>}
            </div>

            <div className="flex items-center gap-2 mt-3">
              <button
                onClick={() => setShowArchived(false)}
                className={`rounded-full px-3 py-1 text-[11px] ${!showArchived ? "bg-gradient-to-br from-electric to-purple text-primary-foreground" : "glass text-muted-foreground"}`}
              >
                Active
              </button>
              <button
                onClick={() => setShowArchived(true)}
                className={`rounded-full px-3 py-1 text-[11px] ${showArchived ? "bg-gradient-to-br from-electric to-purple text-primary-foreground" : "glass text-muted-foreground"}`}
              >
                Archived
              </button>
              <button
                onClick={() => { setDrawer(false); navigate({ search: {} }); }}
                className="ml-auto rounded-full glass px-3 py-1 text-[11px] flex items-center gap-1"
              >
                <Plus className="size-3" /> New
              </button>
            </div>

            <div className="flex-1 overflow-y-auto mt-3 space-y-2">
              {visibleConversations.length === 0 && (
                <p className="text-xs text-muted-foreground text-center py-6">
                  {showArchived ? "Nothing archived." : "No conversations yet."}
                </p>
              )}
              {visibleConversations.map((c) => (
                <div key={c.id} className={`rounded-2xl p-3 border ${c.id === activeId ? "border-electric/50 bg-electric/5" : "border-white/10 bg-white/5"}`}>
                  <div className="flex items-start gap-2">
                    <button
                      onClick={() => { navigate({ search: { c: c.id } }); setDrawer(false); }}
                      className="flex-1 text-left min-w-0"
                    >
                      <p className="text-sm font-medium truncate flex items-center gap-1.5">
                        {c.pinned && <Pin className="size-3 text-electric shrink-0" />}
                        {c.title}
                      </p>
                      <p className="text-[10px] text-muted-foreground mt-0.5">
                        {new Date(c.last_message_at).toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" })}
                      </p>
                    </button>
                    <div className="flex items-center gap-1 shrink-0">
                      <button onClick={() => patchConv(c.id, { pinned: !c.pinned })} className="size-7 rounded-full grid place-items-center text-muted-foreground hover:text-electric" aria-label={c.pinned ? "Unpin" : "Pin"}>
                        {c.pinned ? <PinOff className="size-3.5" /> : <Pin className="size-3.5" />}
                      </button>
                      <button onClick={() => patchConv(c.id, { archived: !c.archived })} className="size-7 rounded-full grid place-items-center text-muted-foreground hover:text-foreground" aria-label={c.archived ? "Restore" : "Archive"}>
                        {c.archived ? <ArchiveRestore className="size-3.5" /> : <Archive className="size-3.5" />}
                      </button>
                      <button onClick={() => deleteConv(c.id)} className="size-7 rounded-full grid place-items-center text-muted-foreground hover:text-destructive" aria-label="Delete">
                        <Trash2 className="size-3.5" />
                      </button>
                    </div>
                  </div>
                </div>
              ))}

              {query.trim().length > 1 && (searchQ.data ?? []).length > 0 && (
                <div className="pt-3">
                  <p className="text-[10px] uppercase tracking-widest text-muted-foreground px-1 pb-2">Message matches</p>
                  {(searchQ.data ?? []).map((m: any) => (
                    <button
                      key={m.id}
                      onClick={() => { if (m.conversation_id) { navigate({ search: { c: m.conversation_id } }); setDrawer(false); } }}
                      className="w-full text-left rounded-2xl px-3 py-2 hover:bg-white/5"
                    >
                      <p className="text-[10px] uppercase tracking-widest text-electric">{m.role}</p>
                      <p className="text-xs text-foreground/85 line-clamp-2">{m.content}</p>
                    </button>
                  ))}
                </div>
              )}
            </div>

            <div className="pt-3 border-t border-white/10 mt-2 flex items-center justify-between">
              <p className="text-[10px] text-muted-foreground">Archived &amp; unpinned threads auto-delete after 30 days.</p>
              <button onClick={clearEverything} className="text-[11px] text-destructive flex items-center gap-1">
                <Trash2 className="size-3" /> Clear all
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
