import { createFileRoute } from "@tanstack/react-router";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useServerFn } from "@tanstack/react-start";
import { UpgradeDialog, type UpgradeReason } from "@/components/UpgradeDialog";
import { parseLimitError } from "@/lib/plans";
import { useMemo, useState } from "react";
import { supabase } from "@/integrations/supabase/client";
import { askDecision, runSimulation, recordDecisionOutcome } from "@/lib/ai.functions";
import { GlassCard, SectionLabel } from "@/components/GlassCard";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { toast } from "sonner";
import {
  Loader2, Sparkles, Zap, TrendingUp, ShieldAlert, AlertTriangle, ThumbsUp, ThumbsDown,
  Car, Home, Landmark, CreditCard, PiggyBank, Flag, Clock, ArrowRight, Wallet,
  ChevronDown, BookOpen,
} from "lucide-react";
import { LineChart, Line, BarChart, Bar, ResponsiveContainer, YAxis, XAxis, Tooltip, Legend } from "recharts";
import { formatCompact, formatCurrency } from "@/lib/format";
import { DisclaimerNote } from "@/components/legal/DisclaimerNote";
import { ListenButton } from "@/components/ListenButton";

export const Route = createFileRoute("/_authenticated/decide")({
  head: () => ({
    meta: [
      { title: "Decide & Simulate — PRUDENTIA" },
      { name: "description", content: "Ask PRUDENTIA any financial decision, simulate cars, homes, loans and debt payoff, and see your money timeline." },
      { property: "og:title", content: "Decide & Simulate — PRUDENTIA" },
      { property: "og:description", content: "Decision engine, scenario simulator and financial timeline." },
      { property: "og:type", content: "website" },
      { name: "twitter:card", content: "summary_large_image" },
    ],
  }),
  component: DecidePage,
});

function DecidePage() {
  return (
    <div className="px-4 pt-8 space-y-5">
      <header className="px-1">
        <p className="text-[11px] text-muted-foreground uppercase tracking-widest">Intelligence</p>
        <h1 className="text-2xl font-semibold">Decide & simulate</h1>
      </header>

      <Tabs defaultValue="decide">
        <TabsList className="grid grid-cols-3 w-full bg-white/5">
          <TabsTrigger value="decide">Decide</TabsTrigger>
          <TabsTrigger value="sim">Simulate</TabsTrigger>
          <TabsTrigger value="timeline">Timeline</TabsTrigger>
        </TabsList>
        <TabsContent value="decide" className="mt-4"><DecisionPanel /></TabsContent>
        <TabsContent value="sim" className="mt-4"><SimulatorPanel /></TabsContent>
        <TabsContent value="timeline" className="mt-4"><TimelinePanel /></TabsContent>
      </Tabs>

      <DisclaimerNote className="px-1 pt-2" />
    </div>
  );
}

/** Currency from the user's profile — the fallback wherever stored data predates it. */
function useProfileCurrency() {
  const { user } = Route.useRouteContext();
  const q = useQuery({
    queryKey: ["profile-currency", user.id],
    queryFn: async () =>
      (await supabase.from("profiles").select("currency").eq("id", user.id).maybeSingle()).data?.currency ?? null,
    staleTime: 5 * 60_000,
  });
  return (q.data as string | null | undefined) ?? null;
}

/* ------------------------------- decisions ------------------------------- */

