"use client";

import { useState } from "react";
import Link from "next/link";
import { ArrowDownRightIcon, ArrowUpRightIcon } from "lucide-react";
import { Line, LineChart } from "recharts";

import { Button } from "@/components/ui/button";
import { ChartContainer } from "@/components/ui/chart";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { Skeleton } from "@/components/ui/skeleton";
import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { formatDate, formatKES } from "@/lib/format";
import { cn } from "@/lib/utils";

import { pinClass, usePinnedScroll } from "../pinned-scroll";
import { StatusTag } from "../record-lists";

const money = "text-right tabular-nums";

/* ---------------------------------------------------------------- Stat tile */

export function Sparkline({ data, className }: { data: number[]; className?: string }) {
  const points = data.map((v, i) => ({ i, v }));
  return (
    <ChartContainer
      config={{ v: { label: "Value", color: "var(--chart-1)" } }}
      className={cn("aspect-auto h-10 w-full", className)}
      initialDimension={{ width: 160, height: 40 }}
    >
      <LineChart data={points} margin={{ top: 4, right: 2, bottom: 4, left: 2 }}>
        <Line dataKey="v" type="monotone" stroke="var(--color-v)" strokeWidth={1.5} dot={false} isAnimationActive={false} />
      </LineChart>
    </ChartContainer>
  );
}

export function StatTile({
  label,
  value,
  delta,
  deltaGoodWhen = "up",
  hint,
  trend,
  loading,
  error,
  href,
  linkLabel,
  status,
  onSelect,
}: {
  label: string;
  value: string;
  /** Percentage change versus the previous period. */
  delta?: number;
  /** Whether a rise is good (sales) or bad (expenses, overdue). Decides the delta colour. */
  deltaGoodWhen?: "up" | "down";
  hint?: string;
  trend?: number[];
  loading?: boolean;
  error?: string;
  /** Drill-down: opens the records behind the figure. */
  href?: string;
  linkLabel?: string;
  /** Count with status (DB-10): the badge beside the label, a word from the badge spec's status map ("Expiring"). */
  status?: string;
  /** Drill-down that opens the records on this page (a list dialog) instead of going to another page. */
  onSelect?: () => void;
}) {
  const good = delta === undefined ? true : deltaGoodWhen === "up" ? delta >= 0 : delta <= 0;
  const DeltaIcon = delta !== undefined && delta < 0 ? ArrowDownRightIcon : ArrowUpRightIcon;
  return (
    <div className="flex h-full flex-col rounded-lg border border-border bg-card p-3">
      <div className="flex items-start justify-between gap-2">
        <p className="text-xs text-muted-foreground">{label}</p>
        {status ? <StatusTag status={status} /> : null}
      </div>
      {loading ? (
        <div className="mt-2 space-y-2" aria-busy>
          <Skeleton className="h-7 w-28" />
          <Skeleton className="h-10 w-full" />
        </div>
      ) : error ? (
        <p className="mt-2 text-sm text-status-error-text">{error}</p>
      ) : (
        <>
          <p className="mt-1 text-2xl font-semibold tabular-nums text-foreground">{value}</p>
          <div className="mt-1 flex items-center gap-2 text-xs">
            {delta !== undefined ? (
              <span className={cn("inline-flex items-center gap-0.5 font-medium tabular-nums", good ? "text-status-success-text" : "text-status-error-text")}>
                <DeltaIcon className="size-3.5" aria-hidden />
                {Math.abs(delta).toFixed(1)}%
              </span>
            ) : null}
            {hint ? <span className="text-muted-foreground">{hint}</span> : null}
          </div>
          {trend ? <Sparkline data={trend} className="mt-2" /> : null}
        </>
      )}
      {href ? (
        <Link href={href} className="mt-auto pt-2 text-xs font-medium text-primary hover:underline">
          {linkLabel ?? "View the detail"}
        </Link>
      ) : onSelect ? (
        <button type="button" onClick={onSelect} className="mt-auto self-start pt-2 text-xs font-medium text-primary hover:underline">
          {linkLabel ?? "View the list"}
        </button>
      ) : null}
    </div>
  );
}

/* --------------------------------------------------------- Balance summary */

