'use client';

import { useMemo, useState, useCallback } from 'react';
import { useSearchParams } from 'next/navigation';
import { useQuery } from '@tanstack/react-query';
import { Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';

import { PageHeader } from '@/components/shared/page-header';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Skeleton } from '@/components/ui/skeleton';
import { DateRangePicker } from '@/components/dashboard/date-range-picker';
import { ReportExportButton } from '@/components/reports/shared/report-export-button';
import { ReportTemplatesButton } from '@/components/reports/shared/report-templates-button';
import { rangeToBounds, type DateRange } from '@/lib/analytics/range';
import { apiFetch } from '@/lib/api/client';
import { formatMoney, formatMoneyCompact, formatNumber } from '@/lib/reports/format-currency';
import type { ReportPayload } from '@/lib/reports/types';
import { ReportEmptyState } from '@/components/reports/shared/report-empty-state';
import type { Route } from 'next';
import { Wallet } from 'lucide-react';

// ─── Payload types (mirror the /api/v1/reports/financial response) ───────────
// NOTE: the API still returns expense/cash-flow/net-contribution fields; we
// deliberately omit them here. Expenses are business-trip costs tracked in the
// standalone Expenses section and do NOT factor into the financial picture, so
// the Financial report is purely revenue / deposits / collections.

interface FinancialKpis {
  revenueCollected: number;
  depositsCollected: number;
  balanceCollected: number;
  refundsIssued: number;
  pipelineExpected: number;
  expectedDepositsOutstanding: number;
  currency: string;
}
interface RevenueByMonthRow {
  month: string;
  deposit: number;
  balance: number;
}
interface CollectionFunnelRow {
  stage: string;
  label: string;
  count: number;
}
interface AgingRow {
  bucket: string;
  count: number;
  value: number;
}
interface OutstandingDepositRow {
  interestId: string;
  clientName: string;
  mooring: string | null;
  expected: number;
  collected: number;
  remaining: number;
  currency: string;
  daysOutstanding: number;
}
interface RecentPaymentRow {
  id: string;
  receivedAt: string;
  clientName: string;
  mooring: string | null;
  paymentType: string;
  amount: number;
  currency: string;
}
interface RefundRow {
  id: string;
  receivedAt: string;
  clientName: string;
  amount: number;
  currency: string;
  notes: string | null;
}

interface FinancialPayload {
  data: {
    kpis: FinancialKpis;
    revenueByMonth: RevenueByMonthRow[];
    collectionFunnel: CollectionFunnelRow[];
    aging: AgingRow[];
    outstandingDeposits: OutstandingDepositRow[];
    recentPayments: RecentPaymentRow[];
    refundLog: RefundRow[];
    range: { from: string; to: string };
    hasData: boolean;
  };
}

interface FinancialTemplateConfig extends Record<string, unknown> {
  kind: 'financial';
  range: DateRange;
}

type MonthGranularity = 'month' | 'quarter' | 'year';