function DecisionPanel() {
  const { user } = Route.useRouteContext();
  const qc = useQueryClient();
  const askFn = useServerFn(askDecision);
  const [upgrade, setUpgrade] = useState<UpgradeReason>(null);
  const [q, setQ] = useState("");
  const [extra, setExtra] = useState("");
  const [loading, setLoading] = useState(false);

  const decisionsQ = useQuery({
    queryKey: ["decisions", user.id],
    queryFn: async () => (await supabase.from("decisions").select("*").eq("user_id", user.id).order("created_at", { ascending: false }).limit(20)).data ?? [],
  });

  async function ask() {
    if (q.trim().length < 4) return;
    setLoading(true);
    try {
      await askFn({ data: { question: q.trim(), context: extra.trim() || undefined } });
      setQ("");
      setExtra("");
      qc.invalidateQueries({ queryKey: ["decisions", user.id] });
    } catch (e: any) {
      const limit = parseLimitError(e?.message);
      if (limit) setUpgrade(limit);
      else toast.error(e.message ?? "Something went wrong");
    } finally { setLoading(false); }
  }

  const suggestions = ["Should I buy a $1200 laptop?", "Should I take a $20k car loan?", "Should I move to a $2500/mo apartment?", "Should I switch jobs for +$15k?"];

  return (
    <div className="space-y-4">
      <UpgradeDialog reason={upgrade} onClose={() => setUpgrade(null)} />
      <GlassCard>
        <div className="flex items-center gap-2 text-electric">
          <Sparkles className="size-4" />
          <span className="text-[11px] font-semibold uppercase tracking-widest">Ask PRUDENTIA</span>
        </div>
        <Textarea value={q} onChange={(e) => setQ(e.target.value)} placeholder="Should I…" className="mt-3 bg-white/5 border-white/10 min-h-[92px] rounded-2xl" />
        <Input value={extra} onChange={(e) => setExtra(e.target.value)} placeholder="Optional context (timing, constraints…)" className="mt-2" />
        <div className="flex flex-wrap gap-2 mt-3">
          {suggestions.map((s) => <button key={s} onClick={() => setQ(s)} className="text-[11px] rounded-full px-3 py-1.5 bg-white/5 hover:bg-white/10 text-muted-foreground">{s}</button>)}
        </div>
        <Button disabled={loading} onClick={ask} className="w-full mt-4 h-11 rounded-full bg-gradient-to-r from-electric to-purple text-primary-foreground glow-electric">
          {loading ? <Loader2 className="size-4 animate-spin" /> : "Get recommendation"}
        </Button>
      </GlassCard>

      <SectionLabel>Recent decisions</SectionLabel>
      {(decisionsQ.data ?? []).length === 0 && <GlassCard className="text-center text-sm text-muted-foreground py-8">Your decisions will appear here.</GlassCard>}
      {(decisionsQ.data ?? []).map((d: any) => <DecisionCard key={d.id} d={d} />)}
    </div>
  );
}

function Meter({ label, value, tone = "electric" }: { label: string; value: number; tone?: string }) {
  return (
    <div>
      <div className="flex items-center justify-between text-[10px] uppercase tracking-widest text-muted-foreground">
        <span>{label}</span><span>{Math.round(value)}%</span>
      </div>
      <div className="h-1.5 rounded-full bg-white/10 mt-1.5 overflow-hidden">
        <div
          className={`h-full rounded-full ${tone === "success" ? "bg-success" : "bg-gradient-to-r from-electric to-purple"}`}
          style={{ width: `${Math.max(0, Math.min(100, value))}%`, transition: "width 700ms ease" }}
        />
      </div>
    </div>
  );
}

const ACTION_TONE: Record<string, string> = {
  BUY: "text-success", WAIT: "text-warning", SPLIT: "text-electric", DONT: "text-destructive",
};

function ScoreDial({ score, action }: { score: number; action: string }) {
  const tone = ACTION_TONE[action] ?? "text-electric";
  return (
    <div className="text-right shrink-0">
      <p className={`text-3xl font-semibold leading-none ${tone}`}>{score}</p>
      <p className="text-[10px] uppercase tracking-widest text-muted-foreground mt-1">Prudence score</p>
      <p className={`text-xs font-semibold uppercase mt-1 ${tone}`}>{action}</p>
    </div>
  );
}

