"use client";

import React, { useCallback, useEffect, useState } from "react";
import MainTitle from "@/components/layout/dashboard/main-title";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import DataService from "@/config/axios";
import { useRequireSuperAdmin } from "@/hooks/use-require-super-admin";
import { getApiErrorMessage } from "@/lib/api-error";
import { toast } from "sonner";
import { Pencil, Trash2 } from "lucide-react";

type PermRef = { _id: string; name: string; label?: string; group?: string };

type RoleRow = {
  _id: string;
  name: string;
  visibleFor?: { _id: string; name: string } | null;
  permissions?: PermRef[];
};

export default function AdminRolesBlock() {
  const ready = useRequireSuperAdmin();
  const [roles, setRoles] = useState<RoleRow[]>([]);
  const [permissionCatalog, setPermissionCatalog] = useState<PermRef[]>([]);
  const [loading, setLoading] = useState(true);
  const [open, setOpen] = useState(false);
  const [editing, setEditing] = useState<RoleRow | null>(null);
  const [form, setForm] = useState({ name: "", visibleForId: "", permissionIds: [] as string[] });

  const load = useCallback(async () => {
    try {
      const [rolesRes, permRes] = await Promise.all([
        DataService.get("/admin/roles"),
        DataService.get("/admin/permissions"),
      ]);
      setRoles(rolesRes.data?.data || []);
      setPermissionCatalog(permRes.data?.data || []);
    } catch (e) {
      toast.error(getApiErrorMessage(e, "Failed to load roles"));
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    if (ready) load();
  }, [ready, load]);

  const openCreate = () => {
    setEditing(null);
    setForm({ name: "", visibleForId: "", permissionIds: [] });
    setOpen(true);
  };

  const openEdit = (r: RoleRow) => {
    setEditing(r);
    setForm({
      name: r.name,
      visibleForId: r.visibleFor?._id || "",
      permissionIds: (r.permissions || []).map((p) => p._id),
    });
    setOpen(true);
  };

  const togglePermission = (id: string) => {
    setForm((f) => ({
      ...f,
      permissionIds: f.permissionIds.includes(id)
        ? f.permissionIds.filter((x) => x !== id)
        : [...f.permissionIds, id],
    }));
  };

  const permissionsByGroup = permissionCatalog.reduce<Record<string, PermRef[]>>((acc, p) => {
    const g = p.group || "General";
    if (!acc[g]) acc[g] = [];
    acc[g].push(p);
    return acc;
  }, {});

  const save = async () => {
    try {
      const visiblePayload =
        form.visibleForId && form.visibleForId !== "__none__" ? form.visibleForId : null;
      if (editing && visiblePayload === editing._id) {
        toast.error("A role cannot be visible only to itself");
        return;
      }
      if (editing) {
        await DataService.patch(`/admin/roles/${editing._id}`, {
          name: form.name.trim(),
          visibleFor: visiblePayload,
          permissions: form.permissionIds,
        });
        toast.success("Role updated");
      } else {
        await DataService.post("/admin/roles", {
          name: form.name.trim(),
          visibleFor: visiblePayload,
          permissions: form.permissionIds,
        });
        toast.success("Role created");
      }
      setOpen(false);
      load();
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not save role"));
    }
  };

  const remove = async (r: RoleRow) => {
    if (!confirm(`Delete role "${r.name}"?`)) return;
    try {
      await DataService.delete(`/admin/roles/${r._id}`);
      toast.success("Role deleted");
      load();
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not delete role"));
    }
  };

  const parentOptions = (currentId?: string) =>
    roles.filter((x) => x._id !== currentId);

  if (!ready || loading) {
    return (
      <div className="rounded-md border bg-white p-8 text-center text-gray-500">Loading…</div>
    );
  }

  return (
    <div>
      <MainTitle title="Roles & visibility (Super admin)">
        <Button onClick={openCreate}>Add role</Button>
      </MainTitle>

      <p className="mb-4 text-sm text-gray-600">
        <strong>Visible to</strong> controls who may <em>assign this role</em> when adding users: pick
        the manager role (e.g. &quot;User&quot; or &quot;Admin&quot;). Users with that role then see
        only those roles in the user form (e.g. three roles for a User manager). Leave{" "}
        <strong>Visible to</strong> empty for roles only a <strong>super admin</strong> may assign
        (system-wide roles).
      </p>

      <div className="rounded-md border bg-white">
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead>Role name</TableHead>
              <TableHead>Visible to (role)</TableHead>
              <TableHead>Permissions</TableHead>
              <TableHead className="w-[100px]" />
            </TableRow>
          </TableHeader>
          <TableBody>
            {roles.length === 0 ? (
              <TableRow>
                <TableCell colSpan={4} className="text-center text-gray-400">
                  No roles — create one to assign to users.
                </TableCell>
              </TableRow>
            ) : (
              roles.map((r) => (
                <TableRow key={r._id}>
                  <TableCell className="font-medium">{r.name}</TableCell>
                  <TableCell>{r.visibleFor?.name || "—"}</TableCell>
                  <TableCell className="max-w-[240px] text-sm text-gray-600">
                    {(r.permissions?.length || 0) === 0
                      ? "—"
                      : `${r.permissions!.length} selected`}
                  </TableCell>
                  <TableCell className="flex gap-2">
                    <Button variant="outline" size="icon" onClick={() => openEdit(r)}>
                      <Pencil className="size-4" />
                    </Button>
                    <Button variant="outline" size="icon" onClick={() => remove(r)}>
                      <Trash2 className="size-4 text-red-600" />
                    </Button>
                  </TableCell>
                </TableRow>
              ))
            )}
          </TableBody>
        </Table>
      </div>

      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-lg">
          <DialogHeader>
            <DialogTitle>{editing ? "Edit role" : "Add role"}</DialogTitle>
          </DialogHeader>
          <div className="grid gap-3 py-2">
            <div className="grid gap-2">
              <Label htmlFor="rname">Role name</Label>
              <Input
                id="rname"
                value={form.name}
                onChange={(e) => setForm({ ...form, name: e.target.value })}
              />
            </div>
            <div className="grid gap-2">
              <Label>Visible to (role)</Label>
              <Select
                value={form.visibleForId || "__none__"}
                onValueChange={(v) => setForm({ ...form, visibleForId: v === "__none__" ? "" : v })}
              >
                <SelectTrigger>
                  <SelectValue placeholder="None" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="__none__">None</SelectItem>
                  {parentOptions(editing?._id).map((x) => (
                    <SelectItem key={x._id} value={x._id}>
                      {x.name}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className="grid gap-2">
              <Label>Permissions (users with this role)</Label>
              <div className="max-h-48 space-y-3 overflow-y-auto rounded-md border p-3 text-sm">
                {permissionCatalog.length === 0 ? (
                  <p className="text-gray-500">
                    Add permission keys under <strong>Permissions</strong> in the menu first.
                  </p>
                ) : (
                  Object.entries(permissionsByGroup).map(([group, items]) => (
                    <div key={group}>
                      <p className="mb-1 font-medium text-gray-700">{group}</p>
                      <ul className="space-y-1 pl-1">
                        {items.map((p) => (
                          <li key={p._id} className="flex items-center gap-2">
                            <input
                              type="checkbox"
                              id={`perm-${p._id}`}
                              checked={form.permissionIds.includes(p._id)}
                              onChange={() => togglePermission(p._id)}
                              className="rounded border-gray-300"
                            />
                            <label htmlFor={`perm-${p._id}`} className="cursor-pointer">
                              <span className="font-mono text-xs text-gray-800">{p.name}</span>
                              {p.label ? (
                                <span className="text-gray-500"> — {p.label}</span>
                              ) : null}
                            </label>
                          </li>
                        ))}
                      </ul>
                    </div>
                  ))
                )}
              </div>
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setOpen(false)}>
              Cancel
            </Button>
            <Button onClick={save}>{editing ? "Save" : "Create"}</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
