import { createFileRoute } from "@tanstack/react-router";
import { Card } from "@/components/ui/card";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis, CartesianGrid, Area, AreaChart } from "recharts";
import { fmtUsd } from "@/lib/mock-data";
import { Download, Table as TableIcon, LineChart as LineIcon, RefreshCcw, Inbox, FlaskConical, Zap, Layers } from "lucide-react";
import { SortTh } from "@/components/sortable-th";
import { useSort, byNumber, byString } from "@/lib/use-sort";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { useId, useMemo, useState, type KeyboardEvent } from "react";
import { useQuery } from "@tanstack/react-query";
import { backendApi, type DeltaPosition } from "@/lib/backend-client";
import { useBackendStream } from "@/hooks/use-backend-stream";


export const Route = createFileRoute("/_app/reports")({
  head: () => ({
    meta: [
      { title: "Performance & Balance Sheet" },
      { name: "description", content: "Daily, weekly, and monthly NAV growth with exportable balance sheet." },
    ],
  }),
  component: Reports,
});

type Point = { d: string; nav: number; pnl: number; trades: number };

function bucketPositions(positions: DeltaPosition[], startingBalance: number, bucket: "day" | "week" | "month"): Point[] {
  if (!positions.length) return [];
  const keyOf = (iso: string) => {
    const d = new Date(iso);
    if (bucket === "day") return d.toISOString().slice(0, 10);
    if (bucket === "week") {
      const first = new Date(d);
      first.setUTCDate(d.getUTCDate() - d.getUTCDay());
      return `W ${first.toISOString().slice(0, 10)}`;
    }
    return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}`;
  };
  const sorted = [...positions].sort(
    (a, b) => new Date(a.opened_at).getTime() - new Date(b.opened_at).getTime(),
  );
  const buckets = new Map<string, { pnl: number; trades: number }>();
  for (const p of sorted) {
    const k = keyOf(p.opened_at);
    const cur = buckets.get(k) ?? { pnl: 0, trades: 0 };
    cur.pnl += Number(p.pnl) || 0;
    cur.trades += 1;
    buckets.set(k, cur);
  }
  let running = startingBalance;
  const out: Point[] = [];
  for (const [k, v] of buckets) {
    running += v.pnl;
    out.push({ d: k, nav: running, pnl: v.pnl, trades: v.trades });
  }
  return out;
}

function Reports() {
  const [mode, setMode] = useState<"all" | "paper" | "live">("all");
  const stream = useBackendStream();
  const positionsQ = useQuery({
    queryKey: ["reports", "positions"],
    queryFn: () => backendApi.listPositions(),
    staleTime: 30_000,
    retry: 1,
  });
  const accountQ = useQuery({
    queryKey: ["reports", "account"],
    queryFn: () => backendApi.testDeltaCredentials(),
    staleTime: 30_000,
    retry: 1,
  });

  // Prefer live streamed positions; fall back to REST query result.
  const allPositions: DeltaPosition[] =
    stream.positions.length > 0 ? stream.positions : (positionsQ.data ?? []);
  const paperPositions = useMemo(() => allPositions.filter((p) => (p.execution_mode ?? "paper") === "paper"), [allPositions]);
  const livePositions = useMemo(() => allPositions.filter((p) => p.execution_mode === "live"), [allPositions]);
  const positions = mode === "paper" ? paperPositions : mode === "live" ? livePositions : allPositions;
  const balance = accountQ.data?.balance ?? 0;


  const stats = useMemo(() => {
    const closed = positions.filter((p) => p.order_status === "FILLED" || p.order_status === "CANCELED");
    const withPnl = positions.filter((p) => typeof p.pnl === "number");
    const wins = withPnl.filter((p) => p.pnl > 0).length;
    const totalTrades = positions.length;
    const winRate = withPnl.length ? (wins / withPnl.length) * 100 : 0;
    const netPnl = withPnl.reduce((s, p) => s + (Number(p.pnl) || 0), 0);
    const avgLev = positions.length
      ? positions.reduce((s, p) => s + (Number(p.leverage) || 1), 0) / positions.length
      : 0;
    return { totalTrades, winRate, netPnl, avgLev, closedCount: closed.length };
  }, [positions]);

  const startingBalance = balance - stats.netPnl;
  const daily = useMemo(() => bucketPositions(positions, startingBalance, "day"), [positions, startingBalance]);
  const weekly = useMemo(() => bucketPositions(positions, startingBalance, "week"), [positions, startingBalance]);
  const monthly = useMemo(() => bucketPositions(positions, startingBalance, "month"), [positions, startingBalance]);

  const loading = (positionsQ.isLoading || accountQ.isLoading) && allPositions.length === 0;
  // A disconnected backend and a fresh account look identical from here; the
  // header already shows the WS/backend status, so we treat "no data" as the
  // canonical empty state and only tweak the copy when the backend is offline.
  const backendDown = !!positionsQ.error && !!accountQ.error && allPositions.length === 0;

  const exportCsv = () => {
    const rows = [["date", "trades", "realized_pnl", "balance"], ...daily.map((d) => [d.d, d.trades, d.pnl.toFixed(2), d.nav.toFixed(2)])];
    const csv = rows.map((r) => r.join(",")).join("\n");
    const blob = new Blob([csv], { type: "text/csv" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `balance-sheet-${new Date().toISOString().slice(0, 10)}.csv`;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div className="space-y-6">
      <Card className="glass flex flex-wrap items-center justify-between gap-3 p-3">
        <div className="flex items-center gap-2">
          <span className="text-[11px] uppercase tracking-widest text-muted-foreground">Execution mode</span>
          <div className="inline-flex rounded-md border border-border/60 p-0.5" role="group" aria-label="Filter by execution mode">
            {([
              { k: "all", label: "All", Icon: Layers },
              { k: "paper", label: "Paper", Icon: FlaskConical },
              { k: "live", label: "Live", Icon: Zap },
            ] as const).map(({ k, label, Icon }) => (
              <button
                key={k}
                type="button"
                onClick={() => setMode(k)}
                aria-pressed={mode === k}
                className={`inline-flex items-center gap-1 rounded px-2.5 py-1 text-xs transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${mode === k ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground"}`}
              >
                <Icon className="h-3 w-3" aria-hidden /> {label}
              </button>
            ))}
          </div>
        </div>
        <div className="flex items-center gap-2 text-xs text-muted-foreground">
          <Badge variant="outline" className="gap-1"><FlaskConical className="h-3 w-3" aria-hidden /> Paper: {paperPositions.length}</Badge>
          <Badge variant="outline" className="gap-1"><Zap className="h-3 w-3" aria-hidden /> Live: {livePositions.length}</Badge>
        </div>
      </Card>


      <div className="grid grid-cols-2 gap-3 md:grid-cols-4">
        <Kpi label="Total Trades" value={loading ? "—" : String(stats.totalTrades)} />
        <Kpi
          label="Win Rate"
          value={loading ? "—" : `${stats.winRate.toFixed(1)}%`}
          tone={stats.winRate >= 50 ? "bull" : stats.winRate > 0 ? "bear" : undefined}
        />
        <Kpi
          label="Net P/L"
          value={loading ? "—" : fmtUsd(stats.netPnl)}
          tone={stats.netPnl > 0 ? "bull" : stats.netPnl < 0 ? "bear" : undefined}
        />
        <Kpi label="Avg Leverage" value={loading ? "—" : `${stats.avgLev.toFixed(1)}x`} />
      </div>

      <Card className="glass p-4">
        <div className="mb-3 flex items-center justify-between">
          <div>
            <h2 className="font-display text-lg font-bold" id="nav-chart-title">Net Asset Value</h2>
            <p className="text-xs text-muted-foreground" id="nav-chart-desc">
              Live equity curve derived from your Delta positions. Use Tab and arrow keys to navigate.
            </p>
          </div>
          <div className="flex gap-2">
            <Button
              variant="outline"
              size="sm"
              className="gap-2"
              onClick={() => { positionsQ.refetch(); accountQ.refetch(); }}
              aria-label="Refresh reports"
            >
              <RefreshCcw className={`h-3.5 w-3.5 ${loading ? "animate-spin" : ""}`} aria-hidden /> Refresh
            </Button>
            <Button
              variant="outline"
              size="sm"
              className="gap-2"
              onClick={exportCsv}
              disabled={!daily.length}
              aria-label="Export balance sheet as CSV"
            >
              <Download className="h-3.5 w-3.5" aria-hidden /> Export CSV
            </Button>
          </div>
        </div>

        {loading ? (
          <div className="h-72 animate-pulse rounded-md bg-muted/30" aria-hidden />
        ) : daily.length === 0 ? (
          <EmptyState
            title={backendDown ? "Waiting for backend" : "No trades yet"}
            body={
              backendDown
                ? "The reports API isn't reachable right now. When the backend reconnects, your NAV curve, KPIs, and balance sheet will populate automatically."
                : "Once trades are executed on your Delta account, your NAV curve will appear here."
            }
          />
        ) : (
          <Tabs defaultValue="daily">
            <TabsList aria-label="Report timeframe">
              <TabsTrigger value="daily">Daily</TabsTrigger>
              <TabsTrigger value="weekly" disabled={!weekly.length}>Weekly</TabsTrigger>
              <TabsTrigger value="monthly" disabled={!monthly.length}>Monthly</TabsTrigger>
            </TabsList>
            <TabsContent value="daily">
              <ChartPanel data={daily} kind="area" label="Daily net asset value" />
            </TabsContent>
            <TabsContent value="weekly">
              <ChartPanel data={weekly} kind="line" label="Weekly net asset value" color="oklch(0.72 0.18 285)" />
            </TabsContent>
            <TabsContent value="monthly">
              <ChartPanel data={monthly} kind="line" label="Monthly net asset value" color="oklch(0.82 0.17 85)" dot />
            </TabsContent>
          </Tabs>
        )}
      </Card>

      <PaperTradeLog positions={paperPositions} loading={loading} />

      <Card className="glass p-4">
        <h2 className="mb-3 font-display text-lg font-bold">Balance Sheet Snapshot</h2>

        {loading ? (
          <div className="h-40 animate-pulse rounded-md bg-muted/30" aria-hidden />
        ) : daily.length === 0 ? (
          <EmptyState title="No entries" body="Balance sheet fills automatically as trades close." />
        ) : (
          <div className="overflow-x-auto">
            <table className="w-full min-w-[560px] text-sm">
              <caption className="sr-only">Recent daily balance sheet entries</caption>
              <thead className="text-left text-[11px] uppercase tracking-wider text-muted-foreground">
                <tr><th scope="col" className="py-2">Date</th><th scope="col">Trades</th><th scope="col">Realized PnL</th><th scope="col">Balance</th></tr>
              </thead>
              <tbody className="num">
                {daily.slice(-8).reverse().map((d) => (
                  <tr key={d.d} className="border-t border-border/60">
                    <th scope="row" className="py-2 text-left font-normal">{d.d}</th>
                    <td>{d.trades}</td>
                    <td className={d.pnl >= 0 ? "text-bull" : "text-bear"}>{fmtUsd(d.pnl)}</td>
                    <td>{fmtUsd(d.nav)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </Card>
    </div>
  );
}

function EmptyState({ title, body }: { title: string; body: string }) {
  return (
    <div className="flex h-56 flex-col items-center justify-center gap-2 rounded-md border border-dashed border-border/60 p-6 text-center">
      <Inbox className="h-6 w-6 text-muted-foreground" aria-hidden />
      <div className="font-medium">{title}</div>
      <p className="max-w-sm text-xs text-muted-foreground">{body}</p>
    </div>
  );
}

function ChartPanel({
  data,
  kind,
  label,
  color = "oklch(0.78 0.17 165)",
  dot = false,
}: {
  data: Point[];
  kind: "area" | "line";
  label: string;
  color?: string;
  dot?: boolean;
}) {
  const [view, setView] = useState<"chart" | "table">("chart");
  const [idx, setIdx] = useState(Math.max(0, data.length - 1));
  const gradId = useId().replace(/:/g, "");
  if (!data.length) {
    return <EmptyState title="No data" body="Not enough trades to render this timeframe yet." />;
  }
  const safeIdx = Math.min(Math.max(0, idx), data.length - 1);
  const min = Math.min(...data.map((p) => p.nav));
  const max = Math.max(...data.map((p) => p.nav));
  const first = data[0].nav;
  const last = data[data.length - 1].nav;
  const change = last - first;
  const changePct = first !== 0 ? (change / first) * 100 : 0;
  const summary = `${label}. ${data.length} points from ${data[0].d} to ${data[data.length - 1].d}. Start ${fmtUsd(first)}, end ${fmtUsd(last)}, change ${changePct.toFixed(2)} percent. Min ${fmtUsd(min)}, max ${fmtUsd(max)}.`;

  const onKey = (e: KeyboardEvent<HTMLDivElement>) => {
    if (e.key === "ArrowRight") { e.preventDefault(); setIdx((i) => Math.min(data.length - 1, i + 1)); }
    else if (e.key === "ArrowLeft") { e.preventDefault(); setIdx((i) => Math.max(0, i - 1)); }
    else if (e.key === "Home") { e.preventDefault(); setIdx(0); }
    else if (e.key === "End") { e.preventDefault(); setIdx(data.length - 1); }
  };

  const active = data[safeIdx];

  return (
    <div>
      <div className="mb-2 flex items-center justify-between gap-2">
        <div className="text-xs text-muted-foreground" aria-live="polite">
          <span className="font-medium text-foreground">{active.d}</span> · NAV{" "}
          <span className="num text-foreground">{fmtUsd(active.nav)}</span>
        </div>
        <div className="inline-flex rounded-md border border-border/60 p-0.5" role="group" aria-label="Chart view">
          <button
            type="button"
            onClick={() => setView("chart")}
            aria-pressed={view === "chart"}
            className={`inline-flex items-center gap-1 rounded px-2 py-1 text-xs transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${view === "chart" ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground"}`}
          >
            <LineIcon className="h-3 w-3" aria-hidden /> Chart
          </button>
          <button
            type="button"
            onClick={() => setView("table")}
            aria-pressed={view === "table"}
            className={`inline-flex items-center gap-1 rounded px-2 py-1 text-xs transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${view === "table" ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground"}`}
          >
            <TableIcon className="h-3 w-3" aria-hidden /> Table
          </button>
        </div>
      </div>

      {view === "chart" ? (
        <div
          role="img"
          aria-label={summary}
          tabIndex={0}
          onKeyDown={onKey}
          className="h-72 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
        >
          <span className="sr-only">
            {summary} Selected point: {active.d}, NAV {fmtUsd(active.nav)}. Use left and right arrows to move, Home and End to jump.
          </span>
          <ResponsiveContainer width="100%" height="100%">
            {kind === "area" ? (
              <AreaChart data={data}>
                <defs>
                  <linearGradient id={gradId} x1="0" x2="0" y1="0" y2="1">
                    <stop offset="0%" stopColor={color} stopOpacity={0.5} />
                    <stop offset="100%" stopColor={color} stopOpacity={0} />
                  </linearGradient>
                </defs>
                <CartesianGrid strokeOpacity={0.06} />
                <XAxis dataKey="d" stroke="oklch(0.68 0.03 260)" fontSize={11} />
                <YAxis stroke="oklch(0.68 0.03 260)" fontSize={11} />
                <Tooltip contentStyle={{ background: "oklch(0.21 0.025 265)", border: "1px solid oklch(1 0 0 / 0.1)", borderRadius: 12, fontSize: 12 }} />
                <Area dataKey="nav" stroke={color} strokeWidth={2} fill={`url(#${gradId})`} />
              </AreaChart>
            ) : (
              <LineChart data={data}>
                <CartesianGrid strokeOpacity={0.06} />
                <XAxis dataKey="d" stroke="oklch(0.68 0.03 260)" fontSize={11} />
                <YAxis stroke="oklch(0.68 0.03 260)" fontSize={11} />
                <Tooltip contentStyle={{ background: "oklch(0.21 0.025 265)", border: "1px solid oklch(1 0 0 / 0.1)", borderRadius: 12, fontSize: 12 }} />
                <Line dataKey="nav" stroke={color} strokeWidth={2} dot={dot} />
              </LineChart>
            )}
          </ResponsiveContainer>
        </div>
      ) : (
        <div className="h-72 overflow-auto rounded-md border border-border/60">
          <table className="w-full text-sm">
            <caption className="sr-only">{summary}</caption>
            <thead className="sticky top-0 bg-background/80 text-left text-[11px] uppercase tracking-wider text-muted-foreground backdrop-blur">
              <tr>
                <th scope="col" className="px-3 py-2">Point</th>
                <th scope="col" className="px-3 py-2">NAV</th>
                <th scope="col" className="px-3 py-2">PnL</th>
              </tr>
            </thead>
            <tbody className="num">
              {data.map((p, i) => (
                <tr
                  key={p.d}
                  aria-selected={i === safeIdx}
                  className={`border-t border-border/40 ${i === safeIdx ? "bg-muted/40" : ""}`}
                >
                  <th scope="row" className="px-3 py-1.5 text-left font-normal">{p.d}</th>
                  <td className="px-3 py-1.5">{fmtUsd(p.nav)}</td>
                  <td className={`px-3 py-1.5 ${p.pnl >= 0 ? "text-bull" : "text-bear"}`}>{fmtUsd(p.pnl)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

function PaperTradeLog({ positions, loading }: { positions: DeltaPosition[]; loading: boolean }) {
  const [q, setQ] = useState("");
  const filtered = useMemo(() => (
    q ? positions.filter((p) => p.coin_symbol.toLowerCase().includes(q.toLowerCase())) : positions
  ), [positions, q]);

  type PSortKey = "opened" | "symbol" | "side" | "size" | "leverage" | "entry" | "mark" | "pnl" | "pnl_pct" | "status";
  const sorters = useMemo(() => ({
    opened: byNumber<DeltaPosition>((p) => new Date(p.opened_at).getTime()),
    symbol: byString<DeltaPosition>((p) => p.coin_symbol),
    side: byString<DeltaPosition>((p) => p.position_side),
    size: byNumber<DeltaPosition>((p) => Number(p.size)),
    leverage: byNumber<DeltaPosition>((p) => Number(p.leverage)),
    entry: byNumber<DeltaPosition>((p) => Number(p.entry_price)),
    mark: byNumber<DeltaPosition>((p) => Number(p.fill_price ?? p.current_price)),
    pnl: byNumber<DeltaPosition>((p) => Number(p.pnl)),
    pnl_pct: byNumber<DeltaPosition>((p) => Number(p.pnl_pct)),
    status: byString<DeltaPosition>((p) => p.order_status),
  }), []);
  const { sorted: rows, key: sortKey, dir: sortDir, toggle: toggleSort } =
    useSort<DeltaPosition, PSortKey>(filtered, sorters, "opened", "desc");


  const stats = useMemo(() => {
    const withPnl = positions.filter((p) => typeof p.pnl === "number");
    const wins = withPnl.filter((p) => p.pnl > 0).length;
    const losses = withPnl.filter((p) => p.pnl < 0).length;
    const net = withPnl.reduce((s, p) => s + (Number(p.pnl) || 0), 0);
    const gross = withPnl.reduce((s, p) => s + Math.abs(Number(p.pnl) || 0), 0);
    const winRate = withPnl.length ? (wins / withPnl.length) * 100 : 0;
    const best = withPnl.reduce((m, p) => (p.pnl > (m?.pnl ?? -Infinity) ? p : m), null as DeltaPosition | null);
    const worst = withPnl.reduce((m, p) => (p.pnl < (m?.pnl ?? Infinity) ? p : m), null as DeltaPosition | null);
    return { wins, losses, net, gross, winRate, best, worst, count: positions.length };
  }, [positions]);

  const exportCsv = () => {
    const header = ["opened_at", "coin", "side", "size", "leverage", "entry", "exit_or_mark", "stop_loss", "take_profit", "pnl", "pnl_pct", "status"];
    const body = rows.map((p) => [
      p.opened_at,
      p.coin_symbol,
      p.position_side,
      p.size,
      p.leverage,
      p.entry_price,
      p.fill_price ?? p.current_price,
      p.stop_loss,
      p.take_profit,
      (p.pnl ?? 0).toFixed(2),
      (p.pnl_pct ?? 0).toFixed(2),
      p.order_status,
    ]);
    const csv = [header, ...body].map((r) => r.join(",")).join("\n");
    const blob = new Blob([csv], { type: "text/csv" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `paper-trades-${new Date().toISOString().slice(0, 10)}.csv`;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <Card className="glass p-4">
      <div className="mb-3 flex flex-wrap items-center justify-between gap-2">
        <div className="flex items-center gap-2">
          <FlaskConical className="h-4 w-4 text-primary" aria-hidden />
          <h2 className="font-display text-lg font-bold">Paper Trade Log</h2>
          <Badge variant="outline" className="text-[10px]">Simulated</Badge>
        </div>
        <div className="flex items-center gap-2">
          <input
            type="search"
            value={q}
            onChange={(e) => setQ(e.target.value)}
            placeholder="Filter by symbol…"
            aria-label="Filter paper trades by symbol"
            className="h-8 rounded-md border border-border/60 bg-background/50 px-2 text-xs focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
          />
          <Button variant="outline" size="sm" className="gap-2" onClick={exportCsv} disabled={!rows.length} aria-label="Export paper trades as CSV">
            <Download className="h-3.5 w-3.5" aria-hidden /> Export
          </Button>
        </div>
      </div>

      <div className="mb-3 grid grid-cols-2 gap-2 md:grid-cols-5">
        <MiniStat label="Trades" value={String(stats.count)} />
        <MiniStat label="Win Rate" value={`${stats.winRate.toFixed(1)}%`} tone={stats.winRate >= 50 ? "bull" : stats.winRate > 0 ? "bear" : undefined} />
        <MiniStat label="Net PnL" value={fmtUsd(stats.net)} tone={stats.net > 0 ? "bull" : stats.net < 0 ? "bear" : undefined} />
        <MiniStat label="Best" value={stats.best ? `${stats.best.coin_symbol} ${fmtUsd(stats.best.pnl)}` : "—"} tone="bull" />
        <MiniStat label="Worst" value={stats.worst ? `${stats.worst.coin_symbol} ${fmtUsd(stats.worst.pnl)}` : "—"} tone="bear" />
      </div>

      {loading ? (
        <div className="h-40 animate-pulse rounded-md bg-muted/30" aria-hidden />
      ) : rows.length === 0 ? (
        <EmptyState title="No paper trades yet" body="Approve a signal in paper mode or execute a manual paper trade to populate this log." />
      ) : (
        <div className="max-h-96 overflow-auto rounded-md border border-border/60">
          <table className="w-full min-w-[820px] text-sm">
            <caption className="sr-only">Paper trade log with entry, exit, pnl and status</caption>
            <thead className="sticky top-0 bg-background/80 text-left text-[11px] uppercase tracking-wider text-muted-foreground backdrop-blur">
              <tr>
                <SortTh label="Opened" active={sortKey === "opened"} dir={sortDir} onClick={() => toggleSort("opened")} className="px-3 py-2" />
                <SortTh label="Symbol" active={sortKey === "symbol"} dir={sortDir} onClick={() => toggleSort("symbol")} className="px-3 py-2" />
                <SortTh label="Side" active={sortKey === "side"} dir={sortDir} onClick={() => toggleSort("side")} className="px-3 py-2" />
                <SortTh label="Size" active={sortKey === "size"} dir={sortDir} onClick={() => toggleSort("size")} className="px-3 py-2" />
                <SortTh label="Lev" active={sortKey === "leverage"} dir={sortDir} onClick={() => toggleSort("leverage")} className="px-3 py-2" />
                <SortTh label="Entry" active={sortKey === "entry"} dir={sortDir} onClick={() => toggleSort("entry")} className="px-3 py-2" />
                <SortTh label="Mark/Fill" active={sortKey === "mark"} dir={sortDir} onClick={() => toggleSort("mark")} className="px-3 py-2" />
                <th scope="col" className="px-3 py-2">SL / TP</th>
                <SortTh label="PnL" active={sortKey === "pnl"} dir={sortDir} onClick={() => toggleSort("pnl")} className="px-3 py-2" />
                <SortTh label="%" active={sortKey === "pnl_pct"} dir={sortDir} onClick={() => toggleSort("pnl_pct")} className="px-3 py-2" />
                <SortTh label="Status" active={sortKey === "status"} dir={sortDir} onClick={() => toggleSort("status")} className="px-3 py-2" />
              </tr>
            </thead>
            <tbody className="num">
              {rows.map((p) => (
                <tr key={p._id} className="border-t border-border/40">
                  <th scope="row" className="px-3 py-1.5 text-left font-normal text-muted-foreground">{new Date(p.opened_at).toLocaleString()}</th>
                  <td className="px-3 py-1.5 font-medium">{p.coin_symbol}</td>
                  <td className={`px-3 py-1.5 ${p.position_side === "LONG" ? "text-bull" : "text-bear"}`}>{p.position_side}</td>
                  <td className="px-3 py-1.5">{p.size}</td>
                  <td className="px-3 py-1.5">{p.leverage}x</td>
                  <td className="px-3 py-1.5">{fmtUsd(p.entry_price)}</td>
                  <td className="px-3 py-1.5">{fmtUsd(p.fill_price ?? p.current_price)}</td>
                  <td className="px-3 py-1.5 text-xs text-muted-foreground">{fmtUsd(p.stop_loss)} / {fmtUsd(p.take_profit)}</td>
                  <td className={`px-3 py-1.5 ${p.pnl >= 0 ? "text-bull" : "text-bear"}`}>{fmtUsd(p.pnl)}</td>
                  <td className={`px-3 py-1.5 ${p.pnl_pct >= 0 ? "text-bull" : "text-bear"}`}>{p.pnl_pct?.toFixed(2)}%</td>
                  <td className="px-3 py-1.5"><Badge variant="outline" className="text-[10px]">{p.order_status}</Badge></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </Card>
  );
}

function MiniStat({ label, value, tone }: { label: string; value: string; tone?: "bull" | "bear" }) {
  return (
    <div className="rounded-md border border-border/60 p-2">
      <div className="text-[10px] uppercase tracking-widest text-muted-foreground">{label}</div>
      <div className={`num mt-0.5 text-sm font-semibold ${tone === "bull" ? "text-bull" : tone === "bear" ? "text-bear" : ""}`}>{value}</div>
    </div>
  );
}


function Kpi({ label, value, tone }: { label: string; value: string; tone?: "bull" | "bear" }) {
  return (
    <Card className="glass p-4">
      <div className="text-[11px] uppercase tracking-widest text-muted-foreground">{label}</div>
      <div className={`num mt-1 text-2xl font-bold ${tone === "bull" ? "text-bull" : tone === "bear" ? "text-bear" : ""}`}>{value}</div>
    </Card>
  );
}