function DecisionCard({ d }: { d: any }) {
  const qc = useQueryClient();
  const recordFn = useServerFn(recordDecisionOutcome);
  const [openWhy, setOpenWhy] = useState(false);
  const [openScenarios, setOpenScenarios] = useState(false);
  const [choice, setChoice] = useState("");
  const [outcome, setOutcome] = useState("");
  const [saving, setSaving] = useState(false);

  const profileCurrency = useProfileCurrency();
  const a = (d.analysis ?? {}) as any;
  const cur = a.currency ?? profileCurrency ?? "USD";
  const components = (d.components ?? []) as any[];
  const scenarios = (d.scenarios ?? []) as any[];
  const assumptions = (d.assumptions ?? []) as string[];
  const action = d.action ?? (d.verdict === "yes" ? "BUY" : d.verdict === "no" ? "DONT" : "WAIT");
  const score = Number(d.score ?? d.confidence ?? 0);

  const spoken = [
    `You asked: ${d.question}.`,
    `Prudence score ${Math.round(score)} out of 100. The verdict is ${action}.`,
    a.headline ?? "",
    d.recommendation,
    (d.pros ?? []).length ? `Pros. ${(d.pros ?? []).join(". ")}.` : "",
    (d.cons ?? []).length ? `Cons. ${(d.cons ?? []).join(". ")}.` : "",
    a.changes_the_answer ? `What would change this. ${a.changes_the_answer}` : "",
    "This is educational guidance, not financial advice.",
  ].filter(Boolean).join(" ");

  async function saveJournal() {
    if (!choice.trim()) return;
    setSaving(true);
    try {
      await recordFn({ data: { id: d.id, chosen_option: choice.trim(), actual_outcome: outcome.trim() || undefined } });
      toast.success("Saved to your decision journal");
      qc.invalidateQueries({ queryKey: ["decisions"] });
    } catch (e: any) {
      toast.error(e?.message ?? "Could not save");
    } finally { setSaving(false); }
  }

  return (
    <GlassCard>
      <div className="flex items-start justify-between gap-3">
        <div className="min-w-0">
          <p className="text-[10px] uppercase tracking-widest text-muted-foreground">Question</p>
          <p className="text-sm font-medium mt-1">{d.question}</p>
        </div>
        <ScoreDial score={Math.round(score)} action={action} />
      </div>

      {a.headline && <p className="text-sm text-foreground mt-3 leading-relaxed font-medium">{a.headline}</p>}
      <p className="text-sm text-foreground/90 mt-2 leading-relaxed">{d.recommendation}</p>

      {(a.cash_flow_impact_monthly !== undefined || a.upfront_cost !== undefined) && (
        <div className="grid grid-cols-3 gap-2 mt-4">
          <Stat label="Monthly" value={formatCurrency(Number(a.cash_flow_impact_monthly ?? 0), cur)} tone={Number(a.cash_flow_impact_monthly ?? 0) < 0 ? "down" : "up"} />
          <Stat label="Upfront" value={formatCompact(Number(a.upfront_cost ?? 0), cur)} />
          <Stat label="Break-even" value={a.break_even_months == null ? "—" : `${a.break_even_months} mo`} />
        </div>
      )}

      {/* Why */}
      {components.length > 0 && (
        <div className="mt-4">
          <button onClick={() => setOpenWhy((v) => !v)} className="w-full flex items-center justify-between text-[10px] uppercase tracking-widest text-muted-foreground">
            <span>Why this score</span>
            <ChevronDown className={`size-3.5 transition-transform ${openWhy ? "rotate-180" : ""}`} />
          </button>
          {openWhy && (
            <div className="mt-3 space-y-3">
              {components.map((c: any) => (
                <div key={c.key}>
                  <Meter label={`${c.label} · ${Math.round(c.weight * 100)}% weight`} value={Number(c.score)} />
                  <p className="text-[11px] text-muted-foreground mt-1">{c.detail}</p>
                </div>
              ))}
              {assumptions.length > 0 && (
                <div className="rounded-2xl bg-white/5 p-3">
                  <p className="text-[10px] uppercase tracking-widest text-muted-foreground">Assumptions</p>
                  <ul className="mt-1 space-y-1">{assumptions.map((s, i) => <li key={i} className="text-[11px] text-muted-foreground">· {s}</li>)}</ul>
                </div>
              )}
              {a.changes_the_answer && (
                <p className="text-[11px] text-foreground/85"><span className="text-muted-foreground">What would change this — </span>{a.changes_the_answer}</p>
              )}
            </div>
          )}
        </div>
      )}

      {/* Scenarios */}
      {scenarios.length > 0 && (
        <div className="mt-4">
          <button onClick={() => setOpenScenarios((v) => !v)} className="w-full flex items-center justify-between text-[10px] uppercase tracking-widest text-muted-foreground">
            <span>Compare your options</span>
            <ChevronDown className={`size-3.5 transition-transform ${openScenarios ? "rotate-180" : ""}`} />
          </button>
          {openScenarios && (
            <>
              <div className="h-32 mt-3">
                <ResponsiveContainer>
                  <BarChart data={scenarios.map((s: any) => ({ name: s.label, value: s.netWorth12m }))} margin={{ top: 4, right: 4, bottom: 0, left: 0 }}>
                    <XAxis dataKey="name" tick={{ fontSize: 9, fill: "var(--muted-foreground)" }} interval={0} />
                    <YAxis hide domain={["auto", "auto"]} />
                    <Tooltip
                      formatter={(v: any) => [formatCompact(Number(v), cur), "Net worth in 12 months"]}
                      contentStyle={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 12 }}
                    />
                    <Bar dataKey="value" fill="var(--electric)" radius={6} />
                  </BarChart>
                </ResponsiveContainer>
              </div>
              <div className="mt-3 space-y-2">
                {scenarios.map((s: any) => (
                  <div key={s.id} className={`rounded-2xl p-3 ${a.better_option === s.label ? "bg-electric/10 ring-1 ring-electric/30" : "bg-white/5"}`}>
                    <div className="flex items-center justify-between">
                      <p className="text-xs font-medium">{s.label}</p>
                      <p className="text-xs text-electric">{formatCompact(Number(s.netWorth12m), cur)} in 12 mo</p>
                    </div>
                    <p className="text-[11px] text-muted-foreground mt-1">
                      Cash after {formatCompact(Number(s.cashAfter), cur)} · reserve {s.reserveMonthsAfter} mo · surplus {formatCurrency(Number(s.surplusAfter), cur)}/mo
                      {Number(s.goalDelayWeeks) > 0 ? ` · goal +${s.goalDelayWeeks} wks` : ""}
                    </p>
                  </div>
                ))}
              </div>
            </>
          )}
        </div>
      )}

      <div className="grid grid-cols-2 gap-3 mt-4">
        <div>
          <p className="text-[10px] uppercase tracking-widest text-success">Pros</p>
          <ul className="mt-1 space-y-1">{(d.pros ?? []).map((p: string, i: number) => <li key={i} className="text-[11px] text-muted-foreground">· {p}</li>)}</ul>
        </div>
        <div>
          <p className="text-[10px] uppercase tracking-widest text-destructive">Cons</p>
          <ul className="mt-1 space-y-1">{(d.cons ?? []).map((p: string, i: number) => <li key={i} className="text-[11px] text-muted-foreground">· {p}</li>)}</ul>
        </div>
      </div>

      {Array.isArray(a.alternatives) && a.alternatives.length > 0 && (
        <div className="mt-4">
          <p className="text-[10px] uppercase tracking-widest text-muted-foreground">Alternatives</p>
          <ul className="mt-1.5 space-y-1.5">
            {a.alternatives.map((alt: string, i: number) => (
              <li key={i} className="flex gap-2 text-[11px] text-foreground/85"><ArrowRight className="size-3 mt-0.5 text-electric shrink-0" />{alt}</li>
            ))}
          </ul>
        </div>
      )}

      {Array.isArray(a.watch_outs) && a.watch_outs.length > 0 && (
        <div className="mt-4 rounded-2xl bg-warning/10 p-3">
          <p className="text-[10px] uppercase tracking-widest text-warning">Watch outs</p>
          <ul className="mt-1 space-y-1">{a.watch_outs.map((w: string, i: number) => <li key={i} className="text-[11px] text-muted-foreground">· {w}</li>)}</ul>
        </div>
      )}

      {(d.opportunity_cost || d.long_term_impact) && (
        <div className="mt-4 space-y-2">
          {d.opportunity_cost && <p className="text-[11px] text-muted-foreground"><span className="text-foreground/80">Opportunity cost — </span>{d.opportunity_cost}</p>}
          {d.long_term_impact && <p className="text-[11px] text-muted-foreground"><span className="text-foreground/80">Long term — </span>{d.long_term_impact}</p>}
        </div>
      )}

      {/* Journal */}
      <div className="mt-4 rounded-2xl bg-white/5 p-3">
        <div className="flex items-center gap-2 text-[10px] uppercase tracking-widest text-muted-foreground">
          <BookOpen className="size-3" /> Decision journal
        </div>
        {d.status === "recorded" ? (
          <div className="mt-2">
            <p className="text-[11px] text-foreground/85">You chose: <span className="font-medium">{d.chosen_option}</span></p>
            {d.actual_outcome && <p className="text-[11px] text-muted-foreground mt-1">{d.actual_outcome}</p>}
            {d.predicted_impact?.net_worth_12m != null && (
              <p className="text-[11px] text-muted-foreground mt-1">
                Prudentia predicted {formatCompact(Number(d.predicted_impact.net_worth_12m), cur)} in 12 months if you went ahead.
              </p>
            )}
          </div>
        ) : (
          <div className="mt-2 space-y-2">
            <Input value={choice} onChange={(e) => setChoice(e.target.value)} placeholder="What did you actually decide?" className="h-9 text-xs" />
            <Input value={outcome} onChange={(e) => setOutcome(e.target.value)} placeholder="How did it turn out? (optional)" className="h-9 text-xs" />
            <Button size="sm" variant="secondary" disabled={saving || !choice.trim()} onClick={saveJournal} className="rounded-full h-8 text-xs">
              {saving ? <Loader2 className="size-3.5 animate-spin" /> : "Record my choice"}
            </Button>
          </div>
        )}
      </div>

      <div className="flex items-center justify-between gap-3 mt-4 text-[10px] text-muted-foreground uppercase tracking-widest">
        <span className="flex items-center gap-1"><ShieldAlert className="size-3" /> {d.risk_level} risk</span>
        <ListenButton label="Listen" text={spoken} className="normal-case tracking-normal" />
      </div>

    </GlassCard>
  );
}


