"use client";

import { useMemo, useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Kpi as KpiCard, KpiStrip } from "@/components/ui/kpi";
import { useLocalStorage } from "@/lib/hooks/use-local-storage";
import { ALL_ORGANIZATIONS } from "@/lib/sag/entities";
import { formatCurrency, formatDate } from "@/lib/utils";
import type { Bill, BillCategory } from "@/lib/finance/bill-types";

interface IncomePaystub {
  id: string;
  date: string;
  gross: number;
  net?: number;
  hours?: number;
  notes?: string;
}

interface IncomeSource {
  id: string;
  employerSlug: string;
  role?: string;
  cadence: string;
  payRate?: number;
  startedAt?: string;
  notes?: string;
  paystubs: IncomePaystub[];
}

interface PlaidAccount {
  accountId: string;
  itemId: string;
  name: string;
  mask?: string;
  balance?: number | null;
  entitySlug?: string;
}

type Period = "month" | "quarter" | "ytd" | "year" | "all";

function periodStart(period: Period, now = new Date()): Date {
  const d = new Date(now);
  switch (period) {
    case "month": {
      d.setDate(1);
      d.setHours(0, 0, 0, 0);
      return d;
    }
    case "quarter": {
      const q = Math.floor(d.getMonth() / 3) * 3;
      d.setMonth(q, 1);
      d.setHours(0, 0, 0, 0);
      return d;
    }
    case "ytd":
    case "year": {
      d.setMonth(0, 1);
      d.setHours(0, 0, 0, 0);
      return d;
    }
    case "all":
      return new Date(0);
  }
}

