"use client";

import { adminMutationJson } from "@/app/customer/_lib/admin/admin-client-fetch";
import { toastApiError } from "@/lib/toast-api-error";
import * as React from "react";
import { Loader2, Pencil, Plus, Save, Trash2 } from "lucide-react";
import { toast } from "sonner";

import { AdminListSearchInput } from "@/app/customer/[tenant]/admin/_components/admin-list-shell";
import { useAdminListQuery } from "@/app/customer/[tenant]/admin/_components/use-admin-list-query";
import { BankSetupHeader } from "@/app/customer/[tenant]/admin/_components/bank-setup-tabs";
import { LinkedAccountsSheet } from "@/app/customer/[tenant]/admin/parent-banks/_components/linked-accounts-sheet";
import { adminPaths } from "@/app/customer/_lib/admin/admin-paths";
import type {
  PortalParentBankRow,
  PortalStatusOption,
} from "@/app/customer/_lib/admin/parent-banks-server-api";
import { AI_STATUS_OPTIONS, normalizeActiveStatus } from "@/config/status";
import { customerCsrfHeader } from "@/lib/customer-csrf.client";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Sheet,
  SheetClose,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetTitle,
} from "@/components/ui/sheet";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import type { CustomerPortalCapabilities } from "@/lib/frontend-auth/report-capabilities";

type ParentBanksPageClientProps = {
  tenant: string;
  initialItems: PortalParentBankRow[];
  initialStatusOptions: PortalStatusOption[];
  initialErrorMessage: string | null;
  catalogAvailable: boolean;
  canManage: boolean;
  capabilities?: CustomerPortalCapabilities | null;
  initialQ?: string;
};

type FormState = {
  id: number;
  parentName: string;
  status: "A" | "I";
  sortOrder: string;
  jurisdiction: string;
};

const DEFAULT_STATUS_OPTIONS: PortalStatusOption[] = AI_STATUS_OPTIONS;

function assignedCountOf(row: { assignedCount?: number }): number {
  return Number.isFinite(row.assignedCount) ? Math.max(0, row.assignedCount ?? 0) : 0;
}

function emptyForm(): FormState {
  return {
    id: 0,
    parentName: "",
    status: "A",
    sortOrder: "0",
    jurisdiction: "",
  };
}

function toForm(row: PortalParentBankRow): FormState {
  return {
    id: row.id,
    parentName: row.parentName,
    status: normalizeActiveStatus(row.status),
    sortOrder: String(row.sortOrder ?? 0),
    jurisdiction: row.jurisdiction ?? "",
  };
}

