"use client";

import * as React from "react";
import Link from "next/link";
import { useRouter, usePathname } from "next/navigation";
import { toast } from "sonner";
import type { ColumnDef } from "@tanstack/react-table";
import { Pencil, Receipt, ReceiptText, Repeat, Trash2, RefreshCw } from "lucide-react";
import { cn } from "@/lib/utils";
import { PageHeader } from "@/components/ui/page-header";
import { Button } from "@/components/ui/button";
import { Input, Field, NativeSelect, Textarea } from "@/components/ui/input";
import { Checkbox } from "@/components/ui/primitives";
import { DataTable, FilterSelect } from "@/components/ui/data-table";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogFooter } from "@/components/ui/dialog";
import { useConfirm } from "@/components/ui/confirm";
import { KpiCard } from "@/components/ui/kpi-card";
import { Money } from "@/components/ui/money";
import { Card, CardHeader, CardContent } from "@/components/ui/card";
import { DonutChart, TrendChart, CHART_COLORS } from "@/components/ui/charts";
import { fmtDate, parseDay, startOfMonth, addMonths } from "@/lib/dates";
import { fmtMoney } from "@/lib/format";
import { PAYMENT_METHODS, PAYMENT_METHOD_LABEL } from "@/lib/domain";
import { createExpense, updateExpense, deleteExpense, generateRecurringExpenses, type ExpenseInput } from "@/lib/actions/expenses";

export interface ExpenseRow {
  id: string;
  code: string;
  date: string;
  description: string;
  amount: number;
  paymentMethod: string;
  vendor: string | null;
  isRecurring: boolean;
  recurrence: string | null;
  recurringParentId: string | null;
  notes: string | null;
  category: { id: string; name: string; key: string };
  apartment: { id: string; code: string } | null;
  addedBy: string;
}