function Stat({ label, value, tone }: { label: string; value: string; tone?: "up" | "down" }) {
  return (
    <div className="rounded-2xl bg-white/5 p-2.5">
      <p className="text-[9px] uppercase tracking-widest text-muted-foreground">{label}</p>
      <p className={`text-sm font-semibold mt-0.5 ${tone === "down" ? "text-destructive" : tone === "up" ? "text-success" : "text-foreground"}`}>{value}</p>
    </div>
  );
}

/* ------------------------------- simulator ------------------------------- */

type FieldDef = { key: string; label: string; help?: string };

const SCENARIOS: Array<{ v: string; name: string; icon: any; fields: FieldDef[]; defaults: Record<string, string> }> = [
  {
    v: "investment", name: "Invest", icon: TrendingUp,
    fields: [],
    defaults: {},
  },
  {
    v: "car", name: "Buy a car", icon: Car,
    fields: [
      { key: "price", label: "Car price" },
      { key: "downPayment", label: "Down payment" },
      { key: "apr", label: "Loan APR", help: "0.07 = 7%" },
      { key: "loanYears", label: "Loan years" },
      { key: "insurance", label: "Insurance / mo" },
      { key: "fuelMaintenance", label: "Fuel + upkeep / mo" },
    ],
    defaults: { price: "25000", downPayment: "5000", apr: "0.07", loanYears: "5", insurance: "120", fuelMaintenance: "180" },
  },
  {
    v: "house", name: "Buy a home", icon: Home,
    fields: [
      { key: "price", label: "Home price" },
      { key: "downPayment", label: "Down payment" },
      { key: "apr", label: "Mortgage APR", help: "0.065 = 6.5%" },
      { key: "loanYears", label: "Term (years)" },
      { key: "appreciation", label: "Appreciation", help: "0.03 = 3%/yr" },
      { key: "rentSaved", label: "Rent saved / mo" },
    ],
    defaults: { price: "350000", downPayment: "70000", apr: "0.065", loanYears: "30", appreciation: "0.03", rentSaved: "1800" },
  },
  {
    v: "loan", name: "Take a loan", icon: Landmark,
    fields: [
      { key: "amount", label: "Loan amount" },
      { key: "apr", label: "APR", help: "0.09 = 9%" },
      { key: "loanYears", label: "Term (years)" },
    ],
    defaults: { amount: "15000", apr: "0.09", loanYears: "3" },
  },
  {
    v: "debt", name: "Pay off debt", icon: CreditCard,
    fields: [
      { key: "balance", label: "Balance" },
      { key: "apr", label: "APR", help: "0.22 = 22%" },
      { key: "monthlyPayment", label: "Monthly payment" },
    ],
    defaults: { balance: "8000", apr: "0.22", monthlyPayment: "400" },
  },
  {
    v: "purchase", name: "Big purchase", icon: Zap,
    fields: [
      { key: "oneTimeCost", label: "One-time cost" },
      { key: "recurringCost", label: "Recurring / mo" },
    ],
    defaults: { oneTimeCost: "1200", recurringCost: "0" },
  },
  {
    v: "salary", name: "Salary change", icon: Sparkles,
    fields: [{ key: "salaryDelta", label: "Salary delta (yr)" }],
    defaults: { salaryDelta: "15000" },
  },
  {
    v: "retirement", name: "Retirement", icon: PiggyBank,
    fields: [],
    defaults: {},
  },
];

