import type { Estimate, Invoice } from './shared';
import { useMemo } from 'react';
import { Link } from 'react-router';
import { Area, AreaChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
import { ArrowDownRight, ArrowUpRight, CircleDollarSign, FileText, Receipt, Wallet } from 'lucide-react';
import { formatAmount, formatDate, formatMoney, relativeDue, toMajor } from './format';
import { EmptyState, ErrorState, LoadingState, StatusBadge } from './components';
import { invoicesRecordPath, invoicesSectionPath } from './shared';
import { useSummary } from './useInvoiceShelfData';

// The /invoices landing section — InvoiceShelf's own dashboard, rebuilt.
//
// Every figure here comes from the single /summary call the nav already makes, so arriving on this section
// costs no extra request. Upstream hands the chart over as five parallel arrays (months + four series)
// rather than as rows, so they are zipped into recharts' row shape below.

export const DashboardView = () => {
  const { dashboard, currency, isLoading, error } = useSummary();

  const chartRows = useMemo(() => {
    const chart = dashboard?.chart_data;
    if (!chart?.months?.length) return [];
    return chart.months.map((month, i) => ({
      month,
      // recharts needs major units or the axis reads in cents; the tooltip re-formats from these.
      // toMajor divides by 100, matching formatMoney — see the note on MINOR_PER_MAJOR in format.ts.
      sales: toMajor(chart.invoice_totals?.[i]),
      receipts: toMajor(chart.receipt_totals?.[i]),
      expenses: toMajor(chart.expense_totals?.[i]),
      net: toMajor(chart.net_income_totals?.[i]),
    }));
  }, [dashboard]);

  if (error) return <ErrorState error={error} />;
  if (isLoading) return <LoadingState />;
  if (!dashboard) return <EmptyState title="No dashboard data" />;

  const hasChart = chartRows.some((r) => r.sales || r.receipts || r.expenses || r.net);

  return (
    <div className="h-full overflow-y-auto p-4">
      <div className="grid grid-cols-2 gap-3 lg:grid-cols-4">
        <MetricCard
          icon={CircleDollarSign}
          tone="text-amber-500 bg-amber-500/10"
          label="Amount due"
          value={formatMoney(dashboard.total_amount_due, currency)}
          hint={`${dashboard.total_invoice_count} invoices`}
          to={`${invoicesSectionPath('invoices')}?status=UNPAID`}
        />
        <MetricCard
          icon={FileText}
          tone="text-sky-500 bg-sky-500/10"
          label="Sales"
          value={formatMoney(dashboard.total_sales, currency)}
          to={invoicesSectionPath('invoices')}
        />
        <MetricCard
          icon={Wallet}
          tone="text-emerald-500 bg-emerald-500/10"
          label="Receipts"
          value={formatMoney(dashboard.total_receipts, currency)}
          to={invoicesSectionPath('payments')}
        />
        <MetricCard
          icon={Receipt}
          tone="text-violet-500 bg-violet-500/10"
          label="Net income"
          value={formatMoney(dashboard.total_net_income, currency)}
          hint={`${formatMoney(dashboard.total_expenses, currency)} expenses`}
          to={invoicesSectionPath('expenses')}
        />
      </div>

      {hasChart && (
        <div className="mt-4 rounded-xl border border-border p-3">
          <div className="mb-2 flex items-center justify-between">
            <span className="text-xs font-medium">Last 12 months</span>
            <div className="flex items-center gap-3 text-[10px] text-muted-foreground">
              <LegendDot className="bg-sky-500" label="Sales" />
              <LegendDot className="bg-emerald-500" label="Receipts" />
              <LegendDot className="bg-red-500" label="Expenses" />
            </div>
          </div>
          <div className="h-56 w-full">
            <ResponsiveContainer width="100%" height="100%">
              <AreaChart data={chartRows} margin={{ top: 4, right: 8, bottom: 0, left: 0 }}>
                <defs>
                  <Gradient id="isSales" color="#0ea5e9" />
                  <Gradient id="isReceipts" color="#10b981" />
                  <Gradient id="isExpenses" color="#ef4444" />
                </defs>
                <CartesianGrid strokeDasharray="3 3" className="stroke-border" vertical={false} />
                <XAxis dataKey="month" tick={{ fontSize: 10 }} tickLine={false} axisLine={false} />
                <YAxis
                  tick={{ fontSize: 10 }}
                  tickLine={false}
                  axisLine={false}
                  width={56}
                  tickFormatter={(v: number) => compact(v)}
                />
                <Tooltip
                  contentStyle={{ fontSize: 11, borderRadius: 8 }}
                  // recharts types both arguments as possibly-undefined — a series can have gaps, and a
                  // datum can carry no name — so neither may be annotated as required here.
                  formatter={(value: number | undefined, name: string | undefined) => [
                    formatAmount(Math.round((value ?? 0) * 100), currency),
                    name ?? '',
                  ]}
                />
                <Area
                  type="monotone"
                  dataKey="sales"
                  name="Sales"
                  stroke="#0ea5e9"
                  fill="url(#isSales)"
                  strokeWidth={2}
                />
                <Area
                  type="monotone"
                  dataKey="receipts"
                  name="Receipts"
                  stroke="#10b981"
                  fill="url(#isReceipts)"
                  strokeWidth={2}
                />
                <Area
                  type="monotone"
                  dataKey="expenses"
                  name="Expenses"
                  stroke="#ef4444"
                  fill="url(#isExpenses)"
                  strokeWidth={2}
                />
              </AreaChart>
            </ResponsiveContainer>
          </div>
        </div>
      )}

      <div className="mt-4 grid gap-3 lg:grid-cols-2">
        <RecentPanel
          title="Due invoices"
          empty="Nothing outstanding."
          rows={dashboard.recent_due_invoices ?? []}
          href={(row) => invoicesRecordPath('invoices', row.id)}
          render={(row: Invoice) => ({
            primary: row.invoice_number,
            secondary: row.customer?.name ?? '—',
            amount: formatMoney(row.due_amount, currency),
            status: row.overdue ? 'OVERDUE' : row.paid_status,
            note: relativeDue(row.due_date),
          })}
        />
        <RecentPanel
          title="Recent estimates"
          empty="No estimates yet."
          rows={dashboard.recent_estimates ?? []}
          href={(row) => invoicesRecordPath('estimates', row.id)}
          render={(row: Estimate) => ({
            primary: row.estimate_number,
            secondary: row.customer?.name ?? '—',
            amount: formatMoney(row.total, currency),
            status: row.status,
            note: formatDate(row.estimate_date, row.formatted_estimate_date),
          })}
        />
      </div>
    </div>
  );
};

const Gradient = ({ id, color }: { id: string; color: string }) => (
  <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
    <stop offset="5%" stopColor={color} stopOpacity={0.3} />
    <stop offset="95%" stopColor={color} stopOpacity={0} />
  </linearGradient>
);

const LegendDot = ({ className, label }: { className: string; label: string }) => (
  <span className="flex items-center gap-1">
    <span className={`h-1.5 w-1.5 rounded-full ${className}`} />
    {label}
  </span>
);

/** Axis labels only — a full currency render would not fit and the tooltip carries the exact figure. */
const compact = (v: number): string => {
  const abs = Math.abs(v);
  if (abs >= 1_000_000) return `${(v / 1_000_000).toFixed(1)}M`;
  if (abs >= 1_000) return `${(v / 1_000).toFixed(0)}k`;
  return String(v);
};

// Every tile here only ever *goes somewhere* — no tile mutates anything — so they are anchors, not
// buttons. That is what makes the figures middle-clickable into a new tab and copyable as a link,
// which is the whole point of the section reading its filter out of the query string.
const MetricCard = ({
  icon: Icon,
  tone,
  label,
  value,
  hint,
  to,
}: {
  icon: typeof Wallet;
  tone: string;
  label: string;
  value: string;
  hint?: string;
  to: string;
}) => (
  <Link
    to={to}
    className="flex flex-col gap-2 rounded-xl border border-border p-3 text-left transition-colors hover:bg-muted/40"
  >
    <div className="flex items-center gap-2">
      <span className={`flex h-7 w-7 items-center justify-center rounded-lg ${tone}`}>
        <Icon className="h-3.5 w-3.5" />
      </span>
      <span className="text-xs text-muted-foreground">{label}</span>
    </div>
    <div className="truncate text-lg font-semibold tabular-nums" title={value}>
      {value}
    </div>
    {hint && <div className="truncate text-[10px] text-muted-foreground">{hint}</div>}
  </Link>
);

type RecentRender = { primary: string; secondary: string; amount: string; status: string; note: string };

const RecentPanel = <T extends { id: number }>({
  title,
  rows,
  render,
  href,
  empty,
}: {
  title: string;
  rows: T[];
  render: (row: T) => RecentRender;
  href: (row: T) => string;
  empty: string;
}) => (
  <div className="rounded-xl border border-border">
    <div className="border-b border-border px-3 py-2 text-xs font-medium">{title}</div>
    {rows.length === 0 ? (
      <div className="px-3 py-6 text-center text-xs text-muted-foreground">{empty}</div>
    ) : (
      <div className="divide-y divide-border/50">
        {rows.map((row) => {
          const r = render(row);
          return (
            <Link
              key={row.id}
              to={href(row)}
              className="flex w-full items-center gap-3 px-3 py-2 text-left transition-colors hover:bg-muted/50"
            >
              <div className="min-w-0 flex-1">
                <div className="flex items-center gap-2">
                  <span className="truncate text-xs font-medium">{r.primary}</span>
                  <StatusBadge value={r.status} />
                </div>
                <div className="truncate text-[10px] text-muted-foreground">
                  {r.secondary}
                  {r.note && ` · ${r.note}`}
                </div>
              </div>
              <span className="shrink-0 text-xs tabular-nums">{r.amount}</span>
            </Link>
          );
        })}
      </div>
    )}
  </div>
);

export { ArrowDownRight, ArrowUpRight };
