"use client"

import * as React from "react"
import { useRouter } from "next/navigation"
import { Save, Lock, Search, ChevronDown, Users } from "lucide-react"

import { Button } from "@/shared/components/ui/button"
import { Checkbox } from "@/shared/components/ui/checkbox"
import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card"
import { Badge } from "@/shared/components/ui/badge"
import { Input } from "@/shared/components/ui/input"
import { Alert, AlertDescription } from "@/shared/components/ui/alert"
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/shared/components/ui/collapsible"
import { useActionMutation } from "@/shared/hooks/use-action-mutation"
import { useTranslations } from "next-intl"
import { cn } from "@/shared/lib/utils"
import type { Permission } from "@/shared/types/permissions"

import { setRolePermissionsAction } from "../actions"
import { PERMISSION_CATALOG, type PermissionMeta } from "../lib/permission-catalog"

interface RolePermissionMatrixProps {
  roleId: string
  roleName: string
  /** Permissions currently assigned to the role. */
  currentPermissions: Permission[]
  /** Whether this role's permissions are locked (admin role). */
  isLocked: boolean
  /** Number of users assigned to this role (for the impact notice). */
  userCount: number
}

/**
 * Permission assignment matrix.
 *
 * Renders all permissions grouped by module with checkboxes. The user can
 * toggle individual permissions or select/deselect all in a group. On save,
 * the full permission list is sent to the server (replacement semantics).
 *
 * Features:
 * - Searchable by permission name/label/value.
 * - Collapsible groups (default expanded; auto-expand while searching).
 * - Impact notice when the role has assigned users.
 *
 * The `admin` role is read-only (`isLocked = true`).
 */
