"use client";

import * as React from "react";

import { useAnyChanged } from "@/hooks/use-changed";
import { Landmark, Loader2, Search, Users, X } from "lucide-react";

import type {
  PortalLinkedBankAccountRow,
  PortalParentBankRow,
} from "@/app/customer/_lib/admin/parent-banks-server-api";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetTitle,
} from "@/components/ui/sheet";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { errorMessageOr } from "@/lib/toast-api-error";
import { cn } from "@/lib/utils";

type LinkedCustomerGroup = {
  customerId: number;
  customerName: string;
  email: string;
  company: string;
  subdomain: string;
  accounts: PortalLinkedBankAccountRow[];
};

function InfoChip({
  label,
  value,
  detail,
}: {
  label: string;
  value: string;
  detail?: string;
}) {
  return (
    <div className="min-w-0 rounded-xl border border-border/60 bg-card/80 px-3 py-2 shadow-sm backdrop-blur-sm">
      <p className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground">
        {label}
      </p>
      <p className="mt-0.5 truncate text-sm font-medium text-foreground" title={value}>
        {value}
      </p>
      {detail ? (
        <p className="mt-0.5 truncate text-xs text-muted-foreground" title={detail}>
          {detail}
        </p>
      ) : null}
    </div>
  );
}

function groupLinkedAccounts(rows: PortalLinkedBankAccountRow[]): LinkedCustomerGroup[] {
  const byId = new Map<number, LinkedCustomerGroup>();

  for (const row of rows) {
    const existing = byId.get(row.customerId);
    if (existing) {
      existing.accounts.push(row);
      continue;
    }
    byId.set(row.customerId, {
      customerId: row.customerId,
      customerName: row.customerName,
      email: row.email,
      company: row.company,
      subdomain: row.subdomain,
      accounts: [row],
    });
  }

  return [...byId.values()].sort((a, b) =>
    (a.customerName || `#${a.customerId}`).localeCompare(b.customerName || `#${b.customerId}`),
  );
}

