import { createFileRoute, Link } from "@tanstack/react-router";
import { useQuery } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { supabase } from "@/integrations/supabase/client";
import { GlassCard, SectionLabel } from "@/components/GlassCard";
import { CategoryIcon, MerchantAvatar } from "@/components/CategoryIcon";
import { formatCurrency, formatCompact } from "@/lib/format";
import { categoryMeta } from "@/lib/categories";
import { ResponsiveContainer, BarChart, Bar, XAxis, Tooltip, Cell, PieChart, Pie } from "recharts";
import { ArrowLeft, TrendingDown, TrendingUp, Repeat } from "lucide-react";

export const Route = createFileRoute("/_authenticated/analytics")({
  head: () => ({
    meta: [
      { title: "Analytics — PRUDENTIA" },
      { name: "description", content: "Category breakdowns, top merchants, monthly comparisons and recurring spend across your PRUDENTIA finances." },
      { property: "og:title", content: "Analytics — PRUDENTIA" },
      { property: "og:description", content: "See exactly where your money goes." },
    ],
  }),
  component: AnalyticsPage,
});

const RANGES = [
  { key: "30d", label: "30D", days: 30 },
  { key: "3m", label: "3M", days: 90 },
  { key: "6m", label: "6M", days: 180 },
  { key: "1y", label: "1Y", days: 365 },
  { key: "all", label: "All", days: null as number | null },
] as const;

