"use client"

import * as React from "react"
import { useRouter } from "next/navigation"
import { UserCog } from "lucide-react"

import { Button } from "@/shared/components/ui/button"
import { Checkbox } from "@/shared/components/ui/checkbox"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/shared/components/ui/dialog"
import { Badge } from "@/shared/components/ui/badge"
import { useActionMutation } from "@/shared/hooks/use-action-mutation"
import { useTranslations } from "next-intl"

import { assignUserRolesAction } from "../actions"

/** Minimal role shape needed by the assign dialog. Re-exported so the users
 * module can pass role data without importing the full RoleRecord type. */
export interface AssignableRole {
  id: string
  name: string
  description: string | null
  isSystem: boolean
  isEnabled: boolean
}

interface UserRoleAssignDialogProps {
  open: boolean
  onOpenChange: (open: boolean) => void
  userId: string
  userName: string
  userEmail: string
  /** All available roles (enabled ones are assignable). */
  allRoles: AssignableRole[]
  /** Role names currently assigned to the user. */
  currentRoleNames: string[]
}

/**
 * Dialog for assigning roles to a user. Renders a checkbox list of all
 * enabled roles. On save, the full role list is sent (replacement semantics).
 */
export function UserRoleAssignDialog({
  open,
  onOpenChange,
  userId,
  userName,
  userEmail,
  allRoles,
  currentRoleNames,
}: UserRoleAssignDialogProps) {
  const router = useRouter()
  const t = useTranslations("rbac")
  const [selected, setSelected] = React.useState<Set<string>>(
    new Set(currentRoleNames)
  )

  React.useEffect(() => {
    setSelected(new Set(currentRoleNames))
  }, [currentRoleNames])

  const assignMutation = useActionMutation({
    successMessage: t("messages.rolesAssigned"),
    onSuccess: () => {
      onOpenChange(false)
      router.refresh()
    },
  })

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

  const handleSave = (): void => {
    const formData = new FormData()
    formData.set("userId", userId)
    formData.set("roleNames", JSON.stringify(Array.from(selected)))
    void assignMutation.mutate(() => assignUserRolesAction(undefined, formData))
  }

  // Only enabled roles can be assigned; disabled roles are shown but read-only
  const enabledRoles = allRoles.filter((r) => r.isEnabled)
  const disabledAssignedRoles = allRoles.filter(
    (r) => !r.isEnabled && selected.has(r.name)
  )

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <UserCog className="h-5 w-5" />
            {t("roles.assignTitle")}
          </DialogTitle>
          <DialogDescription>
            {t.rich("roles.assignDescription", {
              name: userName || userEmail,
              strong: (chunks) => <strong>{chunks}</strong>,
            })}
          </DialogDescription>
        </DialogHeader>
        <div
          className="space-y-3 max-h-96 overflow-y-auto"
          role="group"
          aria-label={t("roles.assignListAriaLabel", { name: userName || userEmail })}
        >
          {enabledRoles.length === 0 && (
            <p className="text-sm text-muted-foreground py-4 text-center">
              {t("roles.noEnabledRoles")}
            </p>
          )}
          {enabledRoles.map((role) => {
            const isChecked = selected.has(role.name)
            const isAdmin = role.name === "admin"
            return (
              <label
                key={role.id}
                htmlFor={`role-${role.id}`}
                className="flex items-start gap-3 rounded-md border p-3 hover:bg-accent cursor-pointer"
              >
                <Checkbox
                  id={`role-${role.id}`}
                  checked={isChecked}
                  onCheckedChange={(checked) =>
                    handleToggle(role.name, checked === true)
                  }
                  disabled={assignMutation.isWorking}
                  className="mt-0.5"
                />
                <div className="space-y-0.5 min-w-0 flex-1">
                  <div className="flex items-center gap-2">
                    <span className="text-sm font-medium">{role.name}</span>
                    {role.isSystem && <Badge variant="secondary">{t("roles.system")}</Badge>}
                    {isAdmin && <Badge variant="destructive">{t("roles.locked")}</Badge>}
                  </div>
                  {role.description && (
                    <p className="text-xs text-muted-foreground">
                      {role.description}
                    </p>
                  )}
                </div>
              </label>
            )
          })}
          {disabledAssignedRoles.length > 0 && (
            <div className="space-y-1 pt-2 border-t">
              <p className="text-xs text-muted-foreground">
                {t("roles.disabledAssignedLabel")}
              </p>
              {disabledAssignedRoles.map((role) => (
                <div key={role.id} className="flex items-center gap-2 text-xs">
                  <Badge variant="outline">{role.name}</Badge>
                  <span className="text-muted-foreground">{t("roles.disabledLabel")}</span>
                </div>
              ))}
            </div>
          )}
        </div>
        <DialogFooter>
          <Button
            type="button"
            variant="outline"
            onClick={() => onOpenChange(false)}
            disabled={assignMutation.isWorking}
          >
            {t("actions.cancel")}
          </Button>
          <Button onClick={handleSave} disabled={assignMutation.isWorking}>
            {assignMutation.isWorking ? t("actions.saving") : t("roles.saveRoles")}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
