"use client";

import { isApiSuccess } from "@/lib/api-messages";
import * as React from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import {
  getCoreRowModel,
  useReactTable,
  type PaginationState,
} from "@tanstack/react-table";
import {
  ChevronDown,
  ChevronRight,
  ChevronsDownUp,
  ChevronsUpDown,
  Folder,
  FolderOpen,
  Pencil,
  Search,
  Trash2,
} from "lucide-react";
import { toast } from "sonner";

import {
  DataTablePagination,
  useDebouncedValue,
} from "@/app/dashboard/_components/data-table";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { SETTINGS_INPUT_CLASS } from "@/components/settings/constants";
import { requestDashboardApi } from "@/lib/dashboard-api-client";
import { cn } from "@/lib/utils";

import {
  buildAssetDefinitionHref,
  DEFAULT_PAGE_SIZE,
  LIST_HREF,
} from "./constants";
import { TREE_LIST_CLASS, TreeItem } from "@/app/dashboard/master-table/_components/tree";
import type { AssetDefinitionRow } from "./schema";
import { formatPlainAmount } from "@/lib/format/numbers";

const DELETE_HREF = "/dashboard/master-table/asset-definition/delete";
const PREVIEW_LIMIT = 4;

type Props = {
  data: AssetDefinitionRow[];
  filters: {
    masterName: string;
  };
  totalCount: number;
  page: number;
  pageSize: number;
  pageCount: number;
};

const filterInputClass = cn(SETTINGS_INPUT_CLASS, "h-9 pl-8");