function AnalyticsPage() {
  const { user } = Route.useRouteContext();
  const [range, setRange] = useState<(typeof RANGES)[number]["key"]>("3m");

  const profileQ = useQuery({ queryKey: ["profile", user.id], queryFn: async () => (await supabase.from("profiles").select("currency").eq("id", user.id).single()).data });
  const currency = profileQ.data?.currency ?? "USD";
  const txQ = useQuery({ queryKey: ["tx", user.id], queryFn: async () => (await supabase.from("transactions").select("*").eq("user_id", user.id).order("occurred_at", { ascending: false })).data ?? [] });

  const days = RANGES.find((r) => r.key === range)!.days;
  const rows = useMemo(() => {
    const cutoff = days ? Date.now() - days * 86_400_000 : 0;
    return ((txQ.data ?? []) as any[]).filter((t) => new Date(t.occurred_at).getTime() >= cutoff);
  }, [txQ.data, days]);

  const totals = useMemo(() => {
    let income = 0, expense = 0;
    rows.forEach((t) => (t.type === "income" ? (income += Number(t.amount)) : (expense += Number(t.amount))));
    const spanDays = days ?? Math.max(1, (Date.now() - new Date(rows.at(-1)?.occurred_at ?? Date.now()).getTime()) / 86_400_000);
    return { income, expense, net: income - expense, avgDaily: expense / Math.max(1, spanDays), rate: income > 0 ? ((income - expense) / income) * 100 : 0 };
  }, [rows, days]);

  const byCategory = useMemo(() => {
    const m = new Map<string, number>();
    rows.filter((t) => t.type === "expense").forEach((t) => m.set(t.category, (m.get(t.category) ?? 0) + Number(t.amount)));
    return Array.from(m, ([name, value]) => ({ name, value })).sort((a, b) => b.value - a.value);
  }, [rows]);

  const byMerchant = useMemo(() => {
    const m = new Map<string, { total: number; count: number; category: string }>();
    rows.filter((t) => t.type === "expense" && t.merchant).forEach((t) => {
      const e = m.get(t.merchant) ?? { total: 0, count: 0, category: t.category };
      e.total += Number(t.amount); e.count++; m.set(t.merchant, e);
    });
    return Array.from(m, ([name, v]) => ({ name, ...v })).sort((a, b) => b.total - a.total).slice(0, 6);
  }, [rows]);

  const monthly = useMemo(() => {
    const m = new Map<string, { label: string; income: number; expense: number }>();
    rows.forEach((t) => {
      const d = new Date(t.occurred_at);
      const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
      const e = m.get(key) ?? { label: d.toLocaleDateString(undefined, { month: "short" }), income: 0, expense: 0 };
      if (t.type === "income") e.income += Number(t.amount); else e.expense += Number(t.amount);
      m.set(key, e);
    });
    return Array.from(m.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v).slice(-12);
  }, [rows]);

  /** Merchants charged 3+ times with a stable amount look like subscriptions. */
  const recurring = useMemo(() => {
    const m = new Map<string, number[]>();
    rows.filter((t) => t.type === "expense" && t.merchant).forEach((t) => {
      const arr = m.get(t.merchant) ?? []; arr.push(Number(t.amount)); m.set(t.merchant, arr);
    });
    return Array.from(m, ([name, amounts]) => {
      const avg = amounts.reduce((s, n) => s + n, 0) / amounts.length;
      const spread = Math.max(...amounts) - Math.min(...amounts);
      return { name, count: amounts.length, avg, stable: amounts.length >= 3 && spread <= avg * 0.15 };
    }).filter((r) => r.stable).sort((a, b) => b.avg - a.avg).slice(0, 5);
  }, [rows]);

  const catTotal = byCategory.reduce((s, c) => s + c.value, 0);
  const empty = rows.length === 0;

  return (
    <div className="px-4 pt-8 pb-8 space-y-5">
      <header className="flex items-center gap-3 px-1">
        <Link to="/home" className="size-9 rounded-full glass grid place-items-center" aria-label="Back"><ArrowLeft className="size-4" /></Link>
        <div>
          <p className="text-[11px] text-muted-foreground uppercase tracking-widest">Insight</p>
          <h1 className="text-2xl font-semibold">Analytics</h1>
        </div>
      </header>

      <div className="glass rounded-full inline-flex p-1 gap-0.5">
        {RANGES.map((r) => (
          <button
            key={r.key}
            onClick={() => setRange(r.key)}
            className={`px-3 py-1 text-[11px] font-medium rounded-full transition-all ${range === r.key ? "bg-gradient-to-br from-electric to-purple text-primary-foreground" : "text-muted-foreground hover:text-foreground"}`}
          >
            {r.label}
          </button>
        ))}
      </div>

      {empty ? (
        <GlassCard className="text-center text-sm text-muted-foreground py-12">No transactions in this range yet.</GlassCard>
      ) : (
        <>
          <div className="grid grid-cols-2 gap-3">
            <Stat label="Income" value={formatCurrency(totals.income, currency)} icon={TrendingUp} tone="text-success" />
            <Stat label="Spending" value={formatCurrency(totals.expense, currency)} icon={TrendingDown} tone="text-foreground" />
            <Stat label="Avg / day" value={formatCurrency(totals.avgDaily, currency)} />
            <Stat label="Savings rate" value={`${totals.rate.toFixed(0)}%`} tone={totals.rate >= 20 ? "text-success" : totals.rate >= 0 ? "text-warning" : "text-destructive"} />
          </div>

          <SectionLabel>Where it goes</SectionLabel>
          <GlassCard>
            <div className="h-44">
              <ResponsiveContainer width="100%" height="100%">
                <PieChart>
                  <Pie data={byCategory.slice(0, 8)} dataKey="value" nameKey="name" innerRadius="60%" outerRadius="92%" paddingAngle={2} stroke="none">
                    {byCategory.slice(0, 8).map((c) => <Cell key={c.name} fill={categoryMeta(c.name).tint} />)}
                  </Pie>
                  <Tooltip
                    contentStyle={{ background: "var(--card)", border: "1px solid var(--border)", borderRadius: 16, fontSize: 12 }}
                    formatter={(v: any, n: any) => [formatCurrency(Number(v), currency), n]}
                  />
                </PieChart>
              </ResponsiveContainer>
            </div>
            <div className="space-y-2 mt-3">
              {byCategory.slice(0, 6).map((c) => (
                <div key={c.name} className="flex items-center gap-3">
                  <CategoryIcon category={c.name} size={30} />
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center justify-between text-[12px]">
                      <span className="font-medium truncate">{c.name}</span>
                      <span className="tabular-nums text-muted-foreground">{formatCurrency(c.value, currency)} · {((c.value / catTotal) * 100).toFixed(0)}%</span>
                    </div>
                    <div className="h-1 rounded-full bg-white/10 mt-1 overflow-hidden">
                      <div className="h-full rounded-full" style={{ width: `${(c.value / catTotal) * 100}%`, background: categoryMeta(c.name).tint }} />
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </GlassCard>

          <SectionLabel>Month over month</SectionLabel>
          <GlassCard>
            <div className="h-48">
              <ResponsiveContainer width="100%" height="100%">
                <BarChart data={monthly} barGap={2}>
                  <XAxis dataKey="label" tickLine={false} axisLine={false} tick={{ fontSize: 10, fill: "var(--muted-foreground)" }} />
                  <Tooltip
                    cursor={{ fill: "rgba(255,255,255,0.04)" }}
                    contentStyle={{ background: "var(--card)", border: "1px solid var(--border)", borderRadius: 16, fontSize: 12 }}
                    formatter={(v: any, n: any) => [formatCurrency(Number(v), currency), n === "income" ? "Income" : "Spending"]}
                  />
                  <Bar dataKey="income" fill="var(--success)" radius={[6, 6, 0, 0]} maxBarSize={16} />
                  <Bar dataKey="expense" fill="var(--electric)" radius={[6, 6, 0, 0]} maxBarSize={16} />
                </BarChart>
              </ResponsiveContainer>
            </div>
            <p className="text-[11px] text-muted-foreground mt-2">
              Net across this range: <span className={totals.net >= 0 ? "text-success" : "text-destructive"}>{formatCompact(totals.net, currency)}</span>
            </p>
          </GlassCard>

          {byMerchant.length > 0 && (
            <>
              <SectionLabel>Top merchants</SectionLabel>
              <GlassCard className="divide-y divide-white/5 p-0 overflow-hidden">
                {byMerchant.map((m) => (
                  <div key={m.name} className="flex items-center gap-3 px-4 py-3">
                    <MerchantAvatar merchant={m.name} category={m.category} size={32} />
                    <div className="flex-1 min-w-0">
                      <p className="text-sm font-medium truncate">{m.name}</p>
                      <p className="text-[11px] text-muted-foreground">{m.count} transaction{m.count > 1 ? "s" : ""}</p>
                    </div>
                    <p className="text-sm font-medium tabular-nums">{formatCurrency(m.total, currency)}</p>
                  </div>
                ))}
              </GlassCard>
            </>
          )}

          {recurring.length > 0 && (
            <>
              <SectionLabel>Looks recurring</SectionLabel>
              <GlassCard className="space-y-3">
                {recurring.map((r) => (
                  <div key={r.name} className="flex items-center gap-3">
                    <div className="size-8 rounded-full bg-white/5 grid place-items-center text-muted-foreground"><Repeat className="size-4" /></div>
                    <div className="flex-1 min-w-0">
                      <p className="text-sm font-medium truncate">{r.name}</p>
                      <p className="text-[11px] text-muted-foreground">{r.count} charges near {formatCurrency(r.avg, currency)}</p>
                    </div>
                    <p className="text-sm font-medium tabular-nums">{formatCurrency(r.avg, currency)}</p>
                  </div>
                ))}
                <p className="text-[11px] text-muted-foreground">Detected from repeated, stable-amount charges — cancel what you no longer use.</p>
              </GlassCard>
            </>
          )}
        </>
      )}
    </div>
  );
}

function Stat({ label, value, icon: Icon, tone = "text-foreground" }: { label: string; value: string; icon?: any; tone?: string }) {
  return (
    <GlassCard className="py-4">
      <p className="text-[10px] uppercase tracking-widest text-muted-foreground flex items-center gap-1">
        {Icon && <Icon className="size-3" />} {label}
      </p>
      <p className={`text-lg font-semibold tabular-nums mt-1 ${tone}`}>{value}</p>
    </GlassCard>
  );
}
