import { useState, useEffect } from 'react'
import { isAxiosError } from 'axios'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { Button } from '@/components/ui/button'
import { AlertCircle, CheckCircle2 } from 'lucide-react'
import { usePermisos } from '../hooks/usePermisos'
import { useRolPermisos } from '../hooks/useRolPermisos'
import { useAssignPermisos } from '../hooks/useAssignPermisos'
import type { PermisoDto } from '../api/types'

interface RolPermisosEditorProps {
  rolCodigo: string
}

function groupByModulo(permisos: PermisoDto[]): Map<string, PermisoDto[]> {
  const map = new Map<string, PermisoDto[]>()
  for (const p of permisos) {
    const modulo = p.codigo.split(':')[0] ?? p.modulo
    if (!map.has(modulo)) map.set(modulo, [])
    map.get(modulo)!.push(p)
  }
  return map
}

export function RolPermisosEditor({ rolCodigo }: RolPermisosEditorProps) {
  const { data: catalogo, isLoading: loadingCatalogo, isError: errorCatalogo } = usePermisos()
  const { data: asignados, isLoading: loadingAsignados, isError: errorAsignados } = useRolPermisos(rolCodigo)
  const assignMut = useAssignPermisos()

  const [selected, setSelected] = useState<Set<string>>(new Set())
  const [saved, setSaved] = useState(false)

  // Prefill checkboxes cuando lleguen los permisos asignados al rol
  useEffect(() => {
    if (asignados) {
      // eslint-disable-next-line react-hooks/set-state-in-effect -- sincroniza prop externa (asignados) con estado local; patrón válido de derived state
      setSelected(new Set(asignados.map((p) => p.codigo)))
      setSaved(false)
    }
  }, [asignados])

  if (loadingCatalogo || loadingAsignados) {
    return <p className="text-sm text-muted-foreground">Cargando permisos...</p>
  }

  if (errorCatalogo || errorAsignados) {
    return (
      <Alert variant="destructive">
        <AlertCircle className="h-4 w-4" />
        <AlertDescription>Error al cargar los permisos del rol.</AlertDescription>
      </Alert>
    )
  }

  if (!catalogo || catalogo.length === 0) {
    return <p className="text-sm text-muted-foreground">No hay permisos registrados en el sistema.</p>
  }

  const grupos = groupByModulo(catalogo)

  function toggle(codigo: string) {
    setSelected((prev) => {
      const next = new Set(prev)
      if (next.has(codigo)) next.delete(codigo)
      else next.add(codigo)
      return next
    })
    setSaved(false)
  }

  function handleSave() {
    assignMut.mutate(
      { rolCodigo, payload: { codigos: Array.from(selected) } },
      {
        onSuccess: () => setSaved(true),
      },
    )
  }

  const saveErrMsg = assignMut.error
    ? isAxiosError(assignMut.error)
      ? assignMut.error.response?.status === 400
        ? 'El rol "admin" no puede quedar sin permisos.'
        : (assignMut.error.response?.data as { message?: string } | undefined)?.message ??
          'No se pudieron guardar los cambios.'
      : 'No se pudieron guardar los cambios.'
    : null

  return (
    <div className="space-y-6">
      {saveErrMsg && (
        <Alert variant="destructive" role="alert">
          <AlertCircle className="h-4 w-4" />
          <AlertDescription>{saveErrMsg}</AlertDescription>
        </Alert>
      )}

      {saved && (
        <Alert role="status">
          <CheckCircle2 className="h-4 w-4" />
          <AlertDescription>Permisos guardados correctamente.</AlertDescription>
        </Alert>
      )}

      {Array.from(grupos.entries()).map(([modulo, permisos]) => (
        <section key={modulo}>
          <h3 className="text-sm font-semibold uppercase tracking-wider text-muted-foreground mb-3 capitalize">
            {modulo}
          </h3>
          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2">
            {permisos.map((p) => (
              <label
                key={p.codigo}
                title={p.descripcion ?? p.codigo}
                className="flex items-center gap-2 rounded-md border border-border px-3 py-2 text-sm cursor-pointer hover:bg-accent hover:text-accent-foreground transition-colors"
              >
                <input
                  type="checkbox"
                  checked={selected.has(p.codigo)}
                  onChange={() => toggle(p.codigo)}
                  className="h-4 w-4 accent-primary shrink-0"
                  aria-label={p.nombre}
                />
                <span className="flex-1 truncate">{p.nombre}</span>
                <span className="font-mono text-xs text-muted-foreground/70 hidden lg:block shrink-0">
                  {p.codigo}
                </span>
              </label>
            ))}
          </div>
        </section>
      ))}

      <div className="flex justify-end pt-2">
        <Button onClick={handleSave} disabled={assignMut.isPending}>
          {assignMut.isPending ? 'Guardando...' : 'Guardar cambios'}
        </Button>
      </div>
    </div>
  )
}
