import { useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Switch } from "@/components/ui/switch";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import {
  Plus, Search, Trash2, Pencil, Shield, Key, Users, Loader2, ChevronRight,
} from "lucide-react";
import { useToast } from "@/hooks/use-toast";
import { rolesService } from "@/services/roles.service";
import type { Role, Permission, RoleCreateRequest, PermissionCreateRequest } from "@/types/role-permission";

const CATEGORY_COLORS: Record<string, string> = {
  exam: "bg-violet-100 text-violet-700 dark:bg-violet-900 dark:text-violet-300",
  user: "bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300",
  entity: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900 dark:text-emerald-300",
  assignment: "bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300",
  classroom: "bg-rose-100 text-rose-700 dark:bg-rose-900 dark:text-rose-300",
  payment: "bg-cyan-100 text-cyan-700 dark:bg-cyan-900 dark:text-cyan-300",
  report: "bg-orange-100 text-orange-700 dark:bg-orange-900 dark:text-orange-300",
};

function categoryBadgeClass(cat: string) {
  return CATEGORY_COLORS[cat.toLowerCase()] ?? "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300";
}

export default function RolesPermissions() {
  const { toast } = useToast();
  const qc = useQueryClient();
  const [search, setSearch] = useState("");
  const [tab, setTab] = useState("roles");

  const [roleDialogOpen, setRoleDialogOpen] = useState(false);
  const [editingRole, setEditingRole] = useState<Role | null>(null);
  const [roleForm, setRoleForm] = useState<RoleCreateRequest>({ name: "", description: "" });

  const [permDialogOpen, setPermDialogOpen] = useState(false);
  const [permForm, setPermForm] = useState<PermissionCreateRequest>({ name: "", code: "", description: "", category: "" });

  const [permAssignOpen, setPermAssignOpen] = useState(false);
  const [assigningRole, setAssigningRole] = useState<Role | null>(null);
  const [selectedPermIds, setSelectedPermIds] = useState<Set<number>>(new Set());

  const rolesQ = useQuery({ queryKey: ["roles", search], queryFn: () => rolesService.listRoles(search ? { search } : undefined) });
  const permsQ = useQuery({ queryKey: ["permissions"], queryFn: () => rolesService.listPermissions() });

  const roles: Role[] = rolesQ.data?.data ?? [];
  const permissions: Permission[] = permsQ.data?.data ?? [];

  const createRoleMut = useMutation({
    mutationFn: (d: RoleCreateRequest) => rolesService.createRole(d),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ["roles"] }); setRoleDialogOpen(false); toast({ title: "Role created" }); },
    onError: () => toast({ title: "Failed to create role", variant: "destructive" }),
  });
  const updateRoleMut = useMutation({
    mutationFn: ({ id, data }: { id: number; data: Partial<RoleCreateRequest> }) => rolesService.updateRole(id, data),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ["roles"] }); setRoleDialogOpen(false); setEditingRole(null); toast({ title: "Role updated" }); },
    onError: () => toast({ title: "Failed to update role", variant: "destructive" }),
  });
  const deleteRoleMut = useMutation({
    mutationFn: rolesService.deleteRole,
    onSuccess: () => { qc.invalidateQueries({ queryKey: ["roles"] }); toast({ title: "Role deleted" }); },
    onError: () => toast({ title: "Failed to delete role", variant: "destructive" }),
  });
  const assignPermsMut = useMutation({
    mutationFn: ({ id, permIds }: { id: number; permIds: number[] }) => rolesService.updateRolePermissions(id, permIds),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ["roles"] }); setPermAssignOpen(false); toast({ title: "Permissions updated" }); },
    onError: () => toast({ title: "Failed to update permissions", variant: "destructive" }),
  });
  const createPermMut = useMutation({
    mutationFn: (d: PermissionCreateRequest) => rolesService.createPermission(d),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ["permissions"] }); setPermDialogOpen(false); toast({ title: "Permission created" }); },
    onError: () => toast({ title: "Failed to create permission", variant: "destructive" }),
  });
  const deletePermMut = useMutation({
    mutationFn: rolesService.deletePermission,
    onSuccess: () => { qc.invalidateQueries({ queryKey: ["permissions"] }); toast({ title: "Permission deleted" }); },
    onError: () => toast({ title: "Failed to delete permission", variant: "destructive" }),
  });

  const loading = rolesQ.isLoading || permsQ.isLoading;

  const openNewRole = () => { setEditingRole(null); setRoleForm({ name: "", description: "" }); setRoleDialogOpen(true); };
  const openEditRole = (r: Role) => { setEditingRole(r); setRoleForm({ name: r.name, description: r.description }); setRoleDialogOpen(true); };
  const openAssignPerms = (r: Role) => { setAssigningRole(r); setSelectedPermIds(new Set(r.permission_ids)); setPermAssignOpen(true); };
  const openNewPerm = () => { setPermForm({ name: "", code: "", description: "", category: "" }); setPermDialogOpen(true); };

  const handleSaveRole = () => {
    if (!roleForm.name.trim()) return;
    if (editingRole) {
      updateRoleMut.mutate({ id: editingRole.id, data: roleForm });
    } else {
      createRoleMut.mutate(roleForm);
    }
  };

  const togglePerm = (pid: number) => {
    setSelectedPermIds(prev => { const s = new Set(prev); if (s.has(pid)) s.delete(pid); else s.add(pid); return s; });
  };

  const categorizedPerms = permissions.reduce<Record<string, Permission[]>>((acc, p) => {
    const cat = p.category || "General";
    (acc[cat] ??= []).push(p);
    return acc;
  }, {});

  const filteredPerms = search
    ? permissions.filter(p => p.name.toLowerCase().includes(search.toLowerCase()) || p.code.toLowerCase().includes(search.toLowerCase()))
    : permissions;

  if (loading) {
    return <div className="flex items-center justify-center min-h-[400px]"><Loader2 className="h-8 w-8 animate-spin text-primary" /></div>;
  }

  return (
    <div className="space-y-6">
      {/* Header */}
      <div className="flex flex-wrap items-center justify-between gap-4">
        <div>
          <h1 className="text-2xl font-bold flex items-center gap-2">
            <Shield className="h-7 w-7 text-primary" />
            Roles & Permissions
          </h1>
          <p className="text-muted-foreground">Manage platform roles and their permission assignments.</p>
        </div>
        <div className="flex gap-2">
          {tab === "roles" ? (
            <Button onClick={openNewRole}><Plus className="mr-2 h-4 w-4" /> New Role</Button>
          ) : (
            <Button onClick={openNewPerm}><Plus className="mr-2 h-4 w-4" /> New Permission</Button>
          )}
        </div>
      </div>

      {/* Summary Cards */}
      <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
        <Card className="border-l-4 border-l-primary">
          <CardContent className="pt-5 pb-4">
            <div className="flex items-center gap-3">
              <div className="h-10 w-10 rounded-lg bg-primary/10 flex items-center justify-center"><Shield className="h-5 w-5 text-primary" /></div>
              <div><p className="text-2xl font-bold">{roles.length}</p><p className="text-xs text-muted-foreground">Total Roles</p></div>
            </div>
          </CardContent>
        </Card>
        <Card className="border-l-4 border-l-amber-500">
          <CardContent className="pt-5 pb-4">
            <div className="flex items-center gap-3">
              <div className="h-10 w-10 rounded-lg bg-amber-500/10 flex items-center justify-center"><Key className="h-5 w-5 text-amber-500" /></div>
              <div><p className="text-2xl font-bold">{permissions.length}</p><p className="text-xs text-muted-foreground">Total Permissions</p></div>
            </div>
          </CardContent>
        </Card>
        <Card className="border-l-4 border-l-emerald-500">
          <CardContent className="pt-5 pb-4">
            <div className="flex items-center gap-3">
              <div className="h-10 w-10 rounded-lg bg-emerald-500/10 flex items-center justify-center"><Users className="h-5 w-5 text-emerald-500" /></div>
              <div><p className="text-2xl font-bold">{Object.keys(categorizedPerms).length}</p><p className="text-xs text-muted-foreground">Permission Categories</p></div>
            </div>
          </CardContent>
        </Card>
      </div>

      {/* Tabs */}
      <Tabs value={tab} onValueChange={setTab}>
        <div className="flex flex-wrap items-center justify-between gap-3">
          <TabsList>
            <TabsTrigger value="roles" className="gap-1.5"><Shield className="h-4 w-4" /> Roles ({roles.length})</TabsTrigger>
            <TabsTrigger value="permissions" className="gap-1.5"><Key className="h-4 w-4" /> Permissions ({permissions.length})</TabsTrigger>
          </TabsList>
          <div className="relative max-w-xs w-full">
            <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
            <Input placeholder={tab === "roles" ? "Search roles..." : "Search permissions..."} className="pl-9" value={search} onChange={e => setSearch(e.target.value)} />
          </div>
        </div>

        {/* ── Roles Tab ── */}
        <TabsContent value="roles" className="mt-4">
          {roles.length === 0 ? (
            <Card><CardContent className="py-16 text-center text-muted-foreground">No roles configured yet. Create one to get started.</CardContent></Card>
          ) : (
            <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
              {roles.map(r => (
                <Card key={r.id} className="group hover:shadow-md transition-shadow">
                  <CardHeader className="pb-3">
                    <div className="flex items-start justify-between">
                      <div className="flex items-center gap-2">
                        <div className="h-9 w-9 rounded-lg bg-primary/10 flex items-center justify-center">
                          <Shield className="h-4 w-4 text-primary" />
                        </div>
                        <div>
                          <CardTitle className="text-base">{r.name}</CardTitle>
                          <CardDescription className="text-xs">{r.user_count} user{r.user_count !== 1 ? "s" : ""} assigned</CardDescription>
                        </div>
                      </div>
                      <div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
                        <Tooltip><TooltipTrigger asChild>
                          <Button size="icon" variant="ghost" className="h-8 w-8" onClick={() => openEditRole(r)}><Pencil className="h-3.5 w-3.5" /></Button>
                        </TooltipTrigger><TooltipContent>Edit</TooltipContent></Tooltip>
                        <Tooltip><TooltipTrigger asChild>
                          <Button size="icon" variant="ghost" className="h-8 w-8 text-destructive" onClick={() => { if (window.confirm(`Delete role "${r.name}"?`)) deleteRoleMut.mutate(r.id); }}><Trash2 className="h-3.5 w-3.5" /></Button>
                        </TooltipTrigger><TooltipContent>Delete</TooltipContent></Tooltip>
                      </div>
                    </div>
                  </CardHeader>
                  <CardContent className="space-y-3">
                    {r.description && <p className="text-sm text-muted-foreground line-clamp-2">{r.description}</p>}
                    <div className="flex flex-wrap gap-1.5">
                      {r.permissions.slice(0, 5).map(p => (
                        <Badge key={p.id} variant="outline" className={`text-[10px] px-1.5 py-0 ${categoryBadgeClass(p.category)}`}>{p.code}</Badge>
                      ))}
                      {r.permissions.length > 5 && <Badge variant="secondary" className="text-[10px] px-1.5 py-0">+{r.permissions.length - 5}</Badge>}
                      {r.permissions.length === 0 && <span className="text-xs text-muted-foreground italic">No permissions</span>}
                    </div>
                    <Button variant="outline" size="sm" className="w-full mt-2" onClick={() => openAssignPerms(r)}>
                      <Key className="mr-1.5 h-3.5 w-3.5" /> Manage Permissions <ChevronRight className="ml-auto h-3.5 w-3.5" />
                    </Button>
                  </CardContent>
                </Card>
              ))}
            </div>
          )}
        </TabsContent>

        {/* ── Permissions Tab ── */}
        <TabsContent value="permissions" className="mt-4">
          {Object.entries(categorizedPerms).length === 0 ? (
            <Card><CardContent className="py-16 text-center text-muted-foreground">No permissions defined yet.</CardContent></Card>
          ) : (
            <div className="space-y-4">
              {Object.entries(categorizedPerms).map(([cat, perms]) => {
                const visible = search ? perms.filter(p => filteredPerms.includes(p)) : perms;
                if (visible.length === 0) return null;
                return (
                  <Card key={cat}>
                    <CardHeader className="pb-3">
                      <CardTitle className="text-sm font-semibold flex items-center gap-2">
                        <Badge className={`${categoryBadgeClass(cat)} font-medium`}>{cat}</Badge>
                        <span className="text-muted-foreground text-xs font-normal">{visible.length} permission{visible.length !== 1 ? "s" : ""}</span>
                      </CardTitle>
                    </CardHeader>
                    <CardContent className="pt-0">
                      <Table>
                        <TableHeader>
                          <TableRow>
                            <TableHead className="w-[200px]">Code</TableHead>
                            <TableHead>Name</TableHead>
                            <TableHead className="hidden md:table-cell">Description</TableHead>
                            <TableHead className="w-[80px]">Actions</TableHead>
                          </TableRow>
                        </TableHeader>
                        <TableBody>
                          {visible.map(p => (
                            <TableRow key={p.id}>
                              <TableCell><code className="text-xs bg-muted px-1.5 py-0.5 rounded font-mono">{p.code}</code></TableCell>
                              <TableCell className="font-medium">{p.name}</TableCell>
                              <TableCell className="hidden md:table-cell text-muted-foreground text-sm max-w-xs truncate">{p.description || "—"}</TableCell>
                              <TableCell>
                                <Button size="icon" variant="ghost" className="h-8 w-8 text-destructive" onClick={() => { if (window.confirm(`Delete permission "${p.code}"?`)) deletePermMut.mutate(p.id); }}>
                                  <Trash2 className="h-3.5 w-3.5" />
                                </Button>
                              </TableCell>
                            </TableRow>
                          ))}
                        </TableBody>
                      </Table>
                    </CardContent>
                  </Card>
                );
              })}
            </div>
          )}
        </TabsContent>
      </Tabs>

      {/* ── Create / Edit Role Dialog ── */}
      <Dialog open={roleDialogOpen} onOpenChange={o => { setRoleDialogOpen(o); if (!o) setEditingRole(null); }}>
        <DialogContent>
          <DialogHeader><DialogTitle>{editingRole ? "Edit Role" : "Create New Role"}</DialogTitle></DialogHeader>
          <div className="space-y-4">
            <div className="space-y-2"><Label>Role Name</Label><Input placeholder="e.g. Exam Manager" value={roleForm.name} onChange={e => setRoleForm(f => ({ ...f, name: e.target.value }))} /></div>
            <div className="space-y-2"><Label>Description</Label><Textarea placeholder="What does this role do?" value={roleForm.description} onChange={e => setRoleForm(f => ({ ...f, description: e.target.value }))} className="h-20" /></div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setRoleDialogOpen(false)}>Cancel</Button>
            <Button disabled={!roleForm.name.trim() || createRoleMut.isPending || updateRoleMut.isPending} onClick={handleSaveRole}>
              {(createRoleMut.isPending || updateRoleMut.isPending) ? <Loader2 className="h-4 w-4 mr-1 animate-spin" /> : null}
              {editingRole ? "Save Changes" : "Create Role"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ── Create Permission Dialog ── */}
      <Dialog open={permDialogOpen} onOpenChange={setPermDialogOpen}>
        <DialogContent>
          <DialogHeader><DialogTitle>Create Permission</DialogTitle></DialogHeader>
          <div className="space-y-4">
            <div className="grid grid-cols-2 gap-3">
              <div className="space-y-2"><Label>Name</Label><Input placeholder="View Exams" value={permForm.name} onChange={e => setPermForm(f => ({ ...f, name: e.target.value }))} /></div>
              <div className="space-y-2"><Label>Code</Label><Input placeholder="exam.view" value={permForm.code} onChange={e => setPermForm(f => ({ ...f, code: e.target.value }))} /></div>
            </div>
            <div className="space-y-2"><Label>Category</Label><Input placeholder="exam" value={permForm.category} onChange={e => setPermForm(f => ({ ...f, category: e.target.value }))} /></div>
            <div className="space-y-2"><Label>Description</Label><Textarea placeholder="Optional description" value={permForm.description} onChange={e => setPermForm(f => ({ ...f, description: e.target.value }))} className="h-16" /></div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setPermDialogOpen(false)}>Cancel</Button>
            <Button disabled={!permForm.name.trim() || !permForm.code.trim() || createPermMut.isPending} onClick={() => createPermMut.mutate(permForm)}>
              {createPermMut.isPending ? <Loader2 className="h-4 w-4 mr-1 animate-spin" /> : null}
              Create Permission
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ── Assign Permissions Dialog ── */}
      <Dialog open={permAssignOpen} onOpenChange={o => { setPermAssignOpen(o); if (!o) setAssigningRole(null); }}>
        <DialogContent className="max-w-2xl max-h-[80vh]">
          <DialogHeader>
            <DialogTitle className="flex items-center gap-2">
              <Shield className="h-5 w-5 text-primary" />
              Permissions for "{assigningRole?.name}"
            </DialogTitle>
          </DialogHeader>
          <div className="overflow-y-auto max-h-[55vh] space-y-4 pr-1">
            {Object.entries(categorizedPerms).map(([cat, catPerms]) => (
              <div key={cat} className="space-y-2">
                <div className="flex items-center justify-between">
                  <Badge className={`${categoryBadgeClass(cat)} font-medium`}>{cat}</Badge>
                  <Button variant="ghost" size="sm" className="text-xs h-6" onClick={() => {
                    const allInCat = catPerms.map(p => p.id);
                    const allSelected = allInCat.every(id => selectedPermIds.has(id));
                    setSelectedPermIds(prev => {
                      const s = new Set(prev);
                      allInCat.forEach(id => allSelected ? s.delete(id) : s.add(id));
                      return s;
                    });
                  }}>
                    {catPerms.every(p => selectedPermIds.has(p.id)) ? "Deselect All" : "Select All"}
                  </Button>
                </div>
                <div className="grid gap-1.5">
                  {catPerms.map(p => (
                    <label key={p.id} className="flex items-center gap-3 px-3 py-2 rounded-md hover:bg-muted/50 cursor-pointer transition-colors">
                      <Switch checked={selectedPermIds.has(p.id)} onCheckedChange={() => togglePerm(p.id)} />
                      <div className="min-w-0 flex-1">
                        <div className="flex items-center gap-2">
                          <span className="text-sm font-medium">{p.name}</span>
                          <code className="text-[10px] bg-muted px-1 rounded font-mono text-muted-foreground">{p.code}</code>
                        </div>
                        {p.description && <p className="text-xs text-muted-foreground truncate">{p.description}</p>}
                      </div>
                    </label>
                  ))}
                </div>
              </div>
            ))}
            {permissions.length === 0 && <p className="text-sm text-muted-foreground text-center py-8">No permissions available. Create some first.</p>}
          </div>
          <DialogFooter>
            <div className="flex items-center gap-2 mr-auto text-sm text-muted-foreground">
              <Key className="h-4 w-4" /> {selectedPermIds.size} of {permissions.length} selected
            </div>
            <Button variant="outline" onClick={() => setPermAssignOpen(false)}>Cancel</Button>
            <Button disabled={assignPermsMut.isPending} onClick={() => { if (assigningRole) assignPermsMut.mutate({ id: assigningRole.id, permIds: Array.from(selectedPermIds) }); }}>
              {assignPermsMut.isPending ? <Loader2 className="h-4 w-4 mr-1 animate-spin" /> : null}
              Save Permissions
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