const BASE_DEFAULTS = { monthlySavings: "500", returnRate: "0.07", inflation: "0.03" };

function SimulatorPanel() {
  const { user } = Route.useRouteContext();
  const qc = useQueryClient();
  const simFn = useServerFn(runSimulation);
  const [upgrade, setUpgrade] = useState<UpgradeReason>(null);
  const [kind, setKind] = useState("car");
  const [inputs, setInputs] = useState<Record<string, string>>({ ...BASE_DEFAULTS, ...SCENARIOS[1].defaults });
  const [horizon, setHorizon] = useState(60);
  const [loading, setLoading] = useState(false);

  const scenario = SCENARIOS.find((s) => s.v === kind)!;

  const simsQ = useQuery({
    queryKey: ["sims", user.id],
    queryFn: async () => (await supabase.from("simulations").select("*").eq("user_id", user.id).order("created_at", { ascending: false }).limit(10)).data ?? [],
  });

  function pick(v: string) {
    const s = SCENARIOS.find((x) => x.v === v)!;
    setKind(v);
    setInputs({ ...BASE_DEFAULTS, ...s.defaults });
  }

  async function run() {
    setLoading(true);
    try {
      const parsed = Object.fromEntries(Object.entries(inputs).map(([k, v]) => [k, Number(v)]));
      await simFn({ data: { kind, name: scenario.name, inputs: parsed, months: horizon } });
      qc.invalidateQueries({ queryKey: ["sims", user.id] });
      toast.success("Simulation ready");
    } catch (e: any) {
      const limit = parseLimitError(e?.message);
      if (limit) setUpgrade(limit);
      else toast.error(e.message ?? "Sim failed");
    }
    finally { setLoading(false); }
  }

  const horizons = [
    { m: 24, l: "2Y" }, { m: 60, l: "5Y" }, { m: 120, l: "10Y" }, { m: 240, l: "20Y" },
  ];

  return (
    <div className="space-y-4">
      <UpgradeDialog reason={upgrade} onClose={() => setUpgrade(null)} />
      <GlassCard>

        <SectionLabel>Scenario</SectionLabel>
        <div className="grid grid-cols-4 gap-2 mt-2">
          {SCENARIOS.map((k) => {
            const I = k.icon;
            return (
              <button key={k.v} onClick={() => pick(k.v)} className={`glass rounded-2xl p-2.5 flex flex-col items-center gap-1.5 transition-all ${kind === k.v ? "ring-2 ring-electric" : "opacity-80 hover:opacity-100"}`}>
                <I className="size-4 text-electric" />
                <span className="text-[10px] text-foreground/90 text-center leading-tight">{k.name}</span>
              </button>
            );
          })}
        </div>

        <div className="grid grid-cols-2 gap-3 mt-4">
          <Field label="Monthly savings" value={inputs.monthlySavings ?? ""} onChange={(v) => setInputs({ ...inputs, monthlySavings: v })} />
          <Field label="Return rate" value={inputs.returnRate ?? ""} onChange={(v) => setInputs({ ...inputs, returnRate: v })} help="0.07 = 7%" />
          <Field label="Inflation" value={inputs.inflation ?? ""} onChange={(v) => setInputs({ ...inputs, inflation: v })} help="0.03 = 3%" />
          {scenario.fields.map((f) => (
            <Field key={f.key} label={f.label} help={f.help} value={inputs[f.key] ?? ""} onChange={(v) => setInputs({ ...inputs, [f.key]: v })} />
          ))}
        </div>

        <div className="flex items-center gap-1.5 mt-4">
          {horizons.map((h) => (
            <button key={h.m} onClick={() => setHorizon(h.m)} className={`text-[11px] rounded-full px-3 py-1.5 ${horizon === h.m ? "bg-electric/20 text-electric" : "bg-white/5 text-muted-foreground"}`}>{h.l}</button>
          ))}
        </div>

        <Button disabled={loading} onClick={run} className="w-full mt-4 h-11 rounded-full bg-gradient-to-r from-electric to-purple text-primary-foreground glow-electric">
          {loading ? <Loader2 className="size-4 animate-spin" /> : "Run simulation"}
        </Button>
      </GlassCard>

      <SectionLabel>Recent simulations</SectionLabel>
      {(simsQ.data ?? []).map((s: any) => <SimCard key={s.id} s={s} />)}
      {(simsQ.data ?? []).length === 0 && <GlassCard className="text-center text-sm text-muted-foreground py-8">Run your first scenario above.</GlassCard>}
    </div>
  );
}