function ParentBanksTable({
  rows,
  emptyMessage,
  showLinkedAccounts,
  canManage,
  deletingId,
  onEdit,
  onDelete,
  onLinkedAccounts,
}: {
  rows: PortalParentBankRow[];
  emptyMessage: string;
  showLinkedAccounts: boolean;
  canManage: boolean;
  deletingId: number | null;
  onEdit: (row: PortalParentBankRow) => void;
  onDelete: (row: PortalParentBankRow) => void;
  onLinkedAccounts: (row: PortalParentBankRow) => void;
}) {
  const colSpan = showLinkedAccounts ? 6 : 5;

  return (
    <div className="rounded-md border">
      <Table>
        <TableHeader>
          <TableRow className="bg-muted/40 hover:bg-muted/40">
            <TableHead className="px-3">Parent name</TableHead>
            <TableHead className="px-3">Jurisdiction</TableHead>
            <TableHead className="px-3">Status</TableHead>
            <TableHead className="px-3 text-center">Sort order</TableHead>
            {showLinkedAccounts ? (
              <TableHead className="px-3 text-center">Linked accounts</TableHead>
            ) : null}
            <TableHead className="px-3 text-right">Actions</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {rows.length ? (
            rows.map((row) => (
              <TableRow key={row.id}>
                <TableCell className="px-3 py-2.5 font-medium">{row.parentName}</TableCell>
                <TableCell className="px-3 py-2.5">
                  {row.jurisdiction?.trim() ? (
                    row.jurisdiction
                  ) : (
                    <span className="text-muted-foreground">—</span>
                  )}
                </TableCell>
                <TableCell className="px-3 py-2.5">
                  <Badge variant={row.status === "A" ? "secondary" : "outline"}>
                    {row.status === "A" ? "Active" : "Inactive"}
                  </Badge>
                </TableCell>
                <TableCell className="px-3 py-2.5 text-center text-muted-foreground">
                  {row.sortOrder}
                </TableCell>
                {showLinkedAccounts ? (
                  <TableCell className="px-3 py-2.5 text-center">
                    {assignedCountOf(row) > 0 ? (
                      <button
                        type="button"
                        className="font-medium text-primary underline-offset-2 hover:underline"
                        onClick={() => onLinkedAccounts(row)}
                      >
                        {assignedCountOf(row)}
                      </button>
                    ) : (
                      <span className="text-muted-foreground">0</span>
                    )}
                  </TableCell>
                ) : null}
                <TableCell className="px-3 py-2.5 text-right">
                  <div className="inline-flex items-center gap-1">
                    <Button
                      type="button"
                      size="sm"
                      variant="outline"
                      onClick={() => onEdit(row)}
                    >
                      <Pencil className="size-3.5" />
                      {canManage ? "Edit" : "View"}
                    </Button>
                    {canManage ? (
                      <Button
                        type="button"
                        size="sm"
                        variant="ghost"
                        className="text-muted-foreground hover:text-destructive"
                        disabled={deletingId === row.id}
                        onClick={() => onDelete(row)}
                      >
                        {deletingId === row.id ? (
                          <Loader2 className="size-3.5 animate-spin" />
                        ) : (
                          <Trash2 className="size-3.5" />
                        )}
                      </Button>
                    ) : null}
                  </div>
                </TableCell>
              </TableRow>
            ))
          ) : (
            <TableRow>
              <TableCell colSpan={colSpan} className="h-24 text-center text-muted-foreground">
                {emptyMessage}
              </TableCell>
            </TableRow>
          )}
        </TableBody>
      </Table>
    </div>
  );
}