export function ExpensesView({ expenses, categories, apartments, currency, perms, openNew, range, today }: { expenses: ExpenseRow[]; categories: { id: string; name: string; key: string }[]; apartments: { id: string; code: string; name: string }[]; currency: string; perms: { view: boolean; create: boolean; edit: boolean; delete: boolean }; openNew: boolean; range: { from: string; to: string }; today: string }) {
  const router = useRouter();
  const pathname = usePathname();
  const confirm = useConfirm();
  const [editing, setEditing] = React.useState<ExpenseRow | null | "new">(openNew ? "new" : null);
  const [category, setCategory] = React.useState("");
  const [apartment, setApartment] = React.useState("");
  const [recurringOnly, setRecurringOnly] = React.useState(false);
  const rows = expenses.filter((e) => (!category || e.category.id === category) && (!apartment || e.apartment?.id === apartment) && (!recurringOnly || e.isRecurring));

  const monthStart = startOfMonth(parseDay(today));
  const thisMonth = expenses.filter((e) => parseDay(e.date) >= monthStart);
  const prevMonth = expenses.filter((e) => parseDay(e.date) >= addMonths(monthStart, -1) && parseDay(e.date) < monthStart);
  const sum = (xs: ExpenseRow[]) => xs.reduce((s, e) => s + e.amount, 0);
  const byCat = categories.map((c) => ({ name: c.name, value: sum(rows.filter((e) => e.category.id === c.id)) })).filter((x) => x.value > 0).sort((a, b) => b.value - a.value);
  const months = Array.from({ length: 6 }, (_, i) => {
    const s = addMonths(monthStart, i - 5);
    const e = addMonths(s, 1);
    return { label: s.toLocaleString("en", { month: "short", timeZone: "UTC" }), expenses: sum(expenses.filter((x) => parseDay(x.date) >= s && parseDay(x.date) < e)) };
  });

  async function remove(e: ExpenseRow) {
    const { ok, reason } = await confirm({ title: `Delete ${e.code}?`, description: `${e.description} · ${fmtMoney(e.amount, currency)}`, destructive: true, requireReason: true, confirmLabel: "Delete", consequences: ["Financial reports are recalculated.", "The deletion is written to the audit log."] });
    if (!ok) return;
    const res = await deleteExpense(e.id, reason ?? "");
    if (!res.ok) return toast.error(res.error);
    toast.success("Expense deleted");
    router.refresh();
  }
  async function generate() {
    const res = await generateRecurringExpenses();
    if (!res.ok) return toast.error(res.error);
    toast.success(res.data.created ? `${res.data.created} recurring expense${res.data.created > 1 ? "s" : ""} created` : "Recurring expenses are up to date");
    router.refresh();
  }

  const cols = React.useMemo<ColumnDef<ExpenseRow, unknown>[]>(
    () => [
      { accessorKey: "date", header: "Date", cell: ({ row }) => <span className="whitespace-nowrap text-xs">{fmtDate(parseDay(row.original.date))}</span> },
      {
        accessorKey: "description",
        header: "Expense",
        cell: ({ row }) => (
          <div className="min-w-0">
            <span className="flex items-center gap-1.5 text-sm font-medium">
              {row.original.description}
              {row.original.isRecurring ? <Repeat className="size-3 text-fg-subtle" aria-label="Recurring" /> : null}
            </span>
            <span className="block text-2xs text-fg-subtle">
              {row.original.code}
              {row.original.vendor ? ` · ${row.original.vendor}` : ""}
            </span>
          </div>
        ),
      },
      { id: "category", accessorFn: (r) => r.category.name, header: "Category", cell: ({ row }) => <span className="rounded-full bg-surface-2 px-2 py-0.5 text-xs">{row.original.category.name}</span> },
      { id: "apartment", accessorFn: (r) => r.apartment?.code ?? "", header: "Apartment", cell: ({ row }) => (row.original.apartment ? <Link href={`/apartments/${row.original.apartment.id}`} className="font-mono text-xs font-semibold hover:text-primary">{row.original.apartment.code}</Link> : <span className="text-xs text-fg-subtle">General</span>) },
      { accessorKey: "paymentMethod", header: "Method", cell: ({ row }) => <span className="text-xs text-fg-muted">{PAYMENT_METHOD_LABEL[row.original.paymentMethod as keyof typeof PAYMENT_METHOD_LABEL] ?? row.original.paymentMethod}</span> },
      { accessorKey: "amount", header: "Amount", meta: { align: "right" }, cell: ({ row }) => <Money value={row.original.amount} currency={currency} className="font-semibold" /> },
      { accessorKey: "addedBy", header: "Added by", cell: ({ row }) => <span className="text-xs text-fg-muted">{row.original.addedBy}</span> },
      ...(perms.edit || perms.delete
        ? [
            {
              id: "actions",
              header: "",
              enableHiding: false,
              cell: ({ row }: { row: { original: ExpenseRow } }) => (
                <span className="flex justify-end gap-0.5" onClick={(e) => e.stopPropagation()}>
                  {perms.edit ? (
                    <Button variant="ghost" size="iconXs" onClick={() => setEditing(row.original)} aria-label="Edit">
                      <Pencil />
                    </Button>
                  ) : null}
                  {perms.delete ? (
                    <Button variant="ghost" size="iconXs" className="text-negative-600" onClick={() => remove(row.original)} aria-label="Delete">
                      <Trash2 />
                    </Button>
                  ) : null}
                </span>
              ),
            } as ColumnDef<ExpenseRow, unknown>,
          ]
        : []),
    ],
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [currency, perms.edit, perms.delete]
  );

  return (
    <div className="space-y-4">
      <PageHeader
        title="Expenses"
        description={perms.view ? "Operating costs by category and apartment. Recurring expenses generate monthly occurrences." : "Expenses you recorded."}
        actions={
          <>
            {perms.create && perms.view ? (
              <Button variant="secondary" onClick={generate}>
                <RefreshCw /> Generate recurring
              </Button>
            ) : null}
            {perms.create ? (
              <Button onClick={() => setEditing("new")}>
                <ReceiptText /> Add expense
              </Button>
            ) : null}
          </>
        }
      />
      {perms.view ? (
        <>
          <div className="grid grid-cols-2 gap-3 md:grid-cols-4">
            <KpiCard compact label="This month" value={fmtMoney(sum(thisMonth), currency, { compact: true })} delta={prevMonth.length ? Math.round(((sum(thisMonth) - sum(prevMonth)) / sum(prevMonth)) * 1000) / 10 : null} invert deltaLabel="vs last month" icon={Receipt} tone="warning" />
            <KpiCard compact label="Last month" value={fmtMoney(sum(prevMonth), currency, { compact: true })} />
            <KpiCard compact label="Recurring / month" value={fmtMoney(sum(expenses.filter((e) => e.isRecurring && e.recurrence === "MONTHLY" && parseDay(e.date) >= addMonths(monthStart, -1))), currency, { compact: true })} icon={Repeat} hint="Sum of recurring monthly expenses in the last month." />
            <KpiCard compact label="Entries in range" value={rows.length} />
          </div>
          <div className="grid gap-4 lg:grid-cols-3">
            <Card className="lg:col-span-2">
              <CardHeader title="Monthly expenses" description="Last 6 months" />
              <CardContent>
                <TrendChart data={months} type="bar" series={[{ key: "expenses", name: "Expenses", color: CHART_COLORS.gold }]} height={200} />
              </CardContent>
            </Card>
            <Card>
              <CardHeader title="By category" description="Current selection" />
              <CardContent>
                <DonutChart data={byCat.slice(0, 7)} money height={170} centerValue={fmtMoney(sum(rows), currency, { compact: true })} centerLabel="total" />
              </CardContent>
            </Card>
          </div>
        </>
      ) : null}
      <DataTable
        columns={cols}
        data={rows}
        globalFilterFn={(r, q) => [r.description, r.vendor ?? "", r.code, r.category.name, r.apartment?.code ?? ""].join(" ").toLowerCase().includes(q)}
        searchPlaceholder="Description, vendor, code…"
        exportName={perms.view ? "expenses" : undefined}
        initialSorting={[{ id: "date", desc: true }]}
        emptyTitle="No expenses in this period"
        emptyDescription="Record electricity, cleaning, maintenance and other operating costs to see real profitability."
        emptyAction={perms.create ? <Button size="sm" onClick={() => setEditing("new")}>Add expense</Button> : undefined}
        onRowClick={perms.edit ? (r) => setEditing(r) : undefined}
        toolbar={
          <>
            <FilterSelect value={category} onChange={setCategory} placeholder="All categories" options={categories.map((c) => ({ value: c.id, label: c.name }))} />
            <FilterSelect value={apartment} onChange={setApartment} placeholder="All apartments" options={[{ value: "", label: "All apartments" }, ...apartments.map((a) => ({ value: a.id, label: `${a.code} · ${a.name}` }))].slice(1)} />
            <div className="flex items-center gap-1">
              <Input type="date" defaultValue={range.from} onChange={(e) => router.replace(`${pathname}?from=${e.target.value}&to=${range.to}`)} className="h-9 w-[140px] text-xs" aria-label="From" />
              <span className="text-xs text-fg-subtle">→</span>
              <Input type="date" defaultValue={range.to} onChange={(e) => router.replace(`${pathname}?from=${range.from}&to=${e.target.value}`)} className="h-9 w-[140px] text-xs" aria-label="To" />
            </div>
            <label className="flex items-center gap-1.5 text-xs text-fg-muted">
              <Checkbox checked={recurringOnly} onCheckedChange={(v) => setRecurringOnly(!!v)} /> Recurring only
            </label>
          </>
        }
        mobileCard={(e) => (
          <div className={cn("flex items-center gap-3 rounded-lg border border-border bg-surface p-3", perms.edit && "cursor-pointer")}>
            <span className="flex size-9 shrink-0 items-center justify-center rounded-md bg-surface-2 text-fg-muted">
              <Receipt className="size-4" />
            </span>
            <span className="min-w-0 flex-1">
              <span className="block truncate text-sm font-medium">{e.description}</span>
              <span className="block text-xs text-fg-muted">
                {e.category.name} · {e.apartment?.code ?? "General"} · {fmtDate(parseDay(e.date), { style: "short" })}
              </span>
            </span>
            <Money value={e.amount} currency={currency} className="font-semibold" />
          </div>
        )}
      />
      <Dialog open={!!editing} onOpenChange={(o) => !o && setEditing(null)}>
        <DialogContent size="md">{editing ? <ExpenseDialog expense={editing === "new" ? null : editing} categories={categories} apartments={apartments} currency={currency} today={today} onClose={() => setEditing(null)} /> : null}</DialogContent>
      </Dialog>
    </div>
  );
}