function Field({ label, value, onChange, help }: { label: string; value: string; onChange: (v: string) => void; help?: string }) {
  return (
    <div>
      <Label className="text-[11px] text-muted-foreground">{label}</Label>
      <Input value={value} onChange={(e) => onChange(e.target.value)} className="mt-1" inputMode="decimal" />
      {help && <p className="text-[10px] text-muted-foreground mt-1">{help}</p>}
    </div>
  );
}

function SimCard({ s }: { s: any }) {
  const points = (s.outputs?.points ?? []) as Array<{ month: number; value: number }>;
  const baseline = (s.baseline?.points ?? []) as Array<{ month: number; value: number }>;
  const m = (s.outputs?.metrics ?? {}) as any;
  const profileCurrency = useProfileCurrency();
  const cur = m.currency ?? profileCurrency ?? "USD";
  const merged = points.map((p, i) => ({ month: p.month, scenario: p.value, baseline: baseline[i]?.value ?? null }));
  const final = points.at(-1)?.value ?? 0;
  const delta = Number(m.delta_vs_baseline ?? 0);

  return (
    <GlassCard>
      <div className="flex items-center justify-between">
        <div>
          <p className="text-sm font-medium">{s.name}</p>
          <p className="text-[10px] uppercase tracking-widest text-muted-foreground mt-0.5">{m.months ?? points.length} month projection</p>
        </div>
        <div className="text-right">
          <p className="text-sm text-electric font-semibold">{formatCompact(final, cur)}</p>
          {baseline.length > 0 && (
            <p className={`text-[10px] ${delta >= 0 ? "text-success" : "text-destructive"}`}>
              {delta >= 0 ? "+" : ""}{formatCompact(delta, cur)} vs baseline
            </p>
          )}
        </div>
      </div>

      <div className="h-28 mt-3">
        <ResponsiveContainer>
          <LineChart data={merged} margin={{ top: 4, right: 4, bottom: 0, left: 0 }}>
            <XAxis dataKey="month" hide />
            <YAxis hide domain={["auto", "auto"]} />
            <Tooltip
              formatter={(v: any, n: any) => [formatCompact(Number(v), cur), n === "scenario" ? "Scenario" : "Do nothing"]}
              labelFormatter={(l: any) => `Month ${l}`}
              contentStyle={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 12 }}
            />
            {baseline.length > 0 && <Legend iconType="plainline" wrapperStyle={{ fontSize: 10, opacity: 0.7 }} formatter={(v) => (v === "scenario" ? "Scenario" : "Do nothing")} />}
            <Line type="monotone" dataKey="scenario" stroke="var(--electric)" strokeWidth={2} dot={false} isAnimationActive />
            {baseline.length > 0 && <Line type="monotone" dataKey="baseline" stroke="var(--muted-foreground)" strokeDasharray="4 4" strokeWidth={1.5} dot={false} isAnimationActive />}
          </LineChart>
        </ResponsiveContainer>
      </div>

      {m.months && (
        <div className="grid grid-cols-3 gap-2 mt-3">
          <Stat label="Upfront" value={formatCompact(Number(m.upfront ?? 0), cur)} />
          <Stat label="Monthly" value={formatCurrency(Number(m.monthly_impact ?? 0), cur)} tone={Number(m.monthly_impact ?? 0) < 0 ? "down" : "up"} />
          <Stat label="Payoff" value={m.payoff_months ? `${m.payoff_months} mo` : "—"} />
        </div>
      )}

      {s.summary && (
        <>
          <p className="text-xs text-muted-foreground mt-3 leading-relaxed">{s.summary}</p>
          <ListenButton label="Listen" className="mt-3" text={`${s.name} simulation. ${s.summary}`} />
        </>
      )}
    </GlassCard>
  );
}