export function AssetDefinitionTable({
  data,
  filters,
  totalCount,
  page,
  pageSize,
  pageCount,
}: Props) {
  const router = useRouter();
  const [masterNameDraft, setMasterNameDraft] = React.useState(filters.masterName);
  const debouncedMasterName = useDebouncedValue(masterNameDraft);

  const navigate = React.useCallback(
    (
      next: {
        masterName?: string;
        page?: number;
        pageSize?: number;
      },
      options?: { replace?: boolean },
    ) => {
      const href = buildAssetDefinitionHref({
        masterName: next.masterName ?? filters.masterName,
        page: next.page ?? page,
        pageSize: next.pageSize ?? pageSize,
      });

      if (options?.replace) {
        router.replace(href, { scroll: false });
        return;
      }

      router.push(href, { scroll: false });
    },
    [filters.masterName, page, pageSize, router],
  );

  React.useEffect(() => {
    setMasterNameDraft(filters.masterName);
  }, [filters.masterName]);

  React.useEffect(() => {
    const normalized = debouncedMasterName.trim();
    if (normalized === filters.masterName) return;
    navigate({ masterName: normalized, page: 1 }, { replace: true });
  }, [debouncedMasterName, filters.masterName, navigate]);

  const onDelete = React.useCallback(
    async (id: string) => {
      try {
        await requestDashboardApi<{ status?: string }>({
          url: DELETE_HREF,
          method: "POST",
          body: { id },
          fallbackError: "Could not delete asset definition.",
          validate: (payload) => isApiSuccess(payload),
        });
        toast.success("Asset definition deleted.");
        router.refresh();
      } catch (error) {
        toast.error(
          error instanceof Error
            ? error.message
            : "Could not delete asset definition.",
        );
      }
    },
    [router],
  );

  // Pagination state only; the grouped list below renders the rows itself.
  const pagination = React.useMemo<PaginationState>(
    () => ({
      pageIndex: Math.max(page - 1, 0),
      pageSize,
    }),
    [page, pageSize],
  );

  const table = useReactTable({
    data,
    columns: [],
    state: { pagination },
    pageCount,
    manualPagination: true,
    onPaginationChange: (updater) => {
      const next = typeof updater === "function" ? updater(pagination) : updater;
      const nextPageSize = next.pageSize > 0 ? next.pageSize : pageSize;
      const nextPage = nextPageSize !== pageSize ? 1 : Math.max(next.pageIndex + 1, 1);

      navigate({
        page: nextPage,
        pageSize: nextPageSize,
      });
    },
    getCoreRowModel: getCoreRowModel(),
    getRowId: (r) => r.id,
  });

  // The backend pages by asset title and sends every definition of each group, in title order.
  const groups = (() => {
    const byKey = new Map<string, AssetDefinitionRow[]>();
    for (const row of data) {
      const key = row.oxyName.toLowerCase();
      const bucket = byKey.get(key);
      if (bucket) bucket.push(row);
      else byKey.set(key, [row]);
    }
    return Array.from(byKey.entries()).map(([key, rows]) => ({
      key,
      title: rows[0].oxyNameTitle || rows[0].oxyName || "Unassigned",
      code: rows[0].oxyName,
      rows,
    }));
  })();

  // Groups start collapsed; keys are lower-cased asset codes.
  const [expanded, setExpanded] = React.useState<Set<string>>(() => new Set());
  const toggleGroup = (key: string) =>
    setExpanded((prev) => {
      const next = new Set(prev);
      if (next.has(key)) next.delete(key);
      else next.add(key);
      return next;
    });
  const allExpanded = groups.length > 0 && groups.every((g) => expanded.has(g.key));

  const start = totalCount === 0 ? 0 : (page - 1) * pageSize + 1;
  const end = Math.min(page * pageSize, totalCount);

  return (
    <div className="space-y-4">
      <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
        <div className="relative w-full lg:max-w-sm">
          <Search className="pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground" />
          <Input
            className={filterInputClass}
            placeholder="Search name"
            aria-label="Filter by name"
            value={masterNameDraft}
            onChange={(e) => setMasterNameDraft(e.target.value)}
          />
        </div>

        <div className="flex items-center justify-between gap-3 lg:justify-end">
          <p className="text-sm text-muted-foreground">
            {start}–{end} of {formatPlainAmount(totalCount)} asset titles
          </p>
          <Button
            variant="outline"
            size="sm"
            disabled={!groups.length}
            onClick={() =>
              setExpanded(allExpanded ? new Set() : new Set(groups.map((g) => g.key)))
            }
          >
            {allExpanded ? (
              <ChevronsDownUp className="size-4" />
            ) : (
              <ChevronsUpDown className="size-4" />
            )}
            {allExpanded ? "Collapse all" : "Expand all"}
          </Button>
        </div>
      </div>

      {groups.length ? (
        <ul className="divide-y overflow-hidden rounded-lg border bg-card">
          {groups.map((group) => {
            const isOpen = expanded.has(group.key);
            const count = group.rows.length;
            const panelId = `ad-${group.key.replace(/[^a-z0-9_-]/g, "_")}`;
            const preview = group.rows.slice(0, PREVIEW_LIMIT);
            const hidden = count - preview.length;

            return (
              <li key={group.key}>
                <button
                  type="button"
                  aria-expanded={isOpen}
                  aria-controls={panelId}
                  onClick={() => toggleGroup(group.key)}
                  className={cn(
                    "flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-muted/40 focus-visible:bg-muted/40 focus-visible:outline-none",
                    isOpen && "bg-muted/30",
                  )}
                >
                  {isOpen ? (
                    <ChevronDown className="size-4 shrink-0 text-muted-foreground" />
                  ) : (
                    <ChevronRight className="size-4 shrink-0 text-muted-foreground" />
                  )}
                  {isOpen ? (
                    <FolderOpen className="size-4 shrink-0 text-primary" />
                  ) : (
                    <Folder className="size-4 shrink-0 text-muted-foreground" />
                  )}
                  <span className="shrink-0 text-sm font-medium">{group.title}</span>
                  {group.code && (
                    <code className="shrink-0 rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground">
                      {group.code}
                    </code>
                  )}
                  <Badge variant="secondary" className="shrink-0 font-normal">
                    {count} {count === 1 ? "definition" : "definitions"}
                  </Badge>
                  {!isOpen && (
                    <span className="ml-2 hidden min-w-0 flex-1 items-center gap-1.5 overflow-hidden md:flex">
                      {preview.map((row) => (
                        <span
                          key={row.id}
                          title={row.masterName}
                          className="max-w-56 truncate rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground"
                        >
                          {row.masterName}
                        </span>
                      ))}
                      {hidden > 0 && (
                        <span className="shrink-0 text-xs text-muted-foreground">
                          +{hidden} more
                        </span>
                      )}
                    </span>
                  )}
                </button>

                {isOpen && (
                  <ul id={panelId} className={TREE_LIST_CLASS}>
                    {group.rows.map((row, index) => (
                      <TreeItem key={row.id} isLast={index === group.rows.length - 1}>
                        <div className="flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1">
                          <span className="text-sm font-medium break-all">{row.masterName}</span>
                          {row.info && (
                            <span className="text-xs text-muted-foreground">{row.info}</span>
                          )}
                        </div>
                        <div className="flex shrink-0 items-center gap-1">
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <Button variant="secondary" size="icon-sm" className="size-7" asChild>
                                <Link
                                  href={`${LIST_HREF}/${encodeURIComponent(row.id)}`}
                                  aria-label={`Update ${row.masterName}`}
                                >
                                  <Pencil className="size-3.5" />
                                </Link>
                              </Button>
                            </TooltipTrigger>
                            <TooltipContent>Update</TooltipContent>
                          </Tooltip>
                          <AlertDialog>
                            <AlertDialogTrigger asChild>
                              <Button
                                variant="destructive"
                                size="icon-sm"
                                className="size-7"
                                aria-label={`Delete ${row.masterName}`}
                              >
                                <Trash2 className="size-3.5" />
                              </Button>
                            </AlertDialogTrigger>
                            <AlertDialogContent>
                              <AlertDialogHeader>
                                <AlertDialogTitle>Delete asset definition?</AlertDialogTitle>
                                <AlertDialogDescription>
                                  Remove {row.masterName}? This cannot be undone.
                                </AlertDialogDescription>
                              </AlertDialogHeader>
                              <AlertDialogFooter>
                                <AlertDialogCancel>Cancel</AlertDialogCancel>
                                <AlertDialogAction
                                  onClick={() => {
                                    void onDelete(row.id);
                                  }}
                                >
                                  Delete
                                </AlertDialogAction>
                              </AlertDialogFooter>
                            </AlertDialogContent>
                          </AlertDialog>
                        </div>
                      </TreeItem>
                    ))}
                  </ul>
                )}
              </li>
            );
          })}
        </ul>
      ) : (
        <div className="flex h-24 items-center justify-center rounded-lg border bg-card text-sm text-muted-foreground">
          No records found.
        </div>
      )}

      <DataTablePagination
        table={table}
        totalRows={totalCount}
        itemNoun="asset title"
        idPrefix="asset-definition"
        pageSizes={[10, 20, DEFAULT_PAGE_SIZE, 100]}
      />
    </div>
  );
}
