"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, Trash2, X } from "lucide-react";
import type { ClientWorkspaceChildCtx } from "./client-workspace-layout";

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

type MgmtRoleRow = {
  _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 permissionIdsFromRow(r: MgmtRoleRow): 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?: MgmtRoleRow["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: MgmtRoleRow): 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);
}

function isOrgMgmtRoleForCurrentClient(
  r: MgmtRoleRow,
  userClientDbId: string | undefined
): boolean {
  if (!userClientDbId) return false;
  const cid = clientDbId(r);
  return !!cid && cid === String(userClientDbId);
}

/** Full “Add management role” modal (name + permissions) — same as Roles → Management roles. */
export function AddManagementRoleDialog({
  open,
  onOpenChange,
  tenantApiKey,
  tenantReady,
  tenantClientId,
  onSuccess,
}: {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  tenantApiKey: string;
  tenantReady: boolean;
  tenantClientId: string | undefined;
  onSuccess?: (created: { _id: string }) => void | Promise<void>;
}) {
  const [roleName, setRoleName] = useState("");
  const [createPermIds, setCreatePermIds] = useState<string[]>([]);
  const [permCatalog, setPermCatalog] = useState<PermissionOpt[]>([]);
  const [saving, setSaving] = useState(false);

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

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

  const reset = () => {
    setRoleName("");
    setCreatePermIds([]);
  };

  const submit = async () => {
    if (!roleName.trim()) {
      toast.error("Enter a management role name");
      return;
    }
    setSaving(true);
    try {
      const res = await DataService.post(tenantApiPath(tenantApiKey, "/management-roles"), {
        name: roleName.trim(),
        permissions: createPermIds,
      });
      toast.success("Management role created");
      const created = res.data?.data;
      const id = created?._id ? String(created._id) : "";
      reset();
      onOpenChange(false);
      if (id) await onSuccess?.({ _id: id });
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not create management role"));
    } finally {
      setSaving(false);
    }
  };

  return (
    <Dialog
      open={open}
      onOpenChange={(next) => {
        onOpenChange(next);
        if (!next) reset();
      }}
    >
      <DialogContent className="max-h-[min(90vh,100dvh)] w-[calc(100vw-1rem)] max-w-lg gap-4 overflow-y-auto p-4 sm:p-6">
        <DialogHeader className="space-y-1 text-left">
          <DialogTitle className="text-base sm:text-lg">Add management role</DialogTitle>
        </DialogHeader>
        <div className="grid gap-2 py-2">
          <Label htmlFor="shared-mm-cr-name">Name</Label>
          <Input
            id="shared-mm-cr-name"
            placeholder="e.g. Committee chair, Building manager"
            value={roleName}
            onChange={(e) => setRoleName(e.target.value)}
          />
          <p className="text-xs text-gray-500">
            Stored separately from app roles. Client id: {tenantClientId ?? "—"}.
          </p>
          <div className="pt-2">
            <Label>Allowed actions</Label>
            <p className="mt-1 text-xs text-muted-foreground">
              Optional permission keys (same catalog as organization roles).
            </p>
          </div>
          <PermissionsField
            idPrefix="mm-add-shared"
            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={() => onOpenChange(false)}>
            Cancel
          </Button>
          <Button className="w-full sm:w-auto" onClick={() => void submit()} disabled={saving}>
            {saving ? "Saving…" : "Create"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

/** Same table UX as Roles, backed by `/management-roles` (separate from app roles). */
export function ClientManagementRolesTableBody({
  ctx,
  panelTitle = "Management Role",
  panelDescription,
  tabsNode,
}: {
  ctx: ClientWorkspaceChildCtx;
  panelTitle?: string;
  panelDescription?: React.ReactNode;
  tabsNode?: React.ReactNode;
}) {
  const { tenantApiKey, tenantReady, tenantClientId, workspaceClientDbId } = ctx;
  const [rows, setRows] = useState<MgmtRoleRow[]>([]);
  const [listLoading, setListLoading] = useState(false);
  const [permCatalog, setPermCatalog] = useState<PermissionOpt[]>([]);

  const [roleOpen, setRoleOpen] = useState(false);
  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 loadRows = useCallback(async (key: string) => {
    setListLoading(true);
    try {
      const res = await DataService.get(tenantApiPath(key, "/management-roles"));
      setRows(res.data?.data || []);
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not load management 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 loadRows(tenantApiKey);
    void loadPermissions(tenantApiKey);
  }, [tenantReady, tenantApiKey, loadRows, loadPermissions]);

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

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

  const removeRole = async (r: MgmtRoleRow) => {
    if (!isOrgMgmtRoleForCurrentClient(r, workspaceClientDbId)) return;
    if (!confirm(`Delete management role “${r.name}”?`)) return;
    try {
      await DataService.delete(tenantApiPath(tenantApiKey, `/management-roles/${r._id}`));
      toast.success("Management role deleted");
      await loadRows(tenantApiKey);
    } catch (e: unknown) {
      toast.error(getApiErrorMessage(e, "Could not delete management role"));
    }
  };

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

  const defaultDescription = (
    <p className="text-xs leading-relaxed text-gray-500 sm:text-xs">
      Separate from organization <strong>Roles</strong>. Assign them to users on{" "}
      <Link href="/client/users" className="font-medium text-primary underline">
        Users
      </Link>{" "}
      → <strong>Management</strong> tab.
    </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 || panelDescription) ? (
            <div className="flex items-center justify-between gap-3 border-b border-border/70">
              {tabsNode || panelDescription}
              <Button
                size="sm"
                className="h-9 shrink-0 px-4"
                onClick={() => setRoleOpen(true)}
              >
                <Plus className="mr-1 size-4" />
                Add management role
              </Button>
            </div>
          ) : null}
        </div>

        {listLoading ? (
          <div className="p-6 text-center text-sm text-gray-500 sm:p-8">Loading management 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 management roles match your current filter."
                      : "No management roles yet. Add management role, then assign on Users → Management."}
                  </TableCell>
                </TableRow>
              ) : (
                pagedRows.map((r) => {
                  const org = isOrgMgmtRoleForCurrentClient(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 management 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 management 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>
      </div>

      <AddManagementRoleDialog
        open={roleOpen}
        onOpenChange={setRoleOpen}
        tenantApiKey={tenantApiKey}
        tenantReady={tenantReady}
        tenantClientId={tenantClientId}
        onSuccess={async () => {
          await loadRows(tenantApiKey);
        }}
      />

      <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 management role</DialogTitle>
          </DialogHeader>
          <div className="grid gap-2 py-2">
            <Label htmlFor="mm-er-name">Name</Label>
            <Input id="mm-er-name" value={editName} onChange={(e) => setEditName(e.target.value)} />
            <div className="pt-2">
              <Label>Allowed actions</Label>
            </div>
            <PermissionsField
              idPrefix="mm-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>
    </>
  );
}