export function FinancialReportClient({ portSlug }: { portSlug: string }) {
  const searchParams = useSearchParams();
  const initialTemplateId = searchParams?.get('templateId') ?? null;

  const [range, setRange] = useState<DateRange>('1y');
  const [granularity, setGranularity] = useState<MonthGranularity>('month');
  const [activeTemplateId, setActiveTemplateId] = useState<string | null>(initialTemplateId);

  const handleRangeChange = useCallback((next: DateRange) => {
    setRange(next);
    setActiveTemplateId(null);
  }, []);

  const currentConfig: FinancialTemplateConfig = useMemo(
    () => ({ kind: 'financial', range }),
    [range],
  );

  const handleApplyTemplate = useCallback((config: FinancialTemplateConfig) => {
    if (config.range) setRange(config.range);
  }, []);

  const bounds = useMemo(() => rangeToBounds(range), [range]);

  const query = useQuery<FinancialPayload>({
    queryKey: ['reports', 'financial', bounds.from.toISOString(), bounds.to.toISOString()],
    queryFn: () =>
      apiFetch<FinancialPayload>(
        `/api/v1/reports/financial?from=${encodeURIComponent(bounds.from.toISOString())}&to=${encodeURIComponent(bounds.to.toISOString())}`,
      ),
    staleTime: 30_000,
  });

  const d = query.data?.data;
  const kpis = d?.kpis;
  const currency = kpis?.currency ?? 'EUR';
  const revenueByMonth = d?.revenueByMonth ?? [];
  const collectionFunnel = d?.collectionFunnel ?? [];
  const aging = d?.aging ?? [];
  const outstandingDeposits = d?.outstandingDeposits ?? [];
  const recentPayments = d?.recentPayments ?? [];
  const refundLog = d?.refundLog ?? [];

  // Re-bucket the monthly revenue series for the quarter/year toggle.
  // Depend on the query-data reference (stable across renders once
  // loaded) rather than the `?? []` fallback, which would be a fresh
  // array each render.
  const revenueSeries = useMemo(
    () => rebucketRevenue(d?.revenueByMonth ?? [], granularity),
    [d?.revenueByMonth, granularity],
  );
  const fundedCount = collectionFunnel.length > 0 ? collectionFunnel[0]!.count : 0;

  function buildExportPayload(): ReportPayload {
    if (!kpis) throw new Error('Report still loading');
    return {
      title: 'Financial',
      description: 'Revenue collected, deposits, outstanding balances, and collections.',
      filenameSlug: 'financial',
      range: bounds,
      kpis: [
        { label: 'Revenue collected', value: formatMoney(kpis.revenueCollected, currency) },
        { label: 'Deposits collected', value: formatMoney(kpis.depositsCollected, currency) },
        { label: 'Balance collected', value: formatMoney(kpis.balanceCollected, currency) },
        {
          label: 'Pipeline (expected deposits)',
          value: formatMoney(kpis.pipelineExpected, currency),
        },
        {
          label: 'Outstanding deposits',
          value: formatMoney(kpis.expectedDepositsOutstanding, currency),
        },
      ],
      sections: [
        {
          title: 'Revenue by month',
          columns: [
            { key: 'month', label: 'Month' },
            { key: 'deposit', label: 'Deposits', align: 'right' },
            { key: 'balance', label: 'Balance', align: 'right' },
          ],
          rows: revenueByMonth.map((r) => ({
            month: r.month,
            deposit: formatMoney(r.deposit, currency),
            balance: formatMoney(r.balance, currency),
          })),
        },
        {
          title: 'Outstanding deposits',
          columns: [
            { key: 'clientName', label: 'Client' },
            { key: 'mooring', label: 'Berth' },
            { key: 'remaining', label: 'Remaining', align: 'right' },
            { key: 'daysOutstanding', label: 'Age (days)', align: 'right' },
          ],
          rows: outstandingDeposits.map((r) => ({
            clientName: r.clientName,
            mooring: r.mooring ?? '—',
            remaining: formatMoney(r.remaining, r.currency),
            daysOutstanding: r.daysOutstanding,
          })),
        },
      ],
    };
  }

  const isLoading = query.isLoading || !kpis;

  if (!query.isLoading && d && !d.hasData) {
    return (
      <div className="space-y-6">
        <PageHeader
          eyebrow="Reports"
          title="Financial"
          description="Revenue collected, deposits, and outstanding balances."
        />
        <ReportEmptyState
          icon={Wallet}
          title="No financial activity yet"
          body="Record a payment on a deal to see revenue, deposits, and collections."
          actionLabel="View deals"
          actionHref={`/${portSlug}/interests` as Route}
        />
      </div>
    );
  }

  return (
    <div className="space-y-6">
      <PageHeader
        eyebrow="Reports"
        title="Financial"
        description="Revenue collected, deposits, and outstanding balances. Sourced from recorded payments; the CRM does not invoice."
        actions={
          <div className="flex items-center gap-2">
            <DateRangePicker value={range} onChange={handleRangeChange} />
            <ReportTemplatesButton<FinancialTemplateConfig>
              kind="financial"
              currentConfig={currentConfig}
              onApply={handleApplyTemplate}
              activeTemplateId={activeTemplateId}
              onActiveTemplateChange={setActiveTemplateId}
              initialTemplateId={initialTemplateId}
            />
            <ReportExportButton buildPayload={buildExportPayload} disabled={!kpis} />
          </div>
        }
      />

      {/* KPI STRIP — 5 tiles (expenses + net-contribution intentionally omitted) */}
      <section
        aria-label="Financial KPIs"
        className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5"
      >
        {isLoading ? (
          Array.from({ length: 5 }).map((_, i) => <KpiSkeleton key={i} />)
        ) : (
          <>
            <KpiCard
              label="Revenue collected"
              value={formatMoney(kpis.revenueCollected, currency)}
              hint="All payments received in period (net of refunds)"
            />
            <KpiCard
              label="Deposits collected"
              value={formatMoney(kpis.depositsCollected, currency)}
            />
            <KpiCard
              label="Balance collected"
              value={formatMoney(kpis.balanceCollected, currency)}
            />
            <KpiCard
              label="Pipeline (expected)"
              value={formatMoney(kpis.pipelineExpected, currency)}
              hint="Expected deposits across open deals"
            />
            <KpiCard
              label="Outstanding deposits"
              value={formatMoney(kpis.expectedDepositsOutstanding, currency)}
              hint="Expected but not yet collected"
            />
          </>
        )}
      </section>

      {/* CHART 1 — Revenue by month (stacked: deposit / balance) */}
      <Card>
        <CardHeader className="flex-row items-start justify-between gap-2 space-y-0">
          <div>
            <CardTitle className="text-base">Revenue collected over time</CardTitle>
            <p className="text-xs text-muted-foreground">
              Payments received per period, split deposits vs balance.
            </p>
          </div>
          <div className="flex gap-1">
            {(['month', 'quarter', 'year'] as MonthGranularity[]).map((g) => (
              <Button
                key={g}
                type="button"
                size="sm"
                variant={granularity === g ? 'default' : 'outline'}
                className="h-7 px-2 text-xs capitalize"
                onClick={() => setGranularity(g)}
              >
                {g}
              </Button>
            ))}
          </div>
        </CardHeader>
        <CardContent>
          {isLoading ? (
            <Skeleton className="h-[300px] w-full" />
          ) : revenueSeries.every((r) => r.deposit === 0 && r.balance === 0) ? (
            <EmptyState>
              No payments recorded in this period. Revenue appears here as deposits and balances are
              received on the Payments tab.
            </EmptyState>
          ) : (
            <ResponsiveContainer width="100%" height={300}>
              <BarChart data={revenueSeries} margin={{ top: 8, right: 8, left: 4, bottom: 8 }}>
                <CartesianGrid strokeDasharray="3 3" className="stroke-border" vertical={false} />
                <XAxis
                  dataKey="label"
                  tick={{ fontSize: 11, fill: 'hsl(var(--muted-foreground))' }}
                  interval="preserveStartEnd"
                />
                <YAxis
                  tickFormatter={(v) => formatMoneyCompact(Number(v), currency)}
                  tick={{ fontSize: 11, fill: 'hsl(var(--muted-foreground))' }}
                  width={64}
                />
                <Tooltip
                  contentStyle={tooltipStyle}
                  formatter={(value, name) => [
                    formatMoney(Number(value), currency),
                    name === 'deposit' ? 'Deposits' : 'Balance',
                  ]}
                />
                <Bar
                  dataKey="deposit"
                  stackId="rev"
                  fill="hsl(var(--chart-1))"
                  radius={[0, 0, 0, 0]}
                />
                <Bar
                  dataKey="balance"
                  stackId="rev"
                  fill="hsl(var(--chart-3))"
                  radius={[3, 3, 0, 0]}
                />
              </BarChart>
            </ResponsiveContainer>
          )}
        </CardContent>
      </Card>

      {/* CHART 2 + 3 — Collection funnel + AR aging side by side */}
      <div className="grid gap-4 lg:grid-cols-2">
        <Card>
          <CardHeader>
            <CardTitle className="text-base">Collection funnel</CardTitle>
            <p className="text-xs text-muted-foreground">
              Deals reaching each money milestone in the period. Highlights where revenue leaks.
            </p>
          </CardHeader>
          <CardContent>
            {isLoading ? (
              <Skeleton className="h-[220px] w-full" />
            ) : (
              <div className="space-y-2 py-2">
                {collectionFunnel.map((row) => {
                  const pct = fundedCount > 0 ? (row.count / fundedCount) * 100 : 0;
                  return (
                    <div key={row.stage} className="space-y-1">
                      <div className="flex items-center justify-between text-xs">
                        <span className="font-medium text-foreground">{row.label}</span>
                        <span className="tabular-nums text-muted-foreground">
                          {formatNumber(row.count)}
                        </span>
                      </div>
                      <div className="h-7 w-full rounded bg-muted/50">
                        <div
                          className="flex h-7 items-center rounded bg-[hsl(var(--chart-1))] px-2"
                          style={{ width: `${Math.max(pct, row.count > 0 ? 8 : 0)}%` }}
                        />
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle className="text-base">Outstanding deposits by age</CardTitle>
            <p className="text-xs text-muted-foreground">
              Expected deposits not yet collected, bucketed by how long the deal has been open.
            </p>
          </CardHeader>
          <CardContent>
            {isLoading ? (
              <Skeleton className="h-[220px] w-full" />
            ) : aging.every((r) => r.value === 0) ? (
              <EmptyState>No outstanding deposits. Every open deal is paid up.</EmptyState>
            ) : (
              <ResponsiveContainer width="100%" height={220}>
                <BarChart
                  data={aging}
                  layout="vertical"
                  margin={{ top: 4, right: 12, left: 8, bottom: 4 }}
                >
                  <CartesianGrid
                    strokeDasharray="3 3"
                    className="stroke-border"
                    horizontal={false}
                  />
                  <XAxis
                    type="number"
                    tickFormatter={(v) => formatMoneyCompact(Number(v), currency)}
                    tick={{ fontSize: 11, fill: 'hsl(var(--muted-foreground))' }}
                  />
                  <YAxis
                    type="category"
                    dataKey="bucket"
                    tick={{ fontSize: 11, fill: 'hsl(var(--muted-foreground))' }}
                    width={48}
                  />
                  <Tooltip
                    contentStyle={tooltipStyle}
                    formatter={(value, _name, item) => [
                      `${formatMoney(Number(value), currency)} · ${item?.payload?.count ?? 0} deal(s)`,
                      'Outstanding',
                    ]}
                  />
                  <Bar dataKey="value" fill="hsl(var(--chart-4))" radius={[0, 3, 3, 0]} />
                </BarChart>
              </ResponsiveContainer>
            )}
          </CardContent>
        </Card>
      </div>

      {/* TABLE — Outstanding deposits (the chase list) */}
      <Card>
        <CardHeader>
          <CardTitle className="text-base">Outstanding deposits</CardTitle>
          <p className="text-xs text-muted-foreground">
            Open deals with an expected deposit not yet fully collected. The chase list.
          </p>
        </CardHeader>
        <CardContent className="px-0">
          {isLoading ? (
            <Skeleton className="mx-6 h-[200px]" />
          ) : outstandingDeposits.length === 0 ? (
            <EmptyState>Nothing outstanding. Every open deal is paid up.</EmptyState>
          ) : (
            <SimpleTable
              head={['Client', 'Berth', 'Expected', 'Collected', 'Remaining', 'Age']}
              rows={outstandingDeposits.slice(0, 12).map((r) => [
                r.clientName,
                r.mooring ?? '—',
                <span key="e" className="tabular-nums">
                  {formatMoney(r.expected, r.currency)}
                </span>,
                <span key="c" className="tabular-nums">
                  {formatMoney(r.collected, r.currency)}
                </span>,
                <span key="r" className="tabular-nums font-medium">
                  {formatMoney(r.remaining, r.currency)}
                </span>,
                `${r.daysOutstanding}d`,
              ])}
            />
          )}
        </CardContent>
      </Card>

      {/* TABLES — Recent payments + Refunds */}
      <div className="grid gap-4 lg:grid-cols-2">
        <Card>
          <CardHeader>
            <CardTitle className="text-base">Recent payments</CardTitle>
            <p className="text-xs text-muted-foreground">Latest money received.</p>
          </CardHeader>
          <CardContent className="px-0">
            {isLoading ? (
              <Skeleton className="mx-6 h-[260px]" />
            ) : recentPayments.length === 0 ? (
              <EmptyState>No payments recorded in this period.</EmptyState>
            ) : (
              <SimpleTable
                head={['Date', 'Client', 'Type', 'Amount']}
                rows={recentPayments.slice(0, 8).map((p) => [
                  p.receivedAt ? p.receivedAt.slice(0, 10) : '—',
                  p.clientName,
                  <span key="t" className="capitalize">
                    {p.paymentType}
                  </span>,
                  <span key="a" className="tabular-nums">
                    {formatMoney(p.amount, p.currency)}
                  </span>,
                ])}
              />
            )}
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle className="text-base">Refunds &amp; write-offs</CardTitle>
            <p className="text-xs text-muted-foreground">
              Refund-type payments issued in the period.
            </p>
          </CardHeader>
          <CardContent className="px-0">
            {isLoading ? (
              <Skeleton className="mx-6 h-[200px]" />
            ) : refundLog.length === 0 ? (
              <EmptyState>No refunds in this period.</EmptyState>
            ) : (
              <SimpleTable
                head={['Date', 'Client', 'Amount', 'Notes']}
                rows={refundLog.slice(0, 10).map((r) => [
                  r.receivedAt ? r.receivedAt.slice(0, 10) : '—',
                  r.clientName,
                  <span key="a" className="tabular-nums">
                    {formatMoney(r.amount, r.currency)}
                  </span>,
                  r.notes ?? '—',
                ])}
              />
            )}
          </CardContent>
        </Card>
      </div>
    </div>
  );
}

// ─── helpers + primitives ────────────────────────────────────────────────────

const tooltipStyle = {
  background: 'hsl(var(--popover))',
  border: '1px solid hsl(var(--border))',
  borderRadius: '6px',
  fontSize: 12,
} as const;

function formatMonthLabel(month: string): string {
  const [year, m] = month.split('-');
  if (!year || !m) return month;
  const date = new Date(parseInt(year), parseInt(m) - 1, 1);
  return date.toLocaleDateString(undefined, { month: 'short', year: '2-digit' });
}

/** Re-bucket the monthly revenue series to month / quarter / year for the toggle. */
function rebucketRevenue(
  rows: RevenueByMonthRow[],
  granularity: MonthGranularity,
): Array<{ label: string; deposit: number; balance: number }> {
  if (granularity === 'month') {
    return rows.map((r) => ({
      label: formatMonthLabel(r.month),
      deposit: r.deposit,
      balance: r.balance,
    }));
  }
  const byKey = new Map<string, { deposit: number; balance: number }>();
  for (const r of rows) {
    const [year, m] = r.month.split('-');
    if (!year || !m) continue;
    const key = granularity === 'year' ? year : `${year}-Q${Math.floor((parseInt(m) - 1) / 3) + 1}`;
    const acc = byKey.get(key) ?? { deposit: 0, balance: 0 };
    acc.deposit += r.deposit;
    acc.balance += r.balance;
    byKey.set(key, acc);
  }
  return Array.from(byKey.entries()).map(([label, v]) => ({ label, ...v }));
}

interface KpiCardProps {
  label: string;
  value: string;
  hint?: string;
  valueTone?: 'positive' | 'negative' | 'neutral';
}

function KpiCard({ label, value, hint, valueTone = 'neutral' }: KpiCardProps) {
  return (
    <Card className="h-full p-4 space-y-1.5">
      <p className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground">
        {label}
      </p>
      <p
        className={
          'text-2xl font-semibold tracking-tight tabular-nums ' +
          (valueTone === 'positive'
            ? 'text-emerald-600'
            : valueTone === 'negative'
              ? 'text-rose-600'
              : 'text-foreground')
        }
      >
        {value}
      </p>
      {hint ? (
        <p className="text-[11px] text-muted-foreground leading-snug line-clamp-2">{hint}</p>
      ) : null}
    </Card>
  );
}

function KpiSkeleton() {
  return (
    <Card className="h-full p-4 space-y-2">
      <Skeleton className="h-3 w-20" />
      <Skeleton className="h-7 w-24" />
      <Skeleton className="h-3 w-28" />
    </Card>
  );
}

function EmptyState({ children }: { children: React.ReactNode }) {
  return (
    <div className="py-12 flex flex-col items-center justify-center text-center space-y-2">
      <Badge variant="outline" className="text-muted-foreground">
        No data
      </Badge>
      <p className="text-sm text-muted-foreground max-w-xs">{children}</p>
    </div>
  );
}

function SimpleTable({ head, rows }: { head: string[]; rows: React.ReactNode[][] }) {
  return (
    <div className="overflow-x-auto">
      <table className="w-full text-sm">
        <thead>
          <tr className="border-b border-border text-start">
            {head.map((h) => (
              <th
                key={h}
                className="px-6 py-2 text-[11px] font-medium uppercase tracking-wider text-muted-foreground"
              >
                {h}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.map((cells, i) => (
            <tr key={i} className="border-b border-border/50 last:border-0">
              {cells.map((c, j) => (
                <td key={j} className="px-6 py-2 text-foreground">
                  {c}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}
