"use client";

import { isApiSuccess } from "@/lib/api-messages";
import * as React from "react";

import {
  getCoreRowModel,
  getPaginationRowModel,
  useReactTable,
  type ColumnDef,
  type PaginationState,
} from "@tanstack/react-table";
import {
  AppWindow,
  Loader2,
  PackagePlus,
  Pencil,
  RefreshCw,
  Search,
  ShieldCheck,
  Trash2,
} from "lucide-react";
import Link from "next/link";
import { toast } from "sonner";

import { fetchAppModuleCatalog } from "@/components/admins/rbac/api/app-modules-api";
import { DataTablePagination, matchesText } from "@/app/dashboard/_components/data-table";
import { DeleteConfirmDialog } from "@/components/shared/delete-confirm-dialog";
import { ErrorBanner } from "@/components/shared/error-banner";
import { useDashboardList } from "@/components/settings/hooks/use-dashboard-list";
import { runDeleteMutation } from "@/lib/toast-api-error";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { requestDashboardApi } from "@/lib/dashboard-api-client";
import type { PermissionCatalogEntry } from "@/components/admins/rbac/types";
import { formatDisplayDateTime } from "@/lib/format/dates";
import type { RbacModule } from "../_lib/app-modules-server-api";

type AppModulesPageClientProps = {
  initialCatalog: PermissionCatalogEntry[];
  initialErrorMessage: string | null;
  initialModules: RbacModule[];
  initialModulesErrorMessage: string | null;
};

type ModuleClientResponse = {
  status?: string;
  message?: string;
};

type AppModuleDraft = {
  id: string;
  name: string;
  description: string;
  permissionCount: number;
  permissions: string[];
  permissionDetails: PermissionCatalogEntry[];
  createdAt?: string | null;
  updatedAt?: string | null;
};

export function AppModulesPageClient({
  initialCatalog,
  initialErrorMessage,
  initialModules,
  initialModulesErrorMessage,
}: AppModulesPageClientProps) {
  const {
    data: modules,
    isRefreshing,
    refresh,
    removeLocal,
    errorMessage: modulesErrorMessage,
  } = useDashboardList<RbacModule>({
    fetcher: fetchAppModuleCatalog,
    initialData: initialModules,
    skipInitialLoad: true,
    initialErrorMessage: initialModulesErrorMessage,
    errorMessage: "Could not load modules.",
    refreshSuccessMessage: "Modules refreshed",
  });
  const [registryQuery, setRegistryQuery] = React.useState("");
  const [pagination, setPagination] = React.useState<PaginationState>({
    pageIndex: 0,
    pageSize: 10,
  });
  const [pendingDeleteModule, setPendingDeleteModule] = React.useState<AppModuleDraft | null>(null);
  const createdModules = React.useMemo(
    () => buildInitialAppModules(modules, initialCatalog),
    [modules, initialCatalog],
  );

  const filteredModules = React.useMemo(() => {
    const query = registryQuery.trim();
    if (!query) return createdModules;

    return createdModules.filter((module) =>
      [
        module.id,
        module.name,
        module.description,
        ...module.permissions,
        ...module.permissionDetails.flatMap((permission) => [
          permission.label,
          permission.description,
          permission.action ?? "",
        ]),
      ].some((value) => matchesText(value, query)),
    );
  }, [createdModules, registryQuery]);

  const moduleColumns = React.useMemo<ColumnDef<AppModuleDraft>[]>(() => [], []);
  const table = useReactTable({
    data: filteredModules,
    columns: moduleColumns,
    state: { pagination },
    onPaginationChange: setPagination,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getRowId: (module) => module.id,
  });
  const paginatedModules = table.getRowModel().rows.map((row) => row.original);
  const shouldShowModulesError =
    modulesErrorMessage && modulesErrorMessage !== initialErrorMessage;

  const deleteModule = async () => {
    const target = pendingDeleteModule;
    if (!target) return;

    await runDeleteMutation(async () => {
      await deleteModuleRequest(target.name);
      removeLocal(target.id);
      toast.success(`Module "${target.name}" deleted.`);
    }, "Could not delete module.");
  };

  return (
    <div className="space-y-6">
      <ErrorBanner message={initialErrorMessage} />
      {shouldShowModulesError ? (
        <div className="rounded-xl border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-amber-700 text-sm dark:text-amber-300">
          {modulesErrorMessage}
        </div>
      ) : null}

      <section className="space-y-4">
        <div className="flex flex-wrap items-end justify-between gap-3 rounded-2xl border bg-card p-4 shadow-sm">
          <div>
            <h2 className="font-semibold text-base">Module registry</h2>
            <p className="text-muted-foreground text-sm">
              Search, review, and edit modules without leaving the list.
            </p>
          </div>
          <div className="flex flex-wrap gap-2">
            <div className="relative">
              <Search className="-translate-y-1/2 pointer-events-none absolute top-1/2 left-3 size-4 text-muted-foreground" />
              <Input
                value={registryQuery}
                onChange={(event) => {
                  setRegistryQuery(event.target.value);
                  setPagination((current) => ({ ...current, pageIndex: 0 }));
                }}
                placeholder="Search modules..."
                className="h-9 w-[260px] pl-9"
              />
            </div>
            <Button
              type="button"
              size="sm"
              variant="outline"
              onClick={() => void refresh()}
              disabled={isRefreshing}
            >
              {isRefreshing ? (
                <Loader2 className="size-4 animate-spin" />
              ) : (
                <RefreshCw className="size-4" />
              )}
              Refresh
            </Button>
            <Button type="button" size="sm" asChild>
              <Link href="/dashboard/admins/access/app-modules/form">
                <PackagePlus className="size-4" />
                Create module
              </Link>
            </Button>
          </div>
        </div>

        <div className="grid gap-4 lg:grid-cols-2">
          {paginatedModules.map((module) => (
            <AppModuleCard
              key={module.id}
              module={module}
              onDelete={setPendingDeleteModule}
            />
          ))}
        </div>
        {filteredModules.length === 0 ? (
          <div className="rounded-2xl border border-dashed p-8 text-center text-muted-foreground text-sm">
            No modules match your search.
          </div>
        ) : null}
        {filteredModules.length > 0 ? (
          <DataTablePagination
            table={table}
            totalRows={filteredModules.length}
            itemNoun="module"
            idPrefix="app-modules"
            pageSizes={[6, 10, 20, 50]}
          />
        ) : null}
      </section>

      <DeleteConfirmDialog
        open={Boolean(pendingDeleteModule)}
        onOpenChange={(open) => {
          if (!open) setPendingDeleteModule(null);
        }}
        icon={Trash2}
        title="Delete this module?"
        description={
          pendingDeleteModule ? (
            <>
              <span className="font-mono font-medium text-foreground">
                {pendingDeleteModule.name}
              </span>{" "}
              will be permanently removed. This action cannot be undone.
            </>
          ) : (
            "This module will be permanently removed. This action cannot be undone."
          )
        }
        confirmLabel="Delete module"
        onConfirm={deleteModule}
      />
    </div>
  );
}