export function ParentBanksPageClient({
  tenant,
  initialItems,
  initialStatusOptions,
  initialErrorMessage,
  catalogAvailable,
  canManage,
  capabilities,
  initialQ = "",
}: ParentBanksPageClientProps) {
  const paths = adminPaths(tenant);
  // Catalog is small — URL search via useAdminListQuery; filter stays client-side.
  const pagination = {
    page: 1,
    pageSize: Math.max(initialItems.length, 1),
    totalCount: initialItems.length,
    pageCount: 1,
  };
  const { searchInput, setSearchInput, isPending } = useAdminListQuery({
    initialQ,
    pagination,
  });
  const [rows, setRows] = React.useState(initialItems);
  const [sheetOpen, setSheetOpen] = React.useState(false);
  const [form, setForm] = React.useState<FormState>(emptyForm());
  const [isSaving, setIsSaving] = React.useState(false);
  const [deletingId, setDeletingId] = React.useState<number | null>(null);
  const [linkedSheetOpen, setLinkedSheetOpen] = React.useState(false);
  const [linkedParent, setLinkedParent] = React.useState<PortalParentBankRow | null>(null);
  const statusOptions =
    initialStatusOptions.length > 0 ? initialStatusOptions : DEFAULT_STATUS_OPTIONS;

  const filtered = React.useMemo(() => {
    const q = searchInput.trim().toLowerCase();
    if (!q) return rows;
    return rows.filter((row) =>
      [row.parentName, row.jurisdiction ?? "", row.status, String(row.id), String(row.sortOrder)]
        .join(" ")
        .toLowerCase()
        .includes(q),
    );
  }, [rows, searchInput]);

  const openCreate = () => {
    setForm(emptyForm());
    setSheetOpen(true);
  };

  const openEdit = (row: PortalParentBankRow) => {
    setForm(toForm(row));
    setSheetOpen(true);
  };

  const openLinkedAccounts = (row: PortalParentBankRow) => {
    setLinkedParent(row);
    setLinkedSheetOpen(true);
  };

  const handleSave = async () => {
    if (!canManage) return;
    const parentName = form.parentName.trim();
    if (!parentName) {
      toast.error("Parent name is required.");
      return;
    }

    setIsSaving(true);
    try {
      const result = await adminMutationJson<{
        status?: string;
        message?: string;
        item?: PortalParentBankRow | null;
      }>(
        paths.parentBanksSave(),
        {
          method: "POST",
          headers: {
            Accept: "application/json",
            "Content-Type": "application/json",
            ...customerCsrfHeader(tenant),
          },
          body: JSON.stringify({
            id: form.id > 0 ? form.id : undefined,
            parentName,
            status: form.status,
            sortOrder: Number(form.sortOrder) || 0,
            jurisdiction: form.jurisdiction.trim(),
          }),
        },
        "Failed to save parent bank.",
      );
      const data = result.data;
      if (!result.ok || !data?.item) {
        return;
      }

      const existing = rows.find((row) => row.id === form.id);
      const previousCount = existing ? assignedCountOf(existing) : 0;
      const saved: PortalParentBankRow = {
        ...data.item,
        assignedCount: Number.isFinite(data.item.assignedCount)
          ? Math.max(0, data.item.assignedCount)
          : previousCount,
      };
      setRows((prev) => {
        const exists = prev.some((row) => row.id === saved.id);
        const next = exists
          ? prev.map((row) => (row.id === saved.id ? saved : row))
          : [...prev, saved];
        return [...next].sort((a, b) => {
          if (a.sortOrder !== b.sortOrder) return b.sortOrder - a.sortOrder;
          return a.parentName.localeCompare(b.parentName);
        });
      });
      toast.success(data.message ?? "Parent bank saved successfully.");
      setSheetOpen(false);
    } catch (error) {
      toastApiError(error, "Failed to save parent bank.");
    } finally {
      setIsSaving(false);
    }
  };

  const handleDelete = async (row: PortalParentBankRow) => {
    if (!canManage) return;
    if (!window.confirm(`Delete parent bank “${row.parentName}”?`)) return;

    setDeletingId(row.id);
    const result = await adminMutationJson(
      paths.parentBanksDelete(),
      {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
          ...customerCsrfHeader(tenant),
        },
        body: JSON.stringify({ id: row.id }),
      },
      "Failed to delete parent bank.",
    );
    if (result.ok) {
      setRows((prev) => prev.filter((item) => item.id !== row.id));
      toast.success(result.message ?? "Parent bank deleted successfully.");
    }
    setDeletingId(null);
  };

  return (
    <>
      <div className={`flex flex-col gap-4${isPending ? " opacity-70" : ""}`}>
        <BankSetupHeader
          tenant={tenant}
          active="parent-banks"
          capabilities={capabilities}
          action={
            canManage && catalogAvailable ? (
              <Button type="button" onClick={openCreate}>
                <Plus className="size-4" />
                Create parent bank
              </Button>
            ) : null
          }
        />

        <div className="flex flex-wrap items-center justify-between gap-x-6 gap-y-2">
          <p className="text-sm text-muted-foreground">
            Catalog of parent banks used when linking customer bank accounts.
          </p>
          <AdminListSearchInput
            value={searchInput}
            onChange={setSearchInput}
            placeholder="Search parent banks"
            aria-label="Search parent banks"
            className="relative w-full sm:w-80"
            inputClassName="pl-8"
          />
        </div>

        {initialErrorMessage ? (
          <p className="rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2 text-sm text-destructive">
            {initialErrorMessage}
          </p>
        ) : null}

        {!catalogAvailable && !initialErrorMessage ? (
          <p className="rounded-md border border-amber-500/30 bg-amber-500/5 px-3 py-2 text-sm text-amber-800 dark:text-amber-200">
            Parent banks catalog is not available on this environment.
          </p>
        ) : null}

        <ParentBanksTable
          rows={filtered}
          emptyMessage={
            searchInput.trim() ? "No parent banks match this search." : "No parent banks found."
          }
          showLinkedAccounts
          canManage={canManage}
          deletingId={deletingId}
          onEdit={openEdit}
          onDelete={(row) => void handleDelete(row)}
          onLinkedAccounts={openLinkedAccounts}
        />
      </div>

      <Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
        <SheetContent className="flex w-full flex-col gap-0 p-0 sm:max-w-md">
          <SheetHeader className="border-b px-6 py-4">
            <SheetTitle>{form.id > 0 ? "Edit parent bank" : "Create parent bank"}</SheetTitle>
            <SheetDescription>
              {canManage
                ? "Parent name, jurisdiction, status, and sort order for the master catalog."
                : "Parent bank details."}
            </SheetDescription>
          </SheetHeader>

          <div className="flex flex-1 flex-col gap-4 overflow-y-auto px-6 py-4">
            <div className="flex flex-col gap-1.5">
              <Label htmlFor="parent-name">Parent name</Label>
              <Input
                id="parent-name"
                value={form.parentName}
                placeholder="e.g. HSBC Group"
                disabled={!canManage}
                onChange={(event) => setForm((prev) => ({ ...prev, parentName: event.target.value }))}
              />
            </div>
            <div className="flex flex-col gap-1.5">
              <Label htmlFor="parent-jurisdiction">Jurisdiction</Label>
              <Input
                id="parent-jurisdiction"
                value={form.jurisdiction}
                maxLength={100}
                placeholder="e.g. Singapore"
                disabled={!canManage}
                onChange={(event) => setForm((prev) => ({ ...prev, jurisdiction: event.target.value }))}
              />
            </div>
            <div className="grid gap-3 sm:grid-cols-2">
              <div className="flex flex-col gap-1.5">
                <Label htmlFor="parent-status">Status</Label>
                <Select
                  value={form.status}
                  disabled={!canManage}
                  onValueChange={(value) =>
                    setForm((prev) => ({ ...prev, status: normalizeActiveStatus(value) }))
                  }
                >
                  <SelectTrigger id="parent-status" className="w-full">
                    <SelectValue placeholder="Active" />
                  </SelectTrigger>
                  <SelectContent>
                    {statusOptions.map((option) => (
                      <SelectItem key={option.id} value={option.id}>
                        {option.name}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
              <div className="flex flex-col gap-1.5">
                <Label htmlFor="parent-sort">Sort order</Label>
                <Input
                  id="parent-sort"
                  type="number"
                  value={form.sortOrder}
                  disabled={!canManage}
                  onChange={(event) =>
                    setForm((prev) => ({ ...prev, sortOrder: event.target.value }))
                  }
                />
              </div>
            </div>
          </div>

          <SheetFooter className="flex-row justify-end gap-2 border-t px-6 py-4">
            <SheetClose asChild>
              <Button type="button" variant="outline" disabled={isSaving}>
                {canManage ? "Cancel" : "Close"}
              </Button>
            </SheetClose>
            {canManage ? (
              <Button type="button" onClick={() => void handleSave()} disabled={isSaving}>
                {isSaving ? (
                  <Loader2 className="size-4 animate-spin" />
                ) : (
                  <Save className="size-4" />
                )}
                Save
              </Button>
            ) : null}
          </SheetFooter>
        </SheetContent>
      </Sheet>

      <LinkedAccountsSheet
        open={linkedSheetOpen}
        onOpenChange={(open) => {
          setLinkedSheetOpen(open);
          if (!open) setLinkedParent(null);
        }}
        tenant={tenant}
        parentBank={linkedParent}
      />
    </>
  );
}
