"use client";

import { useMemo, useState } from "react";
import {
  flexRender,
  getCoreRowModel,
  useReactTable,
  type ColumnDef,
} from "@tanstack/react-table";
import { motion } from "framer-motion";
import { Check, Trash2 } from "lucide-react";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import type { LedgerRow } from "@/lib/recurring";
import type { BankAccount, Category } from "@/db/schema";
import { cn, formatMoney } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { addTransactionAction, deleteTransactionAction, markPostedAction } from "./actions";

const RANGES = [
  { v: "1", l: "1m" },
  { v: "3", l: "3m" },
  { v: "6", l: "6m" },
  { v: "12", l: "1y" },
];

export function LedgerTable({
  rows,
  accounts,
  categories,
  selectedAccountId,
  range,
}: {
  rows: LedgerRow[];
  accounts: BankAccount[];
  categories: Category[];
  selectedAccountId?: string;
  range: string;
}) {
  const router = useRouter();
  const sp = useSearchParams();
  const today = new Date().toISOString().slice(0, 10);
  const accountMap = useMemo(() => new Map(accounts.map((a) => [a.id, a])), [accounts]);
  const catMap = useMemo(() => new Map(categories.map((c) => [c.id, c])), [categories]);

  const columns = useMemo<ColumnDef<LedgerRow>[]>(
    () => [
      {
        id: "date",
        header: "Date",
        cell: ({ row }) => {
          const r = row.original;
          const isToday = r.date === today;
          return (
            <div className="flex items-center gap-2">
              <span className={cn("font-mono text-xs", isToday ? "text-primary font-semibold" : "text-muted-foreground")}>
                {isToday ? "TODAY" : r.date}
              </span>
            </div>
          );
        },
      },
      {
        id: "type",
        header: "Type",
        cell: ({ row }) => {
          const r = row.original;
          const income = r.amountMinor > 0;
          return (
            <Badge variant={income ? "success" : "warning"} className="text-[10px] uppercase tracking-wide">
              {income ? "In" : "Out"}
            </Badge>
          );
        },
      },
      {
        id: "description",
        header: "Description",
        cell: ({ row }) => {
          const r = row.original;
          const acct = accountMap.get(r.bankAccountId);
          const cat = r.categoryId ? catMap.get(r.categoryId) : null;
          return (
            <div className="min-w-0">
              <div className="font-medium truncate">{r.description}</div>
              <div className="text-xs text-muted-foreground truncate">
                {acct?.name}
                {cat ? ` · ${cat.name}` : ""}
              </div>
            </div>
          );
        },
      },
      {
        id: "in",
        header: () => <div className="text-right">In</div>,
        cell: ({ row }) => {
          const r = row.original;
          if (r.amountMinor <= 0) return <div />;
          return (
            <div className="text-right font-mono tabular text-success">
              {formatMoney(r.amountMinor)}
            </div>
          );
        },
      },
      {
        id: "out",
        header: () => <div className="text-right">Out</div>,
        cell: ({ row }) => {
          const r = row.original;
          if (r.amountMinor >= 0) return <div />;
          return (
            <div className="text-right font-mono tabular text-destructive">
              {formatMoney(Math.abs(r.amountMinor))}
            </div>
          );
        },
      },
      {
        id: "balance",
        header: () => <div className="text-right">Balance</div>,
        cell: ({ row }) => (
          <div className="text-right font-mono tabular font-medium">
            {formatMoney(row.original.runningBalanceMinor)}
          </div>
        ),
      },
      {
        id: "actions",
        header: "",
        cell: ({ row }) => {
          const r = row.original;
          if (r.status === "projected") {
            return (
              <form action={markPostedAction}>
                <input type="hidden" name="id" value={r.id} />
                <input type="hidden" name="date" value={r.date} />
                <input type="hidden" name="bankAccountId" value={r.bankAccountId} />
                <input type="hidden" name="description" value={r.description} />
                <input type="hidden" name="amount" value={r.amountMinor / 100} />
                <input type="hidden" name="categoryId" value={r.categoryId ?? ""} />
                <input type="hidden" name="recurringRuleId" value={r.recurringRuleId ?? ""} />
                <Button type="submit" size="icon" variant="ghost" title="Mark as posted">
                  <Check className="size-4" />
                </Button>
              </form>
            );
          }
          return (
            <form action={deleteTransactionAction}>
              <input type="hidden" name="id" value={r.id} />
              <Button type="submit" size="icon" variant="ghost" className="text-muted-foreground hover:text-destructive">
                <Trash2 className="size-4" />
              </Button>
            </form>
          );
        },
      },
    ],
    [accountMap, catMap, today],
  );

  const table = useReactTable({ data: rows, columns, getCoreRowModel: getCoreRowModel() });

  const setQuery = (key: string, value: string | undefined) => {
    const params = new URLSearchParams(sp.toString());
    if (value) params.set(key, value);
    else params.delete(key);
    router.push(`/ledger?${params.toString()}`);
  };

  return (
    <div className="space-y-4">
      <div className="flex flex-wrap gap-3 items-center justify-between">
        <div className="flex gap-2 items-center">
          <select
            value={selectedAccountId ?? ""}
            onChange={(e) => setQuery("account", e.target.value || undefined)}
            className="h-9 rounded-md border bg-input/40 px-2 text-sm"
          >
            <option value="">All accounts</option>
            {accounts.map((a) => (
              <option key={a.id} value={a.id}>{a.name}</option>
            ))}
          </select>
          <div className="flex rounded-md border bg-input/40 overflow-hidden">
            {RANGES.map((r) => (
              <Link
                key={r.v}
                href={`/ledger?${new URLSearchParams({ ...(selectedAccountId ? { account: selectedAccountId } : {}), range: r.v }).toString()}`}
                className={cn(
                  "px-3 h-9 grid place-items-center text-xs",
                  r.v === range ? "bg-primary/20 text-primary" : "text-muted-foreground hover:text-foreground",
                )}
              >
                {r.l}
              </Link>
            ))}
          </div>
        </div>
      </div>

      <AddTransactionForm accounts={accounts} categories={categories} defaultAccountId={selectedAccountId ?? accounts[0]?.id} />

      <div className="rounded-md border overflow-x-auto">
        <table className="w-full text-sm">
          <thead className="bg-muted/40">
            {table.getHeaderGroups().map((hg) => (
              <tr key={hg.id}>
                {hg.headers.map((h) => (
                  <th key={h.id} className="text-left font-medium px-4 py-2 text-xs uppercase tracking-wide text-muted-foreground">
                    {flexRender(h.column.columnDef.header, h.getContext())}
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody>
            {table.getRowModel().rows.map((row, i) => {
              const r = row.original;
              const projected = r.status === "projected";
              const income = r.amountMinor > 0;
              const isToday = r.date === today;
              return (
                <motion.tr
                  key={r.id}
                  initial={{ opacity: 0, y: 4 }}
                  animate={{ opacity: 1, y: 0 }}
                  transition={{ delay: Math.min(i * 0.005, 0.2) }}
                  className={cn(
                    "border-t border-border/50",
                    projected && "opacity-70",
                    isToday && "bg-primary/5",
                    income && !projected && "bg-success/5",
                  )}
                  style={projected ? { borderStyle: "dashed" } : undefined}
                >
                  {row.getVisibleCells().map((c) => (
                    <td key={c.id} className="px-4 py-2 align-middle">
                      {flexRender(c.column.columnDef.cell, c.getContext())}
                    </td>
                  ))}
                </motion.tr>
              );
            })}
            {rows.length === 0 ? (
              <tr>
                <td colSpan={7} className="text-center text-sm text-muted-foreground py-12">
                  No transactions in this range.
                </td>
              </tr>
            ) : null}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function AddTransactionForm({
  accounts,
  categories,
  defaultAccountId,
}: {
  accounts: BankAccount[];
  categories: Category[];
  defaultAccountId?: string;
}) {
  const [open, setOpen] = useState(false);
  const today = new Date().toISOString().slice(0, 10);
  if (!open) {
    return (
      <Button variant="outline" size="sm" onClick={() => setOpen(true)}>
        + Add transaction
      </Button>
    );
  }
  return (
    <form
      action={addTransactionAction}
      className="grid grid-cols-2 sm:grid-cols-[140px_1fr_140px_160px_120px_auto] gap-2 items-end rounded-md border bg-card/40 p-3"
    >
      <div className="space-y-1">
        <label className="text-xs text-muted-foreground">Date</label>
        <Input type="date" name="date" defaultValue={today} required />
      </div>
      <div className="space-y-1">
        <label className="text-xs text-muted-foreground">Description</label>
        <Input name="description" placeholder="Tesco shop" required />
      </div>
      <div className="space-y-1">
        <label className="text-xs text-muted-foreground">Account</label>
        <select name="bankAccountId" defaultValue={defaultAccountId} className="h-9 w-full rounded-md border bg-input/40 px-2 text-sm">
          {accounts.map((a) => <option key={a.id} value={a.id}>{a.name}</option>)}
        </select>
      </div>
      <div className="space-y-1">
        <label className="text-xs text-muted-foreground">Category</label>
        <select name="categoryId" className="h-9 w-full rounded-md border bg-input/40 px-2 text-sm">
          <option value="">— None —</option>
          {categories.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}
        </select>
      </div>
      <div className="space-y-1">
        <label className="text-xs text-muted-foreground">Amount (signed)</label>
        <Input type="number" step="0.01" name="amount" placeholder="-9.99" required />
      </div>
      <div className="flex gap-2">
        <Button type="submit">Save</Button>
        <Button type="button" variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
      </div>
    </form>
  );
}
