"use client"

import { useEffect, useState } from "react"
import Link from "next/link"
import { Pencil, Plus, ShieldCheck, Trash2 } from "lucide-react"

import { navApi } from "@/lib/api/nav"
import { rolesApi } from "@/lib/api/roles"
import { errorMessage } from "@/lib/error-map"
import { cn } from "@/lib/utils"
import { PaginationMeta } from "@/types/common"
import { NavItem, Role } from "@/types/rbac"

import { RolePermissionTree } from "@/components/auth/RolePermissionTree"
import { AlertDialog, AlertDialogContent, AlertDialogTrigger } from "@/components/ui/alert-dialog"
import { Button, buttonVariants } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Badge } from "@/components/ui/badge"
import { Field, FieldError, FieldGroup, FieldLabel } from "@/components/ui/field"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Skeleton } from "@/components/ui/skeleton"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { toast } from "@/components/ui/toast"

const PAGE_SIZE = 10

/** Code is derived from Name, never typed directly (e.g. "Store Manager" -> "STORE_MANAGER"). */
function deriveCode(name: string): string {
  return name
    .trim()
    .toUpperCase()
    .replace(/[^A-Z0-9]+/g, "_")
    .replace(/^_+|_+$/g, "")
}

export default function RolesPage() {
  const [roles, setRoles] = useState<Role[] | null>(null)
  const [pagination, setPagination] = useState<PaginationMeta | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [page, setPage] = useState(1)

  const [tree, setTree] = useState<NavItem[] | null>(null)

  const [open, setOpen] = useState(false)
  const [name, setName] = useState("")
  const [navItemIds, setNavItemIds] = useState<Set<number>>(new Set())
  const [subNavItemIds, setSubNavItemIds] = useState<Set<number>>(new Set())
  const [errors, setErrors] = useState<Record<string, string>>({})
  const [submitting, setSubmitting] = useState(false)
  const [actionPendingId, setActionPendingId] = useState<number | null>(null)

  function load() {
    rolesApi
      .list({ page, pageSize: PAGE_SIZE })
      .then((res) => {
        setRoles(res.items)
        setPagination(res.pagination)
      })
      .catch((err) => setError(errorMessage(err)))
  }

  useEffect(load, [page])

  useEffect(() => {
    navApi.tree().then(setTree).catch(() => setTree([]))
  }, [])

  function resetForm() {
    setName("")
    setNavItemIds(new Set())
    setSubNavItemIds(new Set())
    setErrors({})
  }

  const code = deriveCode(name)

  async function handleCreate() {
    const nextErrors: Record<string, string> = {}
    if (!name.trim()) nextErrors.name = "Role name is required"
    else if (!code) nextErrors.name = "Role name must contain at least one letter or number"
    setErrors(nextErrors)
    if (Object.keys(nextErrors).length > 0) return

    setSubmitting(true)
    try {
      const result = await rolesApi.create({ code, name: name.trim() })
      if (navItemIds.size > 0 || subNavItemIds.size > 0) {
        await rolesApi.assignPermissions(result.data.roleId, {
          navItemIds: Array.from(navItemIds),
          subNavItemIds: Array.from(subNavItemIds),
        })
      }
      toast.success("Role created", `${result.data.code} — ${result.data.name}`)
      setOpen(false)
      resetForm()
      load()
    } catch (err) {
      toast.error("Could not create role", errorMessage(err))
    } finally {
      setSubmitting(false)
    }
  }

  async function handleDelete(role: Role) {
    setActionPendingId(role.roleId)
    try {
      await rolesApi.remove(role.roleId)
      toast.success("Role deleted", `${role.code} has been removed.`)
      load()
    } catch (err) {
      toast.error("Could not delete role", errorMessage(err))
    } finally {
      setActionPendingId(null)
    }
  }

  return (
    <div className="flex flex-col gap-6">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <h1 className="text-2xl font-bold text-foreground">Roles</h1>
          <p className="text-base text-muted-foreground">
            Manage roles and which sidebar sections each one can see.
          </p>
        </div>

        <Dialog
          open={open}
          onOpenChange={(v) => {
            setOpen(v)
            if (!v) resetForm()
          }}
        >
          <DialogTrigger
            render={
              <Button size="lg">
                <Plus className="size-5" />
                New Role
              </Button>
            }
          />
          <DialogContent className="sm:max-w-lg">
            <DialogHeader className="items-center text-center">
              <DialogTitle>New role</DialogTitle>
              <DialogDescription>Created in both the auth service and here.</DialogDescription>
            </DialogHeader>
            <FieldGroup>
              <Field data-invalid={!!errors.name}>
                <FieldLabel htmlFor="r-name">Name</FieldLabel>
                <Input id="r-name" value={name} onChange={(e) => setName(e.target.value)} placeholder="Manager" aria-invalid={!!errors.name} />
                <FieldError errors={[errors.name ? { message: errors.name } : undefined]} />
              </Field>
              <Field>
                <FieldLabel htmlFor="r-code">Code (auto-generated)</FieldLabel>
                <Input id="r-code" value={code} disabled readOnly placeholder="—" className="text-muted-foreground" />
              </Field>
            </FieldGroup>

            <div className="flex flex-col gap-2">
              <FieldLabel>Sidebar permissions</FieldLabel>
              {tree === null ? (
                <Skeleton className="h-32 w-full" />
              ) : (
                <div className="max-h-80 overflow-auto">
                  <RolePermissionTree
                    tree={tree}
                    selectedNavItemIds={navItemIds}
                    selectedSubNavItemIds={subNavItemIds}
                    onChange={(nav, sub) => {
                      setNavItemIds(nav)
                      setSubNavItemIds(sub)
                    }}
                  />
                </div>
              )}
            </div>

            <div className="flex flex-col-reverse gap-3 pt-2 sm:flex-row sm:justify-center">
              <Button variant="outline" className="w-full sm:w-auto sm:min-w-36" onClick={() => setOpen(false)} disabled={submitting}>
                Cancel
              </Button>
              <Button className="w-full sm:w-auto sm:min-w-36" onClick={handleCreate} disabled={submitting}>
                {submitting ? "Creating…" : "Create"}
              </Button>
            </div>
          </DialogContent>
        </Dialog>
      </div>

      {error && (
        <div className="rounded-lg border border-destructive/30 bg-destructive/5 p-5 text-base text-destructive">{error}</div>
      )}

      {!error && roles === null && (
        <div className="flex flex-col gap-3">
          {Array.from({ length: 4 }).map((_, i) => (
            <Skeleton key={i} className="h-14 w-full" />
          ))}
        </div>
      )}

      {!error && roles !== null && roles.length === 0 && (
        <div className="flex flex-col items-center gap-4 rounded-xl border border-dashed py-20 text-center">
          <ShieldCheck className="size-12 text-muted-foreground" />
          <p className="text-base text-muted-foreground">No roles yet.</p>
        </div>
      )}

      {!error && roles !== null && roles.length > 0 && (
        <Table className="text-base">
          <TableHeader>
            <TableRow>
              <TableHead className="h-12 px-3 text-sm">Code</TableHead>
              <TableHead className="h-12 px-3 text-sm">Name</TableHead>
              <TableHead className="h-12 px-3 text-sm">Status</TableHead>
              <TableHead className="h-12 px-3 text-sm">Actions</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {roles.map((r) => (
              <TableRow key={r.roleId}>
                <TableCell className="px-3 py-3.5 font-medium">{r.code}</TableCell>
                <TableCell className="px-3 py-3.5">{r.name}</TableCell>
                <TableCell className="px-3 py-3.5">
                  <Badge
                    variant="outline"
                    className={cn(
                      "h-6 w-fit justify-center border-transparent px-2.5 text-sm",
                      r.status === "Active" ? "bg-success/10 text-success" : "bg-muted text-muted-foreground"
                    )}
                  >
                    {r.status}
                  </Badge>
                </TableCell>
                <TableCell className="px-3 py-3.5">
                  <div className="flex items-center gap-1">
                    <Link
                      href={`/dashboard/settings/roles/${r.roleId}`}
                      className={cn(buttonVariants({ variant: "ghost", size: "icon-sm" }))}
                      aria-label={`Edit ${r.code}`}
                    >
                      <Pencil className="size-4" />
                    </Link>

                    <AlertDialog>
                      <AlertDialogTrigger
                        render={
                          <Button
                            variant="ghost"
                            size="icon-sm"
                            className="text-destructive hover:bg-destructive/10"
                            aria-label={`Delete ${r.code}`}
                            disabled={r.isSystemRole || actionPendingId === r.roleId}
                          />
                        }
                      >
                        <Trash2 className="size-4" />
                      </AlertDialogTrigger>
                      <AlertDialogContent
                        variant="destructive"
                        title={`Delete ${r.code}?`}
                        description={`This removes the role from both the auth service and here. Blocked if any user still holds it.`}
                        confirmLabel="Delete"
                        onConfirm={() => handleDelete(r)}
                      />
                    </AlertDialog>
                  </div>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      )}

      {pagination && pagination.totalPages > 1 && (
        <div className="flex items-center justify-between">
          <p className="text-sm text-muted-foreground">
            Showing {(pagination.page - 1) * pagination.pageSize + 1}–
            {Math.min(pagination.page * pagination.pageSize, pagination.totalItems)} of {pagination.totalItems}
          </p>
          <div className="flex items-center gap-2">
            <Button type="button" variant="outline" size="sm" disabled={pagination.page <= 1} onClick={() => setPage((p) => Math.max(1, p - 1))}>
              Previous
            </Button>
            <span className="text-sm text-muted-foreground">
              Page {pagination.page} of {pagination.totalPages}
            </span>
            <Button
              type="button"
              variant="outline"
              size="sm"
              disabled={pagination.page >= pagination.totalPages}
              onClick={() => setPage((p) => Math.min(pagination.totalPages, p + 1))}
            >
              Next
            </Button>
          </div>
        </div>
      )}
    </div>
  )
}