export function RolePermissionMatrix({
  roleId,
  roleName,
  currentPermissions,
  isLocked,
  userCount,
}: RolePermissionMatrixProps) {
  const t = useTranslations("rbac")
  const router = useRouter()
  const [selected, setSelected] = React.useState<Set<string>>(
    new Set(currentPermissions)
  )
  const [search, setSearch] = React.useState("")
  const [collapsedGroups, setCollapsedGroups] = React.useState<Set<string>>(
    new Set()
  )

  // Reset local state when the prop changes (e.g. after server refresh)
  React.useEffect(() => {
    setSelected(new Set(currentPermissions))
  }, [currentPermissions])

  const saveMutation = useActionMutation({
    successMessage: t("messages.permissionsUpdated"),
    onSuccess: () => router.refresh(),
  })

  const normalizedSearch = search.trim().toLowerCase()

  const matchesSearch = (perm: PermissionMeta): boolean => {
    if (!normalizedSearch) return true
    if (perm.value.toLowerCase().includes(normalizedSearch)) return true
    if (perm.key.toLowerCase().includes(normalizedSearch)) return true
    const labelKey = perm.labelKey.replace("rbac:", "")
    if (t.has(labelKey)) {
      const label = String(t(labelKey)).toLowerCase()
      if (label.includes(normalizedSearch)) return true
    }
    return false
  }

  const filteredCatalog = PERMISSION_CATALOG.map((group) => ({
    ...group,
    permissions: group.permissions.filter(matchesSearch),
  })).filter((group) => group.permissions.length > 0)

  // Auto-expand all groups while a search query is active.
  React.useEffect(() => {
    if (normalizedSearch) {
      setCollapsedGroups(new Set())
    }
  }, [normalizedSearch])

  const handleToggle = (permission: string, checked: boolean): void => {
    setSelected((prev) => {
      const next = new Set(prev)
      if (checked) next.add(permission)
      else next.delete(permission)
      return next
    })
  }

  const handleToggleGroup = (groupPermissions: string[], checked: boolean): void => {
    setSelected((prev) => {
      const next = new Set(prev)
      for (const p of groupPermissions) {
        if (checked) next.add(p)
        else next.delete(p)
      }
      return next
    })
  }

  const handleToggleCollapse = (group: string): void => {
    setCollapsedGroups((prev) => {
      const next = new Set(prev)
      if (next.has(group)) next.delete(group)
      else next.add(group)
      return next
    })
  }

  const handleSave = (): void => {
    const formData = new FormData()
    formData.set("roleId", roleId)
    formData.set("permissions", JSON.stringify(Array.from(selected)))
    void saveMutation.mutate(() => setRolePermissionsAction(undefined, formData))
  }

  const hasChanges = !setsEqual(selected, new Set(currentPermissions))

  return (
    <Card>
      <CardHeader className="flex flex-row items-center justify-between space-y-0">
        <div className="flex items-center gap-2">
          <CardTitle className="text-base">{t("permissions.matrixTitle", { roleName })}</CardTitle>
          {isLocked && (
            <Badge variant="secondary">
              <Lock className="mr-1 h-3 w-3" />
              {t("roles.locked")}
            </Badge>
          )}
          <Badge variant="outline">{t("permissions.selectedCount", { count: selected.size })}</Badge>
        </div>
        {!isLocked && (
          <Button
            onClick={handleSave}
            disabled={!hasChanges || saveMutation.isWorking}
            size="sm"
          >
            <Save className="mr-2 h-4 w-4" />
            {saveMutation.isWorking ? t("actions.saving") : t("actions.save")}
          </Button>
        )}
      </CardHeader>
      <CardContent className={isLocked ? "pointer-events-none opacity-60" : ""}>
        {userCount > 0 && (
          <Alert className="mb-4 border-amber-500/50 bg-amber-50 text-amber-700 dark:bg-amber-950/20 dark:text-amber-400">
            <Users className="h-4 w-4 translate-y-0.5" />
            <AlertDescription>
              {t("permissions.impactNotice", { count: userCount })}
            </AlertDescription>
          </Alert>
        )}

        <div className="mb-4">
          <div className="relative">
            <Search className="absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
            <Input
              type="search"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder={t("permissions.searchPlaceholder")}
              className="pl-8"
              aria-label={t("permissions.searchAriaLabel")}
            />
          </div>
        </div>

        {filteredCatalog.length === 0 ? (
          <p className="text-sm text-muted-foreground py-4 text-center">
            {t("permissions.searchNoResults")}
          </p>
        ) : (
          <div className="space-y-4">
            {filteredCatalog.map((group) => {
              const groupPermValues = group.permissions.map((p) => p.value)
              const selectedInGroup = groupPermValues.filter((p) => selected.has(p))
              const allChecked = selectedInGroup.length === groupPermValues.length
              const someChecked = selectedInGroup.length > 0 && !allChecked
              const isCollapsed = !normalizedSearch && collapsedGroups.has(group.group)
              const groupLabel = t.has(group.labelKey.replace("rbac:", ""))
                ? t(group.labelKey.replace("rbac:", ""))
                : group.group

              return (
                <Collapsible
                  key={group.group}
                  open={!isCollapsed}
                  onOpenChange={() => handleToggleCollapse(group.group)}
                >
                  <fieldset className="space-y-2">
                    <legend className="flex w-full items-center gap-2 border-b pb-2">
                      <Checkbox
                        id={`group-${group.group}`}
                        checked={allChecked ? true : someChecked ? "indeterminate" : false}
                        onCheckedChange={(checked) =>
                          handleToggleGroup(groupPermValues, checked === true)
                        }
                        disabled={isLocked}
                        onClick={(e) => e.stopPropagation()}
                      />
                      <label
                        htmlFor={`group-${group.group}`}
                        className="flex-1 cursor-pointer text-sm font-semibold"
                      >
                        {groupLabel}
                      </label>
                      <Badge variant="outline">
                        {selectedInGroup.length} / {groupPermValues.length}
                      </Badge>
                      <CollapsibleTrigger asChild>
                        <button
                          type="button"
                          className="inline-flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent"
                          aria-label={
                            isCollapsed
                              ? t("permissions.expandGroup", { name: groupLabel })
                              : t("permissions.collapseGroup", { name: groupLabel })
                          }
                          aria-expanded={!isCollapsed}
                        >
                          <ChevronDown
                            className={cn(
                              "h-4 w-4 transition-transform",
                              isCollapsed ? "" : "rotate-180"
                            )}
                          />
                        </button>
                      </CollapsibleTrigger>
                    </legend>
                    <CollapsibleContent>
                      <div className="grid grid-cols-1 gap-2 pt-2 sm:grid-cols-2 lg:grid-cols-3">
                        {group.permissions.map((perm) => {
                          const isChecked = selected.has(perm.value)
                          const permLabel = t.has(perm.labelKey.replace("rbac:", ""))
                            ? t(perm.labelKey.replace("rbac:", ""))
                            : perm.key
                          return (
                            <label
                              key={perm.key}
                              htmlFor={perm.key}
                              className="flex items-start gap-2 rounded-md border p-2 hover:bg-accent cursor-pointer"
                            >
                              <Checkbox
                                id={perm.key}
                                checked={isChecked}
                                onCheckedChange={(checked) =>
                                  handleToggle(perm.value, checked === true)
                                }
                                disabled={isLocked}
                                className="mt-0.5"
                              />
                              <div className="min-w-0 space-y-0.5">
                                <p className="text-sm font-medium leading-tight">
                                  {permLabel}
                                </p>
                                <p className="truncate font-mono text-xs text-muted-foreground">
                                  {perm.value}
                                </p>
                              </div>
                            </label>
                          )
                        })}
                      </div>
                    </CollapsibleContent>
                  </fieldset>
                </Collapsible>
              )
            })}
          </div>
        )}
      </CardContent>
    </Card>
  )
}

function setsEqual<T>(a: Set<T>, b: Set<T>): boolean {
  if (a.size !== b.size) return false
  for (const v of a) if (!b.has(v)) return false
  return true
}
