"use client";

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

import {
  AppWindow,
  PackagePlus,
  Pencil,
  Search,
  ShieldCheck,
  Trash2,
} from "lucide-react";
import Link from "next/link";
import { toast } from "sonner";

import { DeleteConfirmDialog } from "@/components/admins/rbac/delete-confirm-dialog";
import { ErrorBanner } from "@/components/shared/error-banner";
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 { requestDashboardApi } from "@/lib/dashboard-api-client";
import type { PermissionCatalogEntry } from "@/components/admins/rbac/types";
import { formatDisplayDateTime } from "@/lib/format/dates";
import { resolveClientPageCount } from "@/lib/list-pagination";
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 [deletingModule, setDeletingModule] = React.useState(false);
  const [registryQuery, setRegistryQuery] = React.useState("");
  const [pageIndex, setPageIndex] = React.useState(0);
  const [pageSize, setPageSize] = React.useState(10);
  const [pendingDeleteModule, setPendingDeleteModule] = React.useState<AppModuleDraft | null>(null);
  const [createdModules, setCreatedModules] = React.useState<AppModuleDraft[]>(() =>
    buildInitialAppModules(initialModules, initialCatalog),
  );

  const filteredModules = React.useMemo(() => {
    const query = registryQuery.trim().toLowerCase();
    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) => value.toLowerCase().includes(query)),
    );
  }, [createdModules, registryQuery]);

  const totalPages = resolveClientPageCount(filteredModules.length, pageSize);
  const activePageIndex = Math.min(pageIndex, totalPages - 1);
  const paginatedModules = React.useMemo(() => {
    const start = activePageIndex * pageSize;
    return filteredModules.slice(start, start + pageSize);
  }, [activePageIndex, filteredModules, pageSize]);
  const shouldShowModulesError =
    initialModulesErrorMessage && initialModulesErrorMessage !== initialErrorMessage;

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

    setDeletingModule(true);

    try {
      await deleteModuleRequest(pendingDeleteModule.name);

      setCreatedModules((current) =>
        current.filter((module) => module.id !== pendingDeleteModule.id),
      );

      toast.success(`Module "${pendingDeleteModule.name}" deleted.`);
      setPendingDeleteModule(null);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Could not delete module.";
      toast.error(message);
    } finally {
      setDeletingModule(false);
    }
  };

  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">
          {initialModulesErrorMessage}
        </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);
                  setPageIndex(0);
                }}
                placeholder="Search modules..."
                className="h-9 w-[260px] pl-9"
              />
            </div>
            <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 ? (
          <RegistryPagination
            pageIndex={activePageIndex}
            pageSize={pageSize}
            totalRows={filteredModules.length}
            onPageChange={setPageIndex}
            onPageSizeChange={(nextPageSize) => {
              setPageSize(nextPageSize);
              setPageIndex(0);
            }}
          />
        ) : null}
      </section>

      <DeleteConfirmDialog
        open={Boolean(pendingDeleteModule)}
        itemName={pendingDeleteModule?.name ?? null}
        title="Delete this module?"
        itemType="module"
        confirmLabel="Delete module"
        isDeleting={deletingModule}
        onOpenChange={(open) => {
          if (!open && !deletingModule) setPendingDeleteModule(null);
        }}
        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 RegistryPagination({
  pageIndex,
  pageSize,
  totalRows,
  onPageChange,
  onPageSizeChange,
}: {
  pageIndex: number;
  pageSize: number;
  totalRows: number;
  onPageChange: (pageIndex: number) => void;
  onPageSizeChange: (pageSize: number) => void;
}) {
  const totalPages = resolveClientPageCount(totalRows, pageSize);
  const firstRow = totalRows === 0 ? 0 : pageIndex * pageSize + 1;
  const lastRow = Math.min(totalRows, (pageIndex + 1) * pageSize);

  return (
    <div className="flex flex-wrap items-center justify-between gap-3 rounded-2xl border bg-card px-4 py-3 shadow-sm">
      <p className="text-muted-foreground text-sm">
        Showing {firstRow}-{lastRow} of {totalRows} modules
      </p>

      <div className="flex flex-wrap items-center gap-3">
        <div className="flex items-center gap-2">
          <Label htmlFor="app-modules-page-size" className="text-muted-foreground text-xs">
            Rows
          </Label>
          <Select
            value={String(pageSize)}
            onValueChange={(value) => onPageSizeChange(Number(value))}
          >
            <SelectTrigger id="app-modules-page-size" className="h-8 w-[84px]">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {[6, 10, 20, 50].map((size) => (
                <SelectItem key={size} value={String(size)}>
                  {size}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>

        <div className="flex items-center gap-2">
          <span className="text-muted-foreground text-sm">
            Page {pageIndex + 1} of {totalPages}
          </span>
          <Button
            type="button"
            variant="outline"
            size="sm"
            onClick={() => onPageChange(Math.max(0, pageIndex - 1))}
            disabled={pageIndex === 0}
          >
            Previous
          </Button>
          <Button
            type="button"
            variant="outline"
            size="sm"
            onClick={() => onPageChange(Math.min(totalPages - 1, pageIndex + 1))}
            disabled={pageIndex >= totalPages - 1}
          >
            Next
          </Button>
        </div>
      </div>
    </div>
  );
}

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));
}

