"use client"

import { useEffect, useState } from "react"
import { useParams, useRouter } from "next/navigation"
import Link from "next/link"
import { AlertTriangle, Save } from "lucide-react"

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

import { RolePermissionTree } from "@/components/auth/RolePermissionTree"
import { Button, buttonVariants } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { FieldError } from "@/components/ui/field"
import { Badge } from "@/components/ui/badge"
import { Skeleton } from "@/components/ui/skeleton"
import { toast } from "@/components/ui/toast"

export default function RoleDetailPage() {
  const params = useParams<{ id: string }>()
  const router = useRouter()
  const roleId = Number(params.id)

  const [role, setRole] = useState<Role | null>(null)
  const [etag, setEtag] = useState<string | null>(null)
  const [tree, setTree] = useState<NavItem[] | null>(null)
  const [loadError, setLoadError] = useState<string | null>(null)

  const [code, setCode] = useState("")
  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 [conflict, setConflict] = useState(false)
  const [saveError, setSaveError] = useState<string | null>(null)
  const [saving, setSaving] = useState(false)
  const [savingPermissions, setSavingPermissions] = useState(false)

  function load() {
    setLoadError(null)
    Promise.all([rolesApi.get(roleId), navApi.tree(), rolesApi.getPermissions(roleId)])
      .then(([roleResult, navTree, permissions]) => {
        setRole(roleResult.data)
        setEtag(roleResult.etag)
        setCode(roleResult.data.code)
        setName(roleResult.data.name)
        setTree(navTree)
        setNavItemIds(new Set(permissions.navItemIds))
        setSubNavItemIds(new Set(permissions.subNavItemIds))
        setConflict(false)
      })
      .catch((err) => setLoadError(errorMessage(err)))
  }

  useEffect(() => {
    if (Number.isFinite(roleId)) load()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [roleId])

  async function handleSave() {
    setSaveError(null)
    const nextErrors: Record<string, string> = {}
    if (!code.trim()) nextErrors.code = "Role code is required"
    if (!name.trim()) nextErrors.name = "Role name is required"
    setErrors(nextErrors)
    if (Object.keys(nextErrors).length > 0 || !etag) return

    setSaving(true)
    try {
      const result = await rolesApi.update(roleId, { code: code.trim().toUpperCase(), name: name.trim() }, etag)
      setRole(result.data)
      setEtag(result.etag)
      toast.success("Role saved", `${result.data.code} — ${result.data.name}`)
    } catch (err) {
      const errCode = (err as { code?: string })?.code
      if (errCode === "CONCURRENCY_CONFLICT") {
        setConflict(true)
        setSaveError(errorMessage(err))
        setSaving(false)
        return
      }
      const fe = fieldErrors(err)
      if (fe?.code) setErrors({ code: fe.code })
      setSaveError(errorMessage(err))
      toast.error("Could not save role", errorMessage(err))
    } finally {
      setSaving(false)
    }
  }

  async function handleSavePermissions() {
    setSavingPermissions(true)
    try {
      await rolesApi.assignPermissions(roleId, {
        navItemIds: Array.from(navItemIds),
        subNavItemIds: Array.from(subNavItemIds),
      })
      toast.success("Permissions saved", "This role's visible sidebar sections have been updated.")
    } catch (err) {
      toast.error("Could not save permissions", errorMessage(err))
    } finally {
      setSavingPermissions(false)
    }
  }

  if (loadError && !role) {
    return (
      <div className="flex flex-col gap-4">
        <div className="rounded-lg border border-destructive/30 bg-destructive/5 p-5 text-base text-destructive">{loadError}</div>
        <Link href="/dashboard/settings/roles" className={cn(buttonVariants({ variant: "outline" }))}>
          Back to roles
        </Link>
      </div>
    )
  }

  if (!role || !tree) {
    return (
      <div className="flex flex-col gap-3">
        <Skeleton className="h-10 w-72" />
        <Skeleton className="h-48 w-full" />
      </div>
    )
  }

  return (
    <div className="flex flex-col gap-8">
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-3">
          <div>
            <div className="flex items-center gap-3">
              <h1 className="text-2xl font-bold text-foreground">{role.code}</h1>
              <Badge
                variant="outline"
                className={cn(
                  "h-6 w-fit justify-center border-transparent px-2.5 text-sm",
                  role.status === "Active" ? "bg-success/10 text-success" : "bg-muted text-muted-foreground"
                )}
              >
                {role.status}
              </Badge>
            </div>
            <p className="text-base text-muted-foreground">{role.name}</p>
          </div>
        </div>
      </div>

      {conflict && (
        <div className="flex items-start gap-3 rounded-lg border border-warning/30 bg-warning/5 p-5 text-base text-warning">
          <AlertTriangle className="size-5 shrink-0" />
          <div className="flex flex-col gap-2">
            <p>{saveError ?? "This role was changed by someone else."} Reload before retrying.</p>
            <Button size="sm" variant="outline" onClick={load}>
              Reload
            </Button>
          </div>
        </div>
      )}

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

      <section className="flex flex-col gap-4">
        <h2 className="text-lg font-semibold text-foreground">Details</h2>
        <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
          <div className="flex flex-col gap-2">
            <Label className="text-base">Code</Label>
            <Input value={code} readOnly disabled className="h-12 text-base text-muted-foreground" />
          </div>
          <div className="flex flex-col gap-2">
            <Label className="text-base">Name</Label>
            <Input value={name} onChange={(e) => setName(e.target.value)} aria-invalid={!!errors.name} className="h-12 text-base" disabled={conflict} />
            <FieldError errors={[errors.name ? { message: errors.name } : undefined]} />
          </div>
        </div>
        <div className="flex justify-end">
          <Button onClick={handleSave} disabled={saving || conflict}>
            <Save className="size-4" />
            {saving ? "Saving…" : "Save details"}
          </Button>
        </div>
      </section>

      <section className="flex flex-col gap-4">
        <div>
          <h2 className="text-lg font-semibold text-foreground">Sidebar permissions</h2>
          <p className="text-sm text-muted-foreground">Choose which sections a user with this role can see.</p>
        </div>
        <RolePermissionTree
          tree={tree}
          selectedNavItemIds={navItemIds}
          selectedSubNavItemIds={subNavItemIds}
          onChange={(nav, sub) => {
            setNavItemIds(nav)
            setSubNavItemIds(sub)
          }}
        />
        <div className="flex justify-end">
          <Button onClick={handleSavePermissions} disabled={savingPermissions}>
            <Save className="size-4" />
            {savingPermissions ? "Saving…" : "Save permissions"}
          </Button>
        </div>
      </section>

      <div className="flex justify-end">
        <Button variant="outline" onClick={() => router.push("/dashboard/settings/roles")}>
          Back to roles
        </Button>
      </div>
    </div>
  )
}
