"use client";

import { ChevronDown } from "lucide-react";
import { useMemo, useState } from "react";

import { Checkbox } from "@/components/ui/checkbox";
import { AdminNoResourceState } from "@/components/admin/admin-no-resource-state";
import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
import type { AdminPermissionCatalogData } from "@/types/api/admin-user";

type PermissionSelectorProps = {
  catalog: AdminPermissionCatalogData | null;
  selectedSlugs: string[];
  onChange: (next: string[]) => void;
  resolveGroupLabel: (key: string, fallback: string) => string;
  resolvePermissionLabel: (slug: string, fallback: string) => string;
  selectableSlugs?: string[] | null;
  helperText?: string;
  summaryText?: string;
  heightClassName?: string;
};

export function AdminPermissionSelector({
  catalog,
  selectedSlugs,
  onChange,
  resolveGroupLabel,
  resolvePermissionLabel,
  selectableSlugs = null,
  helperText,
  summaryText,
  heightClassName = "h-[52vh]",
}: PermissionSelectorProps): React.ReactElement {
  const [expandedGroups, setExpandedGroups] = useState<Record<string, boolean>>({});
  const selectedSet = useMemo(() => new Set(selectedSlugs), [selectedSlugs]);
  const allowedSet = useMemo(
    () => (selectableSlugs ? new Set(selectableSlugs) : null),
    [selectableSlugs],
  );

  const groups = useMemo(() => {
    const rawGroups = catalog?.permission_menu_groups ?? [];
    const mapped = rawGroups
      .map((group) => ({
        key: group.key,
        label: resolveGroupLabel(group.key, group.label),
        permissions: group.permissions.filter((permission) =>
          allowedSet ? allowedSet.has(permission.slug) : true,
        ),
      }))
      .filter((group) => group.permissions.length > 0);

    if (mapped.length > 0) {
      return mapped;
    }

    const fallbackPermissions = (catalog?.permissions ?? []).filter((permission) =>
      allowedSet ? allowedSet.has(permission.slug) : true,
    );

    if (fallbackPermissions.length === 0) {
      return [];
    }

    return [
      {
        key: "all",
        label: resolveGroupLabel("all", "全部权限"),
        permissions: fallbackPermissions,
      },
    ];
  }, [allowedSet, catalog, resolveGroupLabel]);

  const totalCount = useMemo(
    () => groups.reduce((sum, group) => sum + group.permissions.length, 0),
    [groups],
  );

  const toggleOne = (slug: string, checked: boolean) => {
    const next = new Set(selectedSet);
    if (checked) {
      next.add(slug);
    } else {
      next.delete(slug);
    }
    onChange(Array.from(next).sort());
  };

  const toggleGroup = (slugs: string[], checked: boolean) => {
    const next = new Set(selectedSet);
    for (const slug of slugs) {
      if (checked) {
        next.add(slug);
      } else {
        next.delete(slug);
      }
    }
    onChange(Array.from(next).sort());
  };

  const toggleExpanded = (key: string) => {
    setExpandedGroups((prev) => ({ ...prev, [key]: !(prev[key] ?? true) }));
  };

  const isExpanded = (key: string): boolean => expandedGroups[key] ?? true;

  if (groups.length === 0 || totalCount === 0) {
    return (
      <div className="rounded-xl border border-dashed p-4">
        <AdminNoResourceState compact className="py-4" />
      </div>
    );
  }

  return (
    <div className="space-y-3">
      {helperText || summaryText ? (
        <div className="flex flex-wrap items-center justify-between gap-2 rounded-xl border bg-muted/20 px-3 py-2 text-xs text-muted-foreground">
          <span>{helperText}</span>
          <span>{summaryText}</span>
        </div>
      ) : null}

      <ScrollArea className={cn("pr-3", heightClassName)}>
        <div className="overflow-hidden rounded-xl border border-border/70 bg-background">
          {groups.map((group) => {
            const expanded = isExpanded(group.key);
            const groupSlugs = group.permissions.map((permission) => permission.slug);
            const selectedCount = groupSlugs.filter((slug) => selectedSet.has(slug)).length;
            const checkedState =
              selectedCount === 0 ? false : selectedCount === groupSlugs.length ? true : "indeterminate";

            return (
              <div key={group.key} className={cn("border-b border-border/60 last:border-b-0", expanded && "bg-muted/10")}>
                <div className="flex items-center gap-3 px-4 py-3 text-sm transition-colors hover:bg-muted/20">
                  <button
                    type="button"
                    className="flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted"
                    onClick={() => toggleExpanded(group.key)}
                    aria-label={expanded ? "collapse" : "expand"}
                  >
                    <ChevronDown aria-hidden className={cn("size-4 transition-transform", expanded && "rotate-180")} />
                  </button>
                  <Checkbox
                    checked={checkedState === true}
                    indeterminate={checkedState === "indeterminate"}
                    onCheckedChange={(value) => toggleGroup(groupSlugs, value === true)}
                  />
                  <button type="button" className="min-w-0 flex-1 text-left" onClick={() => toggleExpanded(group.key)}>
                    <div className="flex min-w-0 items-center gap-2">
                      <span className="min-w-0 truncate text-[15px] font-medium leading-6 text-foreground">
                        {group.label}
                      </span>
                      <span className="shrink-0 rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground">
                        {group.permissions.length}
                      </span>
                    </div>
                  </button>
                  <span className="shrink-0 tabular-nums text-xs text-muted-foreground">
                    {selectedCount}/{group.permissions.length}
                  </span>
                </div>
                {expanded ? (
                  <div className="pb-2">
                    {group.permissions.map((permission, index) => (
                      <label
                        key={permission.slug}
                        className={cn(
                          "flex cursor-pointer items-start gap-3 px-4 py-2.5 text-sm transition-colors hover:bg-muted/20",
                          index === 0 && "border-t border-border/50",
                          selectedSet.has(permission.slug) && "bg-muted/20",
                        )}
                      >
                        <span className="mt-1 flex h-4 w-8 shrink-0 items-center">
                          <span className="h-px w-full bg-border/70" />
                        </span>
                        <Checkbox
                          className="mt-0.5"
                          checked={selectedSet.has(permission.slug)}
                          onCheckedChange={(value) => toggleOne(permission.slug, value === true)}
                        />
                        <span className="min-w-0">
                          <div className="whitespace-normal break-words leading-6 text-foreground">
                            {resolvePermissionLabel(permission.slug, permission.name)}
                          </div>
                        </span>
                      </label>
                    ))}
                  </div>
                ) : null}
              </div>
            );
          })}
        </div>
      </ScrollArea>
    </div>
  );
}
