"use client";

import React, { useCallback, useEffect, useMemo, useState } from "react";
import Link from "next/link";
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 {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import DataService from "@/config/axios";
import { getApiErrorMessage } from "@/lib/api-error";
import { tenantApiPath } from "@/lib/tenant-api";
import { toast } from "sonner";
import { Filter, Pencil, Plus, Search, Shield, Trash2, X } from "lucide-react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ClientManagementRolesTableBody } from "./client-management-roles-list";
import ClientWorkspaceLayout, {
  type ClientWorkspaceChildCtx,
} from "./client-workspace-layout";

type RoleClientPop = {
  _id?: string;
  name?: string;
  clientId?: string;
};

type RoleRow = {
  _id: string;
  name: string;
  client?: string | RoleClientPop | null;
  permissions?: { _id?: string; name?: string; label?: string; group?: string }[];
};

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

function groupPermissionsByGroup(perms: PermissionOpt[]): [string, PermissionOpt[]][] {
  const m = new Map<string, PermissionOpt[]>();
  for (const p of perms) {
    const g = (p.group && String(p.group).trim()) || "General";
    if (!m.has(g)) m.set(g, []);
    m.get(g)!.push(p);
  }
  return Array.from(m.entries()).sort(([a], [b]) => a.localeCompare(b));
}

function permissionIdsFromRole(r: RoleRow): string[] {
  const p = r.permissions;
  if (!p?.length) return [];
  return p
    .map((x) => (x && typeof x === "object" && x._id ? String(x._id) : null))
    .filter((x): x is string => !!x);
}

function PermissionsField({
  idPrefix,
  allPermissions,
  selectedIds,
  onToggle,
  onSelectAll,
  onClearAll,
}: {
  idPrefix: string;
  allPermissions: PermissionOpt[];
  selectedIds: string[];
  onToggle: (id: string) => void;
  onSelectAll: () => void;
  onClearAll: () => void;
}) {
  const groups = groupPermissionsByGroup(allPermissions);
  if (allPermissions.length === 0) {
    return (
      <p className="rounded-md border bg-muted/30 px-3 py-2 text-xs text-muted-foreground">
        {
          "No actions are defined in the system yet. Add permission keys under platform admin (Permissions), or contact support."
        }
      </p>
    );
  }
  const allIds = allPermissions.map((p) => p._id);
  const allSelected =
    allIds.length !== 0 && allIds.every((id) => selectedIds.includes(id));
  return (
    <div className="space-y-2">
      <div className="flex flex-wrap items-center gap-2">
        <Button
          type="button"
          variant="outline"
          size="sm"
          className="h-8 text-xs"
          onClick={onSelectAll}
          disabled={allSelected}
        >
          Select all actions
        </Button>
        <Button
          type="button"
          variant="outline"
          size="sm"
          className="h-8 text-xs"
          onClick={onClearAll}
          disabled={selectedIds.length === 0}
        >
          Clear all
        </Button>
      </div>
      <div className="max-h-56 space-y-3 overflow-y-auto rounded-md border bg-muted/30 p-3">
        {groups.map(([group, items]) => (
          <div key={group}>
            <p className="mb-2 text-xs font-semibold uppercase text-muted-foreground">{group}</p>
            <ul className="space-y-2">
              {items.map((p) => (
                <li key={p._id} className="flex items-start gap-2">
                  <input
                    type="checkbox"
                    id={`${idPrefix}-perm-${p._id}`}
                    checked={selectedIds.includes(p._id)}
                    onChange={() => onToggle(p._id)}
                    className="mt-1 size-4 shrink-0 rounded border-gray-300"
                  />
                  <label
                    htmlFor={`${idPrefix}-perm-${p._id}`}
                    className="min-w-0 cursor-pointer text-sm leading-tight"
                  >
                    <span className="font-medium">{p.label || p.name}</span>
                    <span className="block font-mono text-xs text-muted-foreground">{p.name}</span>
                  </label>
                </li>
              ))}
            </ul>
          </div>
        ))}
      </div>
    </div>
  );
}

function formatPermissions(p?: RoleRow["permissions"]) {
  if (!p || p.length === 0) return "—";
  const names = p.map((x) => x.name).filter(Boolean) as string[];
  if (names.length === 0) return "—";
  const show = names.slice(0, 4).join(", ");
  return names.length > 4 ? `${show}…` : show;
}

function clientDbId(r: RoleRow): string | null {
  if (!r.client) return null;
  if (typeof r.client === "object" && r.client !== null && "_id" in r.client) {
    return String((r.client as RoleClientPop)._id);
  }
  return String(r.client);
}

/** True when this role is scoped to the same Client document as the signed-in user / selected workspace. */
function isOrgRoleForCurrentClient(r: RoleRow, userClientDbId: string | undefined): boolean {
  if (!userClientDbId) return false;
  const roleClientId = clientDbId(r);
  return !!roleClientId && roleClientId === String(userClientDbId);
}

export function ClientRolesTableBody({
  ctx,
  panelTitle = "Roles",
  panelDescription,
  tabsNode,
}: {
  ctx: ClientWorkspaceChildCtx;
  panelTitle?: string;
  panelDescription?: React.ReactNode;
  tabsNode?: React.ReactNode;
}) {
  const { tenantApiKey, tenantReady, isSuperAdmin, tenantClientId, workspaceClientDbId } = ctx;
  const [rows, setRows] = useState<RoleRow[]>([]);
  const [listLoading, setListLoading] = useState(false);
  const [permCatalog, setPermCatalog] = useState<PermissionOpt[]>([]);

  const [roleOpen, setRoleOpen] = useState(false);
  const [roleName, setRoleName] = useState("");
  const [createPermIds, setCreatePermIds] = useState<string[]>([]);
  const [roleSaving, setRoleSaving] = useState(false);

  const [editOpen, setEditOpen] = useState(false);
  const [editId, setEditId] = useState<string | null>(null);
  const [editName, setEditName] = useState("");
  const [editPermIds, setEditPermIds] = useState<string[]>([]);
  const [searchInput, setSearchInput] = useState("");
  const [appliedSearch, setAppliedSearch] = useState("");
  const [page, setPage] = useState(1);
  const pageSize = 10;

  const loadRoles = useCallback(async (key: string) => {
    setListLoading(true);
    try {
      const res = await DataService.get(tenantApiPath(key, "/roles"));
      setRows(res.data?.data || []);
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not load roles"));
      setRows([]);
    } finally {
      setListLoading(false);
    }
  }, []);

  const loadPermissions = useCallback(async (key: string) => {
    try {
      const res = await DataService.get(tenantApiPath(key, "/permissions"));
      const data = res.data?.data;
      setPermCatalog(Array.isArray(data) ? data : []);
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not load permission catalog"));
      setPermCatalog([]);
    }
  }, []);

  useEffect(() => {
    if (!tenantReady) return;
    void loadRoles(tenantApiKey);
    void loadPermissions(tenantApiKey);
  }, [tenantReady, tenantApiKey, loadRoles, loadPermissions]);

  const submitRole = async () => {
    if (!roleName.trim()) {
      toast.error("Enter a role name");
      return;
    }
    setRoleSaving(true);
    try {
      await DataService.post(tenantApiPath(tenantApiKey, "/roles"), {
        name: roleName.trim(),
        permissions: createPermIds,
      });
      toast.success("Role created");
      setRoleOpen(false);
      setRoleName("");
      setCreatePermIds([]);
      await loadRoles(tenantApiKey);
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not create role"));
    } finally {
      setRoleSaving(false);
    }
  };

  const openEdit = (r: RoleRow) => {
    setEditId(r._id);
    setEditName(r.name);
    setEditPermIds(permissionIdsFromRole(r));
    setEditOpen(true);
  };

  const submitEdit = async () => {
    if (!editId || !editName.trim()) {
      toast.error("Enter a role name");
      return;
    }
    setRoleSaving(true);
    try {
      await DataService.patch(tenantApiPath(tenantApiKey, `/roles/${editId}`), {
        name: editName.trim(),
        permissions: editPermIds,
      });
      toast.success("Role updated");
      setEditOpen(false);
      setEditId(null);
      await loadRoles(tenantApiKey);
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not update role"));
    } finally {
      setRoleSaving(false);
    }
  };

  const removeRole = async (r: RoleRow) => {
    if (!isOrgRoleForCurrentClient(r, workspaceClientDbId)) return;
    if (!confirm(`Delete role “${r.name}”? This cannot be undone if no users use it.`)) return;
    try {
      await DataService.delete(tenantApiPath(tenantApiKey, `/roles/${r._id}`));
      toast.success("Role deleted");
      await loadRoles(tenantApiKey);
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not delete role"));
    }
  };

  if (!tenantReady) {
    return <p className="text-sm text-gray-500">Select a client to load roles.</p>;
  }

  const defaultDescription = (
    <p className="text-xs leading-relaxed text-gray-500 sm:text-xs">
      This list shows roles created for this client plus shared global roles visible for your
      account. Shared/global rows are read-only here; assign roles under{" "}
      <Link href="/client/users" className="font-medium text-primary underline">
        Users
      </Link>
      .
    </p>
  );

  const normalizedAppliedSearch = appliedSearch.trim().toLowerCase();
  const filteredRows = useMemo(() => {
    if (!normalizedAppliedSearch) return rows;
    return rows.filter((r) => {
      const permissionsSummary = formatPermissions(r.permissions);
      const haystack = `${r.name || ""} ${permissionsSummary || ""}`.toLowerCase();
      return haystack.includes(normalizedAppliedSearch);
    });
  }, [rows, normalizedAppliedSearch]);
  const totalPages = Math.max(1, Math.ceil(filteredRows.length / pageSize));
  const pagedRows = useMemo(() => {
    const start = (page - 1) * pageSize;
    return filteredRows.slice(start, start + pageSize);
  }, [filteredRows, page]);
  const filterIsActive =
    normalizedAppliedSearch.length > 0 &&
    searchInput.trim().toLowerCase() === normalizedAppliedSearch;

  const handleFilterButtonClick = () => {
    if (filterIsActive) {
      setAppliedSearch("");
      setSearchInput("");
      setPage(1);
      return;
    }
    setAppliedSearch(searchInput.trim());
    setPage(1);
  };

  useEffect(() => {
    if (page > totalPages) setPage(totalPages);
  }, [page, totalPages]);

  return (
    <>
      <div className="min-w-0 overflow-hidden rounded-xl border bg-white">
        <div className="space-y-3 border-b px-3 py-3 sm:px-4">
          <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
            <h2 className="font-semibold text-gray-900">{panelTitle}</h2>
            <div className="flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:items-center sm:justify-end">
              <div className="relative w-full sm:w-56">
                <Search className="pointer-events-none absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-gray-400" />
                <Input
                  className="h-9 pl-8"
                  placeholder="Search"
                  value={searchInput}
                  onChange={(e) => setSearchInput(e.target.value)}
                />
              </div>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 px-3"
                onClick={handleFilterButtonClick}
              >
                {filterIsActive ? (
                  <X className="mr-2 size-4" />
                ) : (
                  <Filter className="mr-2 size-4" />
                )}
                {filterIsActive ? "Cancel" : "Filters"}
              </Button>
            </div>
          </div>
          {tabsNode ? (
            <div className="flex items-center justify-between gap-3 border-b border-border/70">
              {tabsNode}
              <Button
                size="sm"
                className="h-9 shrink-0 px-4"
                onClick={() => {
                  setRoleName("");
                  setCreatePermIds([]);
                  setRoleOpen(true);
                }}
              >
                <Plus className="mr-1 size-4" />
                Add role
              </Button>
            </div>
          ) : null}
        </div>
        {listLoading ? (
          <div className="p-6 text-center text-sm text-gray-500 sm:p-8">Loading roles…</div>
        ) : (
          <Table className="min-w-[640px]">
            <TableHeader>
              <TableRow className="bg-muted/30">
                <TableHead>Name</TableHead>
                <TableHead>Allowed actions (summary)</TableHead>
                <TableHead className="w-[88px] text-right sm:w-[100px]">Actions</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {pagedRows.length === 0 ? (
                <TableRow>
                  <TableCell colSpan={3} className="text-center text-gray-400">
                    {normalizedAppliedSearch
                      ? "No roles match your current filter."
                      : "No organization roles yet. Add one above, or assign platform roles under Users."}
                  </TableCell>
                </TableRow>
              ) : (
                pagedRows.map((r) => {
                  const org = isOrgRoleForCurrentClient(r, workspaceClientDbId);
                  return (
                    <TableRow key={r._id}>
                      <TableCell className="font-medium">{r.name}</TableCell>
                      <TableCell className="max-w-md text-sm text-gray-600">
                        {formatPermissions(r.permissions)}
                      </TableCell>
                      <TableCell className="text-right">
                        {org ? (
                          <div className="flex justify-end gap-1">
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="size-8"
                              onClick={() => openEdit(r)}
                              aria-label="Edit role"
                            >
                              <Pencil className="size-4" />
                            </Button>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="size-8 text-red-600"
                              onClick={() => void removeRole(r)}
                              aria-label="Delete role"
                            >
                              <Trash2 className="size-4" />
                            </Button>
                          </div>
                        ) : (
                          <span className="text-xs text-gray-400">—</span>
                        )}
                      </TableCell>
                    </TableRow>
                  );
                })
              )}
            </TableBody>
          </Table>
        )}
        <div className="flex items-center justify-between border-t px-3 py-3 sm:px-4">
          <Button
            type="button"
            variant="outline"
            size="sm"
            disabled={page <= 1 || listLoading}
            onClick={() => setPage((prev) => Math.max(1, prev - 1))}
          >
            Previous
          </Button>
          <p className="text-xs text-gray-500">{`Page ${page} of ${totalPages}`}</p>
          <Button
            type="button"
            variant="outline"
            size="sm"
            disabled={page >= totalPages || listLoading}
            onClick={() => setPage((prev) => Math.min(totalPages, prev + 1))}
          >
            Next
          </Button>
        </div>
        {isSuperAdmin && (
          <p className="border-t px-3 py-3 text-xs leading-relaxed text-gray-500 sm:px-4">
            Platform-wide role templates:{" "}
            <Link href="/super-admin/admin/roles" className="font-medium text-primary underline">
              Super admin — Roles
            </Link>
            .
          </p>
        )}
      </div>

      <Dialog
        open={roleOpen}
        onOpenChange={(open) => {
          setRoleOpen(open);
          if (!open) {
            setRoleName("");
            setCreatePermIds([]);
          }
        }}
      >
        <DialogContent className="w-[calc(100vw-1rem)] max-w-lg gap-4 p-4 sm:p-6">
          <DialogHeader className="space-y-1 text-left">
            <DialogTitle className="text-base sm:text-lg">Add organization role</DialogTitle>
          </DialogHeader>
          <div className="grid gap-2 py-2">
            <Label htmlFor="cr-name">Role name</Label>
            <Input
              id="cr-name"
              placeholder="e.g. Tenant, Shop owner"
              value={roleName}
              onChange={(e) => setRoleName(e.target.value)}
            />
            <p className="text-xs text-gray-500">
              Saved with this client&apos;s id ({tenantClientId ?? "—"}). Names must be unique
              within this organization.
            </p>
            <div className="pt-2">
              <Label>Allowed actions</Label>
              <p className="mt-1 text-xs text-muted-foreground">
                Choose what users with this role can do in your organization (same permission keys as
                platform roles).
              </p>
            </div>
            <PermissionsField
              idPrefix="add"
              allPermissions={permCatalog}
              selectedIds={createPermIds}
              onToggle={(id) =>
                setCreatePermIds((prev) =>
                  prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]
                )
              }
              onSelectAll={() => setCreatePermIds(permCatalog.map((p) => p._id))}
              onClearAll={() => setCreatePermIds([])}
            />
          </div>
          <DialogFooter className="gap-2 sm:gap-0">
            <Button
              variant="outline"
              className="w-full sm:w-auto"
              onClick={() => setRoleOpen(false)}
            >
              Cancel
            </Button>
            <Button
              className="w-full sm:w-auto"
              onClick={() => void submitRole()}
              disabled={roleSaving}
            >
              {roleSaving ? "Saving…" : "Create role"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog
        open={editOpen}
        onOpenChange={(open) => {
          setEditOpen(open);
          if (!open) {
            setEditId(null);
            setEditName("");
            setEditPermIds([]);
          }
        }}
      >
        <DialogContent className="w-[calc(100vw-1rem)] max-w-lg gap-4 p-4 sm:p-6">
          <DialogHeader className="space-y-1 text-left">
            <DialogTitle className="text-base sm:text-lg">Edit organization role</DialogTitle>
          </DialogHeader>
          <div className="grid gap-2 py-2">
            <Label htmlFor="er-name">Role name</Label>
            <Input
              id="er-name"
              value={editName}
              onChange={(e) => setEditName(e.target.value)}
            />
            <div className="pt-2">
              <Label>Allowed actions</Label>
              <p className="mt-1 text-xs text-muted-foreground">
                Update what users with this role can do.
              </p>
            </div>
            <PermissionsField
              idPrefix="edit"
              allPermissions={permCatalog}
              selectedIds={editPermIds}
              onToggle={(id) =>
                setEditPermIds((prev) =>
                  prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]
                )
              }
              onSelectAll={() => setEditPermIds(permCatalog.map((p) => p._id))}
              onClearAll={() => setEditPermIds([])}
            />
          </div>
          <DialogFooter className="gap-2 sm:gap-0">
            <Button
              variant="outline"
              className="w-full sm:w-auto"
              onClick={() => setEditOpen(false)}
            >
              Cancel
            </Button>
            <Button
              className="w-full sm:w-auto"
              onClick={() => void submitEdit()}
              disabled={roleSaving}
            >
              {roleSaving ? "Saving…" : "Save"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}

export default function ClientRolesList() {
  return (
    <ClientWorkspaceLayout
      title=""
      barDescription="Organization roles (app permissions) and a separate Management roles catalog. Assign both on Users."
      actions={(ctx) =>
        ctx.isSuperAdmin ? (
          <Button variant="outline" size="sm" className="w-full md:w-auto" asChild>
            <Link href="/super-admin/admin/roles">
              <Shield className="mr-2 size-4" />
              Roles (platform admin)
            </Link>
          </Button>
        ) : null
      }
    >
      {(ctx) => (
        <Tabs defaultValue="organization" className="min-w-0">
          <TabsContent value="organization" className="mt-4">
            <ClientRolesTableBody
              ctx={ctx}
              tabsNode={
                <TabsList className="h-auto w-full justify-start gap-6 rounded-none border-0 bg-transparent p-0">
                  <TabsTrigger
                    value="organization"
                    className="shrink-0 rounded-none border-b-2 border-transparent px-0.5 pb-2 pt-1 text-sm font-medium text-muted-foreground shadow-none data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-slate-800"
                  >
                    Organization roles
                  </TabsTrigger>
                  <TabsTrigger
                    value="management"
                    className="shrink-0 rounded-none border-b-2 border-transparent px-0.5 pb-2 pt-1 text-sm font-medium text-muted-foreground shadow-none data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-slate-800"
                  >
                    Management roles
                  </TabsTrigger>
                </TabsList>
              }
            />
          </TabsContent>
          <TabsContent value="management" className="mt-4">
            <ClientManagementRolesTableBody
              ctx={ctx}
              panelTitle="Management roles"
              panelDescription={
                <TabsList className="h-auto w-full justify-start gap-6 rounded-none border-0 bg-transparent p-0">
                  <TabsTrigger
                    value="organization"
                    className="shrink-0 rounded-none border-b-2 border-transparent px-0.5 pb-2 pt-1 text-sm font-medium text-muted-foreground shadow-none data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-slate-800"
                  >
                    Organization roles
                  </TabsTrigger>
                  <TabsTrigger
                    value="management"
                    className="shrink-0 rounded-none border-b-2 border-transparent px-0.5 pb-2 pt-1 text-sm font-medium text-muted-foreground shadow-none data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-slate-800"
                  >
                    Management roles
                  </TabsTrigger>
                </TabsList>
              }
            />
          </TabsContent>
        </Tabs>
      )}
    </ClientWorkspaceLayout>
  );
}