function ExpenseDialog({ expense, categories, apartments, currency, today, onClose }: { expense: ExpenseRow | null; categories: { id: string; name: string }[]; apartments: { id: string; code: string; name: string }[]; currency: string; today: string; onClose: () => void }) {
  const router = useRouter();
  const [busy, setBusy] = React.useState(false);
  const [f, setF] = React.useState({ date: expense?.date ?? today, categoryId: expense?.category.id ?? categories[0]?.id ?? "", apartmentId: expense?.apartment?.id ?? "", description: expense?.description ?? "", amount: expense ? String(expense.amount) : "", paymentMethod: expense?.paymentMethod ?? "CASH", vendor: expense?.vendor ?? "", isRecurring: expense?.isRecurring ?? false, recurrence: expense?.recurrence ?? "MONTHLY", notes: expense?.notes ?? "" });
  const upd = <K extends keyof typeof f>(k: K, v: (typeof f)[K]) => setF((s) => ({ ...s, [k]: v }));
  async function submit() {
    setBusy(true);
    const payload: ExpenseInput = { ...f, amount: Number(f.amount), apartmentId: f.apartmentId || null, vendor: f.vendor || null, notes: f.notes || null, paymentMethod: f.paymentMethod as ExpenseInput["paymentMethod"], recurrence: f.isRecurring ? (f.recurrence as "WEEKLY" | "MONTHLY" | "YEARLY") : null };
    const res = expense ? await updateExpense(expense.id, payload) : await createExpense(payload);
    setBusy(false);
    if (!res.ok) return toast.error(res.error);
    toast.success(expense ? "Expense updated" : "Expense added");
    onClose();
    router.refresh();
  }
  return (
    <>
      <DialogHeader>
        <DialogTitle>{expense ? `Edit ${expense.code}` : "Add expense"}</DialogTitle>
      </DialogHeader>
      <DialogBody className="grid gap-4 sm:grid-cols-2">
        <Field label="Description" required className="sm:col-span-2">
          <Input value={f.description} onChange={(e) => upd("description", e.target.value)} autoFocus placeholder="Electricity — A03, Laundry, Plumber…" />
        </Field>
        <Field label="Amount" required>
          <Input type="number" min={0} step="1" inputMode="decimal" value={f.amount} onChange={(e) => upd("amount", e.target.value)} suffix={currency} />
        </Field>
        <Field label="Date" required>
          <Input type="date" value={f.date} onChange={(e) => upd("date", e.target.value)} />
        </Field>
        <Field label="Category" required>
          <NativeSelect value={f.categoryId} onChange={(e) => upd("categoryId", e.target.value)}>
            {categories.map((c) => (
              <option key={c.id} value={c.id}>
                {c.name}
              </option>
            ))}
          </NativeSelect>
        </Field>
        <Field label="Apartment" hint="Leave empty for general costs">
          <NativeSelect value={f.apartmentId} onChange={(e) => upd("apartmentId", e.target.value)}>
            <option value="">General (whole business)</option>
            {apartments.map((a) => (
              <option key={a.id} value={a.id}>
                {a.code} · {a.name}
              </option>
            ))}
          </NativeSelect>
        </Field>
        <Field label="Payment method">
          <NativeSelect value={f.paymentMethod} onChange={(e) => upd("paymentMethod", e.target.value)}>
            {PAYMENT_METHODS.map((m) => (
              <option key={m} value={m}>
                {PAYMENT_METHOD_LABEL[m]}
              </option>
            ))}
          </NativeSelect>
        </Field>
        <Field label="Vendor">
          <Input value={f.vendor} onChange={(e) => upd("vendor", e.target.value)} placeholder="Lydec, Orange, Marjane…" />
        </Field>
        <div className="flex items-center gap-3 sm:col-span-2">
          <label className="flex items-center gap-2 text-sm">
            <Checkbox checked={f.isRecurring} onCheckedChange={(v) => upd("isRecurring", !!v)} /> Recurring
          </label>
          {f.isRecurring ? (
            <NativeSelect value={f.recurrence} onChange={(e) => upd("recurrence", e.target.value)} className="w-36">
              <option value="WEEKLY">Weekly</option>
              <option value="MONTHLY">Monthly</option>
              <option value="YEARLY">Yearly</option>
            </NativeSelect>
          ) : null}
        </div>
        <Field label="Notes" className="sm:col-span-2">
          <Textarea value={f.notes} onChange={(e) => upd("notes", e.target.value)} rows={2} />
        </Field>
      </DialogBody>
      <DialogFooter>
        <Button variant="secondary" onClick={onClose}>
          Cancel
        </Button>
        <Button loading={busy} disabled={!f.description.trim() || !(Number(f.amount) > 0) || !f.categoryId} onClick={submit}>
          {expense ? "Save" : "Add expense"}
        </Button>
      </DialogFooter>
    </>
  );
}