/* -------------------------------- timeline ------------------------------- */

type TimelineItem = {
  id: string;
  monthsAway: number;
  title: string;
  detail?: string;
  kind: "goal" | "decision" | "simulation";
};

function TimelinePanel() {
  const { user } = Route.useRouteContext();
  const profileCurrency = useProfileCurrency();

  const goalsQ = useQuery({
    queryKey: ["timeline-goals", user.id],
    queryFn: async () => (await supabase.from("goals").select("*").eq("user_id", user.id)).data ?? [],
  });
  const decisionsQ = useQuery({
    queryKey: ["timeline-decisions", user.id],
    queryFn: async () => (await supabase.from("decisions").select("*").eq("user_id", user.id).order("created_at", { ascending: false }).limit(5)).data ?? [],
  });
  const simsQ = useQuery({
    queryKey: ["timeline-sims", user.id],
    queryFn: async () => (await supabase.from("simulations").select("*").eq("user_id", user.id).order("created_at", { ascending: false }).limit(5)).data ?? [],
  });

  const items = useMemo<TimelineItem[]>(() => {
    const out: TimelineItem[] = [];
    const now = new Date();

    for (const g of (goalsQ.data ?? []) as any[]) {
      if (!g.target_date) continue;
      const d = new Date(g.target_date);
      const monthsAway = Math.max(0, Math.round((d.getTime() - now.getTime()) / (30.44 * 86_400_000)));
      const progress = Number(g.target_amount) > 0 ? (Number(g.current_amount) / Number(g.target_amount)) * 100 : 0;
      out.push({
        id: `goal-${g.id}`,
        monthsAway,
        title: g.name,
        detail: `${Math.round(progress)}% funded · target ${formatCompact(Number(g.target_amount), profileCurrency ?? "USD")} by ${d.toLocaleDateString(undefined, { month: "short", year: "numeric" })}`,
        kind: "goal",
      });
    }

    for (const dec of (decisionsQ.data ?? []) as any[]) {
      const ms = (dec.analysis?.milestones ?? []) as Array<{ month: number; label: string }>;
      for (const m of ms) {
        out.push({
          id: `dec-${dec.id}-${m.month}`,
          monthsAway: Number(m.month) || 0,
          title: m.label,
          detail: dec.question,
          kind: "decision",
        });
      }
    }

    for (const s of (simsQ.data ?? []) as any[]) {
      const payoff = Number(s.outputs?.metrics?.payoff_months ?? 0);
      if (payoff > 0) {
        out.push({
          id: `sim-${s.id}`,
          monthsAway: payoff,
          title: `${s.name} fully paid off`,
          detail: `Projected balance ${formatCompact(Number(s.outputs?.points?.at(-1)?.value ?? 0), s.outputs?.metrics?.currency ?? profileCurrency ?? "USD")}`,
          kind: "simulation",
        });
      }
    }

    return out.sort((a, b) => a.monthsAway - b.monthsAway).slice(0, 20);
  }, [goalsQ.data, decisionsQ.data, simsQ.data, profileCurrency]);

  const loading = goalsQ.isLoading || decisionsQ.isLoading || simsQ.isLoading;

  function when(monthsAway: number) {
    if (monthsAway <= 0) return "Now";
    if (monthsAway < 12) return `In ${monthsAway} mo`;
    const y = Math.floor(monthsAway / 12);
    const m = monthsAway % 12;
    return m ? `In ${y}y ${m}mo` : `In ${y}y`;
  }

  const iconFor = { goal: Flag, decision: Sparkles, simulation: Wallet } as const;

  return (
    <div className="space-y-4">
      <GlassCard>
        <div className="flex items-center gap-2 text-electric">
          <Clock className="size-4" />
          <span className="text-[11px] font-semibold uppercase tracking-widest">Money timeline</span>
        </div>
        <p className="text-xs text-muted-foreground mt-2 leading-relaxed">
          Every goal deadline, decision milestone and payoff date on one line, ordered by how soon it lands.
        </p>
      </GlassCard>

      {loading && <GlassCard className="text-center text-sm text-muted-foreground py-8"><Loader2 className="size-4 animate-spin mx-auto" /></GlassCard>}

      {!loading && items.length === 0 && (
        <GlassCard className="text-center text-sm text-muted-foreground py-8">
          Add a goal with a target date, or run a decision, and your timeline builds itself.
        </GlassCard>
      )}

      {!loading && items.length > 0 && (
        <GlassCard>
          <ol className="border-l border-white/10 pl-5 space-y-5">
            {items.map((it) => {
              const I = iconFor[it.kind];
              return (
                <li key={it.id} className="relative">
                  <span className="absolute -left-[27px] top-0.5 size-4 rounded-full bg-surface flex items-center justify-center ring-1 ring-white/10">
                    <I className="size-2.5 text-electric" />
                  </span>
                  <p className="text-[10px] uppercase tracking-widest text-muted-foreground">{when(it.monthsAway)}</p>
                  <p className="text-sm font-medium mt-0.5">{it.title}</p>
                  {it.detail && <p className="text-[11px] text-muted-foreground mt-0.5">{it.detail}</p>}
                </li>
              );
            })}
          </ol>
        </GlassCard>
      )}
    </div>
  );
}