export function IfrReport() {
  const [bills] = useLocalStorage<Bill[]>("sag.bills.v2", []);
  const [incomeSources] = useLocalStorage<IncomeSource[]>("sag.income.sources", []);
  const [plaidAccounts] = useLocalStorage<PlaidAccount[]>("sag.plaid.accounts", []);

  const [period, setPeriod] = useState<Period>("ytd");
  const [entityFilter, setEntityFilter] = useState<string>("all");

  const { now, startISO } = useMemo(() => {
    const n = new Date();
    return { now: n, startISO: periodStart(period, n).toISOString().slice(0, 10) };
  }, [period]);

  const filteredBills = useMemo(() => {
    return bills.filter((b) => {
      if (entityFilter !== "all" && b.entitySlug !== entityFilter) return false;
      const reference = b.payment?.paidDate ?? b.dueDate;
      if (reference < startISO) return false;
      return true;
    });
  }, [bills, entityFilter, startISO]);

  const outstandingBills = useMemo(
    () =>
      filteredBills
        .filter((b) => b.status !== "Paid" && b.status !== "Cancelled")
        .sort((a, b) => a.dueDate.localeCompare(b.dueDate)),
    [filteredBills]
  );
  const paidBills = useMemo(
    () =>
      filteredBills
        .filter((b) => b.status === "Paid")
        .sort((a, b) =>
          (b.payment?.paidDate ?? b.dueDate).localeCompare(a.payment?.paidDate ?? a.dueDate)
        ),
    [filteredBills]
  );

  const totalPaid = paidBills.reduce((a, b) => a + (b.payment?.amount ?? b.amount), 0);
  const totalOutstanding = outstandingBills.reduce((a, b) => a + b.amount, 0);
  const overdueCount = outstandingBills.filter((b) => b.dueDate < now.toISOString().slice(0, 10))
    .length;
  const overdueAmount = outstandingBills
    .filter((b) => b.dueDate < now.toISOString().slice(0, 10))
    .reduce((a, b) => a + b.amount, 0);

  // Income paystubs in window.
  const incomeInWindow = useMemo(() => {
    let sum = 0;
    const records: Array<{ source: IncomeSource; stub: IncomePaystub }> = [];
    for (const s of incomeSources) {
      for (const p of s.paystubs) {
        if (p.date < startISO) continue;
        sum += p.gross;
        records.push({ source: s, stub: p });
      }
    }
    records.sort((a, b) => b.stub.date.localeCompare(a.stub.date));
    return { sum, records };
  }, [incomeSources, startISO]);

  const byCategory = useMemo(() => {
    const map = new Map<string, number>();
    for (const b of paidBills) {
      const k = b.category ?? "Uncategorized";
      map.set(k, (map.get(k) ?? 0) + (b.payment?.amount ?? b.amount));
    }
    return Array.from(map.entries()).sort((a, b) => b[1] - a[1]);
  }, [paidBills]);

  const byEntity = useMemo(() => {
    const map = new Map<string, number>();
    for (const b of paidBills) {
      map.set(b.entitySlug, (map.get(b.entitySlug) ?? 0) + (b.payment?.amount ?? b.amount));
    }
    return Array.from(map.entries()).sort((a, b) => b[1] - a[1]);
  }, [paidBills]);

  const byPaymentMethod = useMemo(() => {
    const map = new Map<string, number>();
    for (const b of paidBills) {
      const method = b.payment?.method ?? "Other";
      map.set(method, (map.get(method) ?? 0) + (b.payment?.amount ?? b.amount));
    }
    return Array.from(map.entries()).sort((a, b) => b[1] - a[1]);
  }, [paidBills]);

  const plaidBalances = useMemo(() => {
    const visible =
      entityFilter === "all"
        ? plaidAccounts
        : plaidAccounts.filter((a) => a.entitySlug === entityFilter);
    const total = visible.reduce((a, x) => a + (x.balance ?? 0), 0);
    return { accounts: visible, total };
  }, [plaidAccounts, entityFilter]);

  const net = incomeInWindow.sum - totalPaid;

  function exportJson() {
    const payload = {
      generatedAt: new Date().toISOString(),
      period,
      periodStart: startISO,
      entityFilter,
      kpis: {
        cashBalance: plaidBalances.total,
        incomeInPeriod: incomeInWindow.sum,
        billsPaidInPeriod: totalPaid,
        billsOutstanding: totalOutstanding,
        overdueCount,
        overdueAmount,
        netCashFlow: net,
      },
      byCategory: Object.fromEntries(byCategory),
      byEntity: Object.fromEntries(byEntity),
      byPaymentMethod: Object.fromEntries(byPaymentMethod),
      paidBills: paidBills.map((b) => ({
        vendor: b.vendor,
        amount: b.payment?.amount ?? b.amount,
        paidDate: b.payment?.paidDate,
        method: b.payment?.method,
        confirmation: b.payment?.confirmationNumber,
        entity: b.entitySlug,
        category: b.category,
      })),
      outstandingBills: outstandingBills.map((b) => ({
        vendor: b.vendor,
        amount: b.amount,
        dueDate: b.dueDate,
        status: b.status,
        entity: b.entitySlug,
        category: b.category,
      })),
      incomePaystubs: incomeInWindow.records.map((r) => ({
        employer: r.source.employerSlug,
        date: r.stub.date,
        gross: r.stub.gross,
        net: r.stub.net,
      })),
    };
    const blob = new Blob([JSON.stringify(payload, null, 2)], { type: "application/json" });
    triggerDownload(blob, `IFR-${periodLabel(period)}-${startISO}.json`);
  }

  function exportCsv() {
    const rows: Array<Array<string | number>> = [];
    rows.push(["Type", "Date", "Vendor / Source", "Amount", "Entity", "Category / Method"]);
    for (const r of incomeInWindow.records) {
      rows.push(["INCOME", r.stub.date, r.source.employerSlug, r.stub.gross, "—", "W-2"]);
    }
    for (const b of paidBills) {
      rows.push([
        "BILL PAID",
        b.payment?.paidDate ?? b.dueDate,
        b.vendor,
        -(b.payment?.amount ?? b.amount),
        b.entitySlug,
        `${b.category ?? "—"} / ${b.payment?.method ?? "—"}`,
      ]);
    }
    for (const b of outstandingBills) {
      rows.push([
        `BILL ${b.status.toUpperCase()}`,
        b.dueDate,
        b.vendor,
        -b.amount,
        b.entitySlug,
        b.category ?? "—",
      ]);
    }
    const csv = rows
      .map((r) =>
        r
          .map((cell) => {
            const s = typeof cell === "number" ? cell.toFixed(2) : String(cell);
            return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
          })
          .join(",")
      )
      .join("\n");
    const blob = new Blob([csv], { type: "text/csv" });
    triggerDownload(blob, `IFR-${periodLabel(period)}-${startISO}.csv`);
  }

  return (
    <div className="space-y-6 max-w-6xl">
      <Card>
        <CardContent className="p-4 flex items-center flex-wrap gap-3">
          <div className="flex items-center gap-2">
            <label className="text-xs text-muted-foreground">Period</label>
            <select
              value={period}
              onChange={(e) => setPeriod(e.target.value as Period)}
              className="h-9 rounded-md border border-input bg-background px-3 text-sm"
            >
              <option value="month">This month</option>
              <option value="quarter">This quarter</option>
              <option value="ytd">Year to date</option>
              <option value="year">This year</option>
              <option value="all">All time</option>
            </select>
          </div>
          <div className="flex items-center gap-2">
            <label className="text-xs text-muted-foreground">Entity</label>
            <select
              value={entityFilter}
              onChange={(e) => setEntityFilter(e.target.value)}
              className="h-9 rounded-md border border-input bg-background px-3 text-sm"
            >
              <option value="all">All entities</option>
              {ALL_ORGANIZATIONS.map((o) => (
                <option key={o.slug} value={o.slug}>
                  {o.emoji} {o.name}
                </option>
              ))}
            </select>
          </div>
          <span className="text-xs text-muted-foreground tabular-nums">
            {periodLabel(period)} · since {startISO}
          </span>
          <div className="md:ml-auto flex flex-wrap items-center gap-2 w-full md:w-auto">
            <Button variant="outline" size="sm" onClick={exportCsv}>
              ⬇ CSV
            </Button>
            <Button variant="outline" size="sm" onClick={exportJson}>
              ⬇ JSON
            </Button>
          </div>
        </CardContent>
      </Card>

      <KpiStrip cols={5}>
        <KpiCard
          label="Cash balance"
          value={formatCurrency(plaidBalances.total)}
          hint={`${plaidBalances.accounts.length} linked account${plaidBalances.accounts.length === 1 ? "" : "s"}`}
          tone="violet"
        />
        <KpiCard
          label="Income in period"
          value={formatCurrency(incomeInWindow.sum)}
          hint={`${incomeInWindow.records.length} paystubs`}
          tone="emerald"
        />
        <KpiCard
          label="Bills paid in period"
          value={formatCurrency(totalPaid)}
          hint={`${paidBills.length} bill${paidBills.length === 1 ? "" : "s"}`}
        />
        <KpiCard
          label="Outstanding"
          value={formatCurrency(totalOutstanding)}
          hint={`${outstandingBills.length} open`}
          tone="amber"
        />
        <KpiCard
          label="Net (income − bills)"
          value={formatCurrency(net)}
          hint={net >= 0 ? "Positive" : "Negative"}
          tone={net >= 0 ? "emerald" : "rose"}
        />
      </KpiStrip>

      {overdueCount > 0 && (
        <Card className="border-destructive/40 bg-destructive/5">
          <CardContent className="p-4 text-sm">
            <strong className="text-destructive">⚠️ Overdue:</strong> {overdueCount} bill
            {overdueCount === 1 ? "" : "s"} past due totaling {formatCurrency(overdueAmount)}.
          </CardContent>
        </Card>
      )}

      <div className="grid gap-4 md:grid-cols-2">
        <BarsCard
          title="Spend by category"
          rows={byCategory.map(([k, v]) => ({
            label: k,
            value: v,
            color: categoryColor(k as BillCategory | "Uncategorized"),
          }))}
          total={totalPaid}
          empty="No paid bills in this period."
        />
        <BarsCard
          title="Spend by entity"
          rows={byEntity.map(([slug, v]) => {
            const org = ALL_ORGANIZATIONS.find((o) => o.slug === slug);
            return {
              label: org ? `${org.emoji} ${org.name}` : slug,
              value: v,
              color: org?.primaryColor ?? "#7a3e2e",
            };
          })}
          total={totalPaid}
          empty="No paid bills in this period."
        />
      </div>

      <BarsCard
        title="Spend by payment method"
        rows={byPaymentMethod.map(([k, v]) => ({
          label: k,
          value: v,
          color: "#7a3e2e",
        }))}
        total={totalPaid}
        empty="No paid bills in this period."
      />

      <Card>
        <CardContent className="p-5">
          <h2 className="text-sm font-semibold mb-3">Outstanding bills</h2>
          {outstandingBills.length === 0 ? (
            <p className="text-xs text-muted-foreground">
              Nothing outstanding for this filter. Add bills at <code>/app/finance/bills</code>.
            </p>
          ) : (
            <div className="overflow-x-auto">
              <table className="w-full min-w-[640px] text-sm">
                <thead className="section-label border-b">
                  <tr>
                    <th className="px-2 py-2 text-left">Vendor</th>
                    <th className="px-2 py-2 text-left">Due</th>
                    <th className="px-2 py-2 text-right">Amount</th>
                    <th className="px-2 py-2 text-left">Entity</th>
                    <th className="px-2 py-2 text-left">Category</th>
                    <th className="px-2 py-2 text-left">Status</th>
                  </tr>
                </thead>
                <tbody>
                  {outstandingBills.map((b) => {
                    const org = ALL_ORGANIZATIONS.find((o) => o.slug === b.entitySlug);
                    const isOverdue = b.dueDate < now.toISOString().slice(0, 10);
                    return (
                      <tr key={b.id} className="border-b last:border-0">
                        <td className="px-2 py-2">{b.vendor}</td>
                        <td className="px-2 py-2 font-mono text-xs">
                          {b.dueDate}{" "}
                          {isOverdue && (
                            <Badge variant="destructive" className="text-[10px] ml-1">
                              overdue
                            </Badge>
                          )}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums">
                          {formatCurrency(b.amount)}
                        </td>
                        <td className="px-2 py-2 text-xs">
                          {org ? `${org.emoji} ${org.name}` : b.entitySlug}
                        </td>
                        <td className="px-2 py-2 text-xs">{b.category ?? "—"}</td>
                        <td className="px-2 py-2 text-xs">{b.status}</td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}
        </CardContent>
      </Card>

      <Card>
        <CardContent className="p-5">
          <h2 className="text-sm font-semibold mb-3">Recent payments</h2>
          {paidBills.length === 0 ? (
            <p className="text-xs text-muted-foreground">No payments logged in this period.</p>
          ) : (
            <div className="overflow-x-auto">
              <table className="w-full min-w-[640px] text-sm">
                <thead className="section-label border-b">
                  <tr>
                    <th className="px-2 py-2 text-left">Paid</th>
                    <th className="px-2 py-2 text-left">Vendor</th>
                    <th className="px-2 py-2 text-right">Amount</th>
                    <th className="px-2 py-2 text-left">Method</th>
                    <th className="px-2 py-2 text-left">Entity</th>
                    <th className="px-2 py-2 text-left">Conf #</th>
                  </tr>
                </thead>
                <tbody>
                  {paidBills.slice(0, 20).map((b) => {
                    const org = ALL_ORGANIZATIONS.find((o) => o.slug === b.entitySlug);
                    return (
                      <tr key={b.id} className="border-b last:border-0">
                        <td className="px-2 py-2 font-mono text-xs">
                          {b.payment?.paidDate ?? "—"}
                        </td>
                        <td className="px-2 py-2">{b.vendor}</td>
                        <td className="px-2 py-2 text-right tabular-nums">
                          {formatCurrency(b.payment?.amount ?? b.amount)}
                        </td>
                        <td className="px-2 py-2 text-xs">{b.payment?.method ?? "—"}</td>
                        <td className="px-2 py-2 text-xs">
                          {org ? `${org.emoji} ${org.name}` : b.entitySlug}
                        </td>
                        <td className="px-2 py-2 text-[11px] font-mono text-muted-foreground">
                          {b.payment?.confirmationNumber ?? "—"}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
              {paidBills.length > 20 && (
                <p className="mt-2 text-[11px] text-muted-foreground">
                  Showing 20 of {paidBills.length} — export CSV for the full ledger.
                </p>
              )}
            </div>
          )}
        </CardContent>
      </Card>

      <Card>
        <CardContent className="p-5">
          <h2 className="text-sm font-semibold mb-3">Income paystubs</h2>
          {incomeInWindow.records.length === 0 ? (
            <p className="text-xs text-muted-foreground">
              No paystubs in this period. Log them at <code>/app/income</code>.
            </p>
          ) : (
            <div className="overflow-x-auto">
              <table className="w-full min-w-[560px] text-sm">
                <thead className="section-label border-b">
                  <tr>
                    <th className="px-2 py-2 text-left">Date</th>
                    <th className="px-2 py-2 text-left">Employer</th>
                    <th className="px-2 py-2 text-right">Gross</th>
                    <th className="px-2 py-2 text-right">Net</th>
                    <th className="px-2 py-2 text-right">Hours</th>
                  </tr>
                </thead>
                <tbody>
                  {incomeInWindow.records.slice(0, 20).map((r) => {
                    const org = ALL_ORGANIZATIONS.find((o) => o.slug === r.source.employerSlug);
                    return (
                      <tr key={r.stub.id} className="border-b last:border-0">
                        <td className="px-2 py-2 font-mono text-xs">{r.stub.date}</td>
                        <td className="px-2 py-2 text-xs">
                          {org ? `${org.emoji} ${org.name}` : r.source.employerSlug}
                          {r.source.role ? (
                            <span className="text-muted-foreground"> · {r.source.role}</span>
                          ) : null}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums">
                          {formatCurrency(r.stub.gross)}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums text-muted-foreground">
                          {r.stub.net != null ? formatCurrency(r.stub.net) : "—"}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums text-muted-foreground">
                          {r.stub.hours ?? "—"}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}
        </CardContent>
      </Card>

      <Card className="border-dashed">
        <CardContent className="p-5 text-xs text-muted-foreground">
          Generated from local data — bills (<code>sag.bills.v2</code>), personal income
          (<code>sag.income.sources</code>), and Plaid balances (<code>sag.plaid.accounts</code>).
          When Supabase is provisioned, this same view will run server-side with row-level
          security, period comparison, and multi-user attribution. Last computed{" "}
          {formatDate(now)}.
        </CardContent>
      </Card>
    </div>
  );
}

function BarsCard({
  title,
  rows,
  total,
  empty,
}: {
  title: string;
  rows: Array<{ label: string; value: number; color: string }>;
  total: number;
  empty: string;
}) {
  return (
    <Card>
      <CardContent className="p-5">
        <h2 className="text-sm font-semibold mb-3">{title}</h2>
        {rows.length === 0 || total === 0 ? (
          <p className="text-xs text-muted-foreground">{empty}</p>
        ) : (
          <div className="space-y-2">
            {rows.map((r) => {
              const pct = total > 0 ? (r.value / total) * 100 : 0;
              return (
                <div key={r.label}>
                  <div className="flex items-center justify-between text-xs mb-1">
                    <span className="truncate pr-2">{r.label}</span>
                    <span className="tabular-nums text-muted-foreground shrink-0">
                      {formatCurrency(r.value)} · {pct.toFixed(0)}%
                    </span>
                  </div>
                  <div className="h-2 rounded-full bg-muted overflow-hidden">
                    <div
                      className="h-full rounded-full"
                      style={{
                        width: `${pct}%`,
                        backgroundColor: r.color,
                      }}
                    />
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </CardContent>
    </Card>
  );
}

function periodLabel(p: Period): string {
  return p === "month"
    ? "this-month"
    : p === "quarter"
      ? "this-quarter"
      : p === "ytd"
        ? "ytd"
        : p === "year"
          ? "year"
          : "all";
}

function categoryColor(category: BillCategory | "Uncategorized"): string {
  const map: Record<string, string> = {
    Utilities: "#0284c7",
    "Internet & Telecom": "#0891b2",
    "Software & SaaS": "#7c3aed",
    Insurance: "#0d9488",
    "Rent & Lease": "#92400e",
    "Professional Services": "#525252",
    "Inventory & Supplies": "#b45309",
    "Taxes & Fees": "#dc2626",
    Payroll: "#16a34a",
    "Loan & Financing": "#0c4a6e",
    Marketing: "#a21caf",
    "Travel & Meals": "#ca8a04",
    Maintenance: "#65a30d",
    Subscriptions: "#4338ca",
    Other: "#64748b",
    Uncategorized: "#9ca3af",
  };
  return map[category] ?? "#7a3e2e";
}

function triggerDownload(blob: Blob, filename: string) {
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}