async function deleteModuleRequest(moduleName: string) {
  await requestDashboardApi<ModuleClientResponse>({
    url: "/dashboard/admins/access/app-modules/delete",
    method: "POST",
    body: { name: moduleName },
    fallbackError: "Could not delete module.",
    validate: (data) => isApiSuccess(data),
  });
}

function AppModuleCard({
  module,
  onDelete,
}: {
  module: AppModuleDraft;
  onDelete: (module: AppModuleDraft) => void;
}) {
  return (
    <div className="rounded-2xl border bg-card p-4 shadow-sm">
      <div className="flex items-start justify-between gap-3">
        <div className="min-w-0">
          <div className="flex flex-wrap items-center gap-2">
            <Badge variant="outline" className="font-mono">
              ID {module.id}
            </Badge>
          </div>
          <h3 className="mt-3 font-semibold text-base">{module.name}</h3>
          <p className="mt-1 text-muted-foreground text-xs">
            Updated {formatDisplayDateTime(module.updatedAt)}
          </p>
        </div>
        <div className="flex shrink-0 items-center gap-2">
          <Button
            type="button"
            size="sm"
            variant="outline"
            asChild
          >
            <Link href={`/dashboard/admins/access/app-modules/form?name=${encodeURIComponent(module.name)}`}>
              <Pencil className="size-4" />
              Edit
            </Link>
          </Button>
          <Button
            type="button"
            size="sm"
            variant="destructive"
            onClick={() => onDelete(module)}
          >
            <Trash2 className="size-4" />
            Delete
          </Button>
          <div className="flex size-10 items-center justify-center rounded-xl bg-muted">
            <AppWindow className="size-5" />
          </div>
        </div>
      </div>

      {module.description ? (
        <p className="mt-3 text-muted-foreground text-sm">{module.description}</p>
      ) : null}

      <div className="mt-4 grid gap-3 sm:grid-cols-2">
        <Metric
          icon={ShieldCheck}
          label="Permissions"
          value={`${module.permissionCount} selected`}
        />
        <Metric
          icon={AppWindow}
          label="Created"
          value={formatDisplayDateTime(module.createdAt)}
        />
      </div>

      <div className="mt-4 flex flex-wrap gap-2">
        {module.permissions.slice(0, 8).map((permission) => (
          <Badge key={permission} variant="outline" className="font-mono">
            {permission}
          </Badge>
        ))}
        {module.permissions.length > 8 ? (
          <Badge variant="secondary">+{module.permissions.length - 8} more</Badge>
        ) : null}
      </div>
    </div>
  );
}

function Metric({
  icon: Icon,
  label,
  value,
  mono,
}: {
  icon: React.ComponentType<{ className?: string }>;
  label: string;
  value: string;
  mono?: boolean;
}) {
  return (
    <div className="rounded-xl border bg-muted/30 p-3">
      <div className="flex items-center gap-2 text-muted-foreground text-xs">
        <Icon className="size-3.5" />
        {label}
      </div>
      <p className={mono ? "mt-1 break-all font-mono text-sm" : "mt-1 text-sm"}>{value}</p>
    </div>
  );
}

function buildInitialAppModules(
  backendModules: RbacModule[],
  catalog: PermissionCatalogEntry[],
): AppModuleDraft[] {
  return backendModules
    .map((module) => moduleToDraft(module, catalog))
    .sort((a, b) => a.name.localeCompare(b.name));
}

function moduleToDraft(module: RbacModule, catalog: PermissionCatalogEntry[]): AppModuleDraft {
  const permissionDetails = getPermissionDetails(module.permissions, catalog);

  return {
    id: module.id,
    name: module.name,
    description: module.description,
    permissionCount: module.permissionCount,
    permissions: module.permissions,
    permissionDetails,
    createdAt: module.createdAt,
    updatedAt: module.updatedAt,
  };
}

function getPermissionDetails(
  permissions: string[],
  catalog: PermissionCatalogEntry[],
): PermissionCatalogEntry[] {
  const byName = new Map(catalog.map((permission) => [permission.name, permission]));
  return permissions
    .map((permission) => byName.get(permission))
    .filter((permission): permission is PermissionCatalogEntry => Boolean(permission));
}