export function BalanceSummary({
  kind,
  balance,
  creditLimit,
  overdue,
  loading,
}: {
  kind: "receivable" | "payable";
  balance: number;
  /** Credit limit (customer) or supplier terms ceiling. Omit when none is set. */
  creditLimit?: number;
  overdue?: number;
  loading?: boolean;
}) {
  const label = kind === "receivable" ? "Owed by customer" : "Owed to supplier";
  const used = creditLimit ? Math.min(100, Math.round((balance / creditLimit) * 100)) : 0;
  const headroom = creditLimit ? creditLimit - balance : null;
  const over = headroom !== null && headroom < 0;
  const barTone = over ? "bg-status-error-fill" : used >= 80 ? "bg-status-warning-fill" : "bg-primary";
  return (
    <div className="rounded-lg border border-border bg-card p-3">
      <div className="flex items-baseline justify-between gap-2">
        <p className="text-xs text-muted-foreground">{label}</p>
        {overdue ? <p className="text-xs font-medium tabular-nums text-status-error-text">{formatKES(overdue)} overdue</p> : null}
      </div>
      {loading ? (
        <Skeleton className="mt-2 h-7 w-32" />
      ) : (
        <p className="mt-1 text-2xl font-semibold tabular-nums text-foreground">{formatKES(balance)}</p>
      )}
      {creditLimit ? (
        <div className="mt-3">
          <div
            role="progressbar"
            aria-valuemin={0}
            aria-valuemax={100}
            aria-valuenow={used}
            aria-label="Credit limit used"
            className="h-1.5 w-full overflow-hidden rounded-full bg-muted"
          >
            <div className={cn("h-full", barTone)} style={{ width: `${used}%` }} />
          </div>
          <div className="mt-1.5 flex justify-between text-xs tabular-nums text-muted-foreground">
            <span>
              {used}% of {formatKES(creditLimit)} limit
            </span>
            <span className={over ? "font-medium text-status-error-text" : ""}>
              {over ? `${formatKES(-(headroom ?? 0))} over limit` : `${formatKES(headroom ?? 0)} headroom`}
            </span>
          </div>
        </div>
      ) : (
        <p className="mt-3 text-xs text-muted-foreground">No credit limit set.</p>
      )}
    </div>
  );
}

/* ----------------------------------------------------------- Aging buckets */

export type AgingData = { current: number; d31to60: number; d61to90: number; over90: number };
const AGING: { key: keyof AgingData; label: string; cls: string }[] = [
  { key: "current", label: "Current (0-30)", cls: "" },
  { key: "d31to60", label: "31-60 days", cls: "" },
  { key: "d61to90", label: "61-90 days", cls: "text-status-warning-text" },
  { key: "over90", label: "Over 90 days", cls: "text-status-error-text" },
];

export function AgingBuckets({ data, loading }: { data: AgingData; loading?: boolean }) {
  const total = data.current + data.d31to60 + data.d61to90 + data.over90;
  return (
    <div className="overflow-hidden rounded-lg border border-border bg-card">
      <div className="grid grid-cols-2 divide-x divide-border sm:grid-cols-4">
        {AGING.map((b) => (
          <div key={b.key} className="p-3">
            <p className="text-xs text-muted-foreground">{b.label}</p>
            {loading ? (
              <Skeleton className="mt-1.5 h-5 w-20" />
            ) : (
              <p className={cn("mt-1 text-base font-semibold tabular-nums", data[b.key] > 0 ? b.cls : "text-muted-foreground")}>
                {formatKES(data[b.key])}
              </p>
            )}
            <p className="text-xs tabular-nums text-muted-foreground">{total ? Math.round((data[b.key] / total) * 100) : 0}%</p>
          </div>
        ))}
      </div>
    </div>
  );
}

/* --------------------------------------------------------- Statement table */

export type StatementRow = { date: string; ref: string; description: string; charge?: number; payment?: number };

/**
 * A statement with a running balance. `openingBalance` is the balance brought forward when the statement starts at
 * a date; a statement that covers the whole history starts from nothing, so it has no opening row.
 */