export function LinkedAccountsSheet({
  open,
  onOpenChange,
  tenant,
  parentBank,
}: {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  tenant: string;
  parentBank: PortalParentBankRow | null;
}) {
  const [loading, setLoading] = React.useState(Boolean(open && parentBank));
  const [error, setError] = React.useState<string | null>(null);
  const [accounts, setAccounts] = React.useState<PortalLinkedBankAccountRow[]>([]);
  const [resolvedParent, setResolvedParent] = React.useState<PortalParentBankRow | null>(open ? parentBank : null);
  const [search, setSearch] = React.useState("");
  const [selectedCustomerId, setSelectedCustomerId] = React.useState<number | null>(null);

  // Opening, closing or switching bank starts from a clean slate (adjusted during render, not in an effect).
  if (useAnyChanged([open, parentBank, tenant])) {
    const active = Boolean(open && parentBank);
    setLoading(active);
    setError(null);
    setAccounts([]);
    setResolvedParent(active ? parentBank : null);
    setSearch("");
    setSelectedCustomerId(null);
  }

  React.useEffect(() => {
    if (!open || !parentBank) return;

    const controller = new AbortController();

    fetch(
      `/customer/${tenant}/admin/parent-banks/linked?parentBankId=${parentBank.id}`,
      {
        headers: { Accept: "application/json" },
        cache: "no-store",
        signal: controller.signal,
      },
    )
      .then(async (response) => {
        const data = (await response.json().catch(() => null)) as {
          status?: string;
          message?: string;
          parentBank?: PortalParentBankRow | null;
          linkedAccounts?: PortalLinkedBankAccountRow[];
        } | null;
        if (!response.ok || !data || data.status === "error") {
          throw new Error(
            typeof data?.message === "string"
              ? data.message
              : "Could not load linked accounts.",
          );
        }
        setAccounts(Array.isArray(data.linkedAccounts) ? data.linkedAccounts : []);
        if (data.parentBank) {
          setResolvedParent(data.parentBank);
        }
      })
      .catch((err: unknown) => {
        if (controller.signal.aborted) return;
        setError(errorMessageOr(err, "Could not load linked accounts."));
      })
      .finally(() => {
        if (!controller.signal.aborted) setLoading(false);
      });

    return () => controller.abort();
  }, [open, parentBank, tenant]);

  const groups = React.useMemo(() => groupLinkedAccounts(accounts), [accounts]);

  const filteredGroups = React.useMemo(() => {
    const q = search.trim().toLowerCase();
    if (!q) return groups;
    return groups
      .map((group) => {
        const customerHit = [
          group.customerName,
          group.email,
          group.company,
          group.subdomain,
          String(group.customerId),
        ]
          .join(" ")
          .toLowerCase()
          .includes(q);
        const accounts = customerHit
          ? group.accounts
          : group.accounts.filter((account) =>
              [account.bankName, account.accountNumber, account.status]
                .join(" ")
                .toLowerCase()
                .includes(q),
            );
        if (accounts.length === 0) return null;
        return { ...group, accounts };
      })
      .filter((group): group is LinkedCustomerGroup => group != null);
  }, [groups, search]);

  const selectedGroup =
    selectedCustomerId == null
      ? null
      : (filteredGroups.find((group) => group.customerId === selectedCustomerId) ?? null);

  const parentName = resolvedParent?.parentName ?? parentBank?.parentName ?? "Parent bank";
  const linkedCount = accounts.length;
  const customerCount = groups.length;

  return (
    <Sheet open={open} onOpenChange={onOpenChange}>
      <SheetContent
        side="right"
        showCloseButton={false}
        className={cn(
          "flex h-dvh w-full flex-col gap-0 overflow-hidden bg-muted/30 p-0",
          "data-[side=right]:w-full data-[side=right]:sm:max-w-none",
          "data-[side=right]:sm:!w-[min(56rem,calc(100vw-1.5rem))]",
        )}
      >
        <div className="shrink-0 space-y-2 border-b border-border/60 bg-card/80 px-4 pt-4 pb-3 backdrop-blur-md">
          <p className="text-muted-foreground text-[10px] font-semibold tracking-widest uppercase">
            Parent Banks
          </p>
          <div className="flex items-center justify-between gap-2">
            <SheetTitle className="flex min-w-0 items-center gap-2 text-left text-base font-semibold tracking-tight">
              <span className="flex size-8 shrink-0 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-md shadow-primary/25">
                <Users className="size-3.5" />
              </span>
              <span className="truncate">Linked Accounts</span>
            </SheetTitle>
            <Button
              type="button"
              variant="ghost"
              size="icon-sm"
              className="rounded-lg"
              onClick={() => onOpenChange(false)}
              aria-label="Close"
            >
              <X className="size-4" />
            </Button>
          </div>
          <SheetDescription className="sr-only">
            Customers and bank accounts linked to this parent bank.
          </SheetDescription>
        </div>

        <div className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-4 py-4">
          <section className="flex flex-col gap-3 rounded-2xl border border-border/60 bg-card p-3 shadow-sm">
            {selectedGroup ? (
              <button
                type="button"
                className="w-fit text-sm text-primary underline-offset-2 hover:underline"
                onClick={() => setSelectedCustomerId(null)}
              >
                ← Back to customers
              </button>
            ) : null}

            <div className="grid gap-2 sm:grid-cols-3">
              <InfoChip label="Parent bank" value={parentName} />
              <InfoChip
                label="Linked accounts"
                value={String(linkedCount)}
                detail={`${customerCount} customer${customerCount === 1 ? "" : "s"}`}
              />
              <InfoChip
                label={selectedGroup ? "Customer" : "Status"}
                value={
                  selectedGroup
                    ? selectedGroup.customerName || `#${selectedGroup.customerId}`
                    : resolvedParent?.status === "I"
                      ? "Inactive"
                      : "Active"
                }
                detail={
                  selectedGroup
                    ? [selectedGroup.email, selectedGroup.company].filter(Boolean).join(" · ") ||
                      undefined
                    : undefined
                }
              />
            </div>

            {!selectedGroup ? (
              <div className="relative w-full max-w-sm">
                <Search className="pointer-events-none absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
                <Input
                  value={search}
                  placeholder="Search customers or accounts"
                  className="pl-8"
                  onChange={(event) => setSearch(event.target.value)}
                />
              </div>
            ) : null}
          </section>

          {loading ? (
            <div className="flex items-center gap-2 py-10 text-sm text-muted-foreground">
              <Loader2 className="size-4 animate-spin" />
              Loading…
            </div>
          ) : null}

          {error ? <p className="text-sm text-destructive">{error}</p> : null}

          {!loading && !error && selectedGroup ? (
            <div className="rounded-2xl border border-border/60 bg-card shadow-sm">
              <div className="flex items-center gap-2 border-b border-border/60 px-4 py-3">
                <Landmark className="size-4 text-muted-foreground" />
                <p className="text-sm font-medium">
                  {selectedGroup.accounts.length} account
                  {selectedGroup.accounts.length === 1 ? "" : "s"} under {parentName}
                </p>
              </div>
              <Table>
                <TableHeader>
                  <TableRow className="bg-muted/40 hover:bg-muted/40">
                    <TableHead className="px-3">Bank name</TableHead>
                    <TableHead className="px-3">Account number</TableHead>
                    <TableHead className="px-3 text-center">Status</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {selectedGroup.accounts.map((account) => (
                    <TableRow key={`${account.customerId}-${account.bankId}`}>
                      <TableCell className="px-3 py-2.5 font-medium">
                        {account.bankName || `Bank #${account.bankId}`}
                      </TableCell>
                      <TableCell className="px-3 py-2.5 font-mono text-sm text-muted-foreground">
                        {account.accountNumber || "—"}
                      </TableCell>
                      <TableCell className="px-3 py-2.5 text-center">
                        <Badge variant={account.status === "A" ? "secondary" : "outline"}>
                          {account.status === "A" ? "Active" : "Inactive"}
                        </Badge>
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </div>
          ) : null}

          {!loading && !error && !selectedGroup ? (
            filteredGroups.length ? (
              <div className="rounded-2xl border border-border/60 bg-card shadow-sm">
                <Table>
                  <TableHeader>
                    <TableRow className="bg-muted/40 hover:bg-muted/40">
                      <TableHead className="px-3">Customer</TableHead>
                      <TableHead className="px-3">Subdomain</TableHead>
                      <TableHead className="px-3 text-center">Linked accounts</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {filteredGroups.map((group) => (
                      <TableRow
                        key={group.customerId}
                        className="cursor-pointer"
                        onClick={() => setSelectedCustomerId(group.customerId)}
                      >
                        <TableCell className="px-3 py-2.5">
                          <div className="flex flex-col">
                            <span className="font-medium text-primary underline-offset-2 hover:underline">
                              {group.customerName || `#${group.customerId}`}
                            </span>
                            <span className="text-xs text-muted-foreground">
                              {[group.email, group.company].filter(Boolean).join(" · ") ||
                                `Customer #${group.customerId}`}
                            </span>
                          </div>
                        </TableCell>
                        <TableCell className="px-3 py-2.5 text-muted-foreground">
                          {group.subdomain || "—"}
                        </TableCell>
                        <TableCell className="px-3 py-2.5 text-center">
                          <Badge variant="secondary">{group.accounts.length}</Badge>
                        </TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </div>
            ) : (
              <p className="text-sm text-muted-foreground">
                {search.trim()
                  ? "No customers or accounts match this search."
                  : "No customers are linked to this parent bank."}
              </p>
            )
          ) : null}
        </div>
      </SheetContent>
    </Sheet>
  );
}