export function StatementTable({
  openingBalance,
  rows,
  chargeLabel = "Invoices",
  paymentLabel = "Receipts",
}: {
  openingBalance?: number;
  rows: StatementRow[];
  chargeLabel?: string;
  paymentLabel?: string;
}) {
  const lines = rows.reduce<(StatementRow & { running: number })[]>((acc, r) => {
    const prev = acc.length ? acc[acc.length - 1].running : (openingBalance ?? 0);
    return [...acc, { ...r, running: prev + (r.charge ?? 0) - (r.payment ?? 0) }];
  }, []);
  const running = lines.length ? lines[lines.length - 1].running : (openingBalance ?? 0);
  const charges = rows.reduce((s, r) => s + (r.charge ?? 0), 0);
  const payments = rows.reduce((s, r) => s + (r.payment ?? 0), 0);
  const pin = usePinnedScroll();
  return (
    // One white container (data table spec §1). The first column, Date, stays on the left while the rest scrolls
    // sideways (§1.3, the design system's wide-table pattern); the opening and closing labels sit in that pinned cell.
    <div {...pin} className="group/scroll overflow-auto rounded-md border border-[var(--color-border-panel)] bg-card [&_[data-slot=table-container]]:overflow-visible">
      <Table className="whitespace-nowrap">
        <TableHeader>
          <TableRow className="hover:bg-transparent">
            <TableHead className={pinClass("left", true)}>Date</TableHead>
            <TableHead>Reference</TableHead>
            <TableHead>Description</TableHead>
            <TableHead className={money}>{chargeLabel}</TableHead>
            <TableHead className={money}>{paymentLabel}</TableHead>
            <TableHead className={money}>Balance</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {openingBalance !== undefined ? (
            <TableRow className="group/row bg-muted/50">
              <TableCell className={cn("font-medium", pinClass("left"))}>Opening balance</TableCell>
              <TableCell colSpan={4} />
              <TableCell className={cn(money, "font-medium")}>{formatKES(openingBalance)}</TableCell>
            </TableRow>
          ) : null}
          {lines.map((r) => (
            <TableRow key={r.ref} className="group/row">
              <TableCell className={pinClass("left")}>{formatDate(r.date, { short: true })}</TableCell>
              <TableCell className="font-mono text-xs">{r.ref}</TableCell>
              <TableCell className="text-muted-foreground">{r.description}</TableCell>
              <TableCell className={money}>{r.charge ? formatKES(r.charge) : ""}</TableCell>
              <TableCell className={cn(money, "text-status-success-text")}>{r.payment ? formatKES(r.payment) : ""}</TableCell>
              <TableCell className={money}>{formatKES(r.running)}</TableCell>
            </TableRow>
          ))}
        </TableBody>
        <TableFooter>
          <TableRow className="group/row">
            <TableCell className={cn("font-medium", pinClass("left"))}>Closing balance</TableCell>
            <TableCell colSpan={2} />
            <TableCell className={cn(money, "font-medium")}>{formatKES(charges)}</TableCell>
            <TableCell className={cn(money, "font-medium")}>{formatKES(payments)}</TableCell>
            <TableCell className={cn(money, "font-semibold")}>{formatKES(running)}</TableCell>
          </TableRow>
        </TableFooter>
      </Table>
    </div>
  );
}

/* ----------------------------------------------------- Payment recording form */

export type PaymentFormStatus = "idle" | "submitting" | "error" | "disabled";

export function PaymentForm({
  party,
  outstanding,
  today,
  status = "idle",
  error,
  onSubmit,
}: {
  party: string;
  outstanding: number;
  today: string;
  status?: PaymentFormStatus;
  error?: string;
  onSubmit?: (p: { amount: number; method: string; reference: string; date: string }) => void;
}) {
  const [amount, setAmount] = useState(String(outstanding));
  const [method, setMethod] = useState("M-Pesa");
  const [reference, setReference] = useState("");
  const [date, setDate] = useState(today);
  const disabled = status === "disabled" || status === "submitting";
  const n = Number(amount);
  const invalid = !(n > 0);
  const id = `pay-${status}`;
  return (
    <form
      className="max-w-md space-y-3 rounded-lg border border-border bg-card p-4"
      onSubmit={(e) => {
        e.preventDefault();
        if (!invalid) onSubmit?.({ amount: n, method, reference, date });
      }}
    >
      <div>
        <h3 className="text-sm font-semibold text-foreground">Record payment</h3>
        <p className="text-xs text-muted-foreground">
          {party}, outstanding <span className="tabular-nums">{formatKES(outstanding)}</span>
        </p>
      </div>
      <div className="grid grid-cols-2 gap-3">
        <div className="space-y-1.5">
          <Label htmlFor={`${id}-amt`}>Amount (KES)</Label>
          <Input
            id={`${id}-amt`}
            inputMode="decimal"
            className="text-right tabular-nums"
            value={amount}
            onChange={(e) => setAmount(e.target.value)}
            disabled={disabled}
            aria-invalid={status === "error" || undefined}
          />
        </div>
        <div className="space-y-1.5">
          <Label htmlFor={`${id}-date`}>Date</Label>
          <Input id={`${id}-date`} type="date" value={date} onChange={(e) => setDate(e.target.value)} disabled={disabled} />
        </div>
        <div className="space-y-1.5">
          <Label htmlFor={`${id}-method`}>Method</Label>
          <NativeSelect id={`${id}-method`} className="w-full" value={method} onChange={(e) => setMethod(e.target.value)} disabled={disabled}>
            {["M-Pesa", "Cash", "Bank transfer", "Cheque"].map((m) => (
              <NativeSelectOption key={m} value={m}>
                {m}
              </NativeSelectOption>
            ))}
          </NativeSelect>
        </div>
        <div className="space-y-1.5">
          <Label htmlFor={`${id}-ref`}>Reference</Label>
          <Input id={`${id}-ref`} placeholder="e.g. SJK4F29LQ1" value={reference} onChange={(e) => setReference(e.target.value)} disabled={disabled} />
        </div>
      </div>
      {status === "error" && error ? (
        <p role="alert" className="text-xs text-status-error-text">
          {error}
        </p>
      ) : null}
      <div className="flex justify-end">
        <Button type="submit" size="sm" disabled={disabled || invalid}>
          {status === "submitting" ? "Recording..." : "Record payment"}
        </Button>
      </div>
    </form>
  );
}
