"use client";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { Button } from "@open-mercato/ui/primitives/button";
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
import Link from "next/link";
import { hasFeature, matchFeature } from "@open-mercato/shared/security/features";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { AclDependencyDiagnosticsPanel } from "./AclDependencyDiagnosticsPanel.js";
function toTitleCase(value) {
  return value.replace(/[-_.]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
}
function normalizeFeatureArray(input) {
  if (!Array.isArray(input)) return [];
  const dedup = /* @__PURE__ */ new Set();
  for (const value of input) {
    if (typeof value !== "string") continue;
    const trimmed = value.trim();
    if (!trimmed) continue;
    dedup.add(trimmed);
  }
  return Array.from(dedup);
}
function isTenantRestrictedFeature(feature) {
  if (feature === "*" || feature === "directory.*") return true;
  if (feature.startsWith("directory.tenants")) return true;
  return false;
}
function formatWildcardLabel(moduleId, wildcard) {
  if (!wildcard.endsWith(".*")) return wildcard;
  const prefix = `${moduleId}.`;
  const suffix = wildcard.startsWith(prefix) ? wildcard.slice(prefix.length, -2) : wildcard.slice(0, -2);
  if (!suffix) return "All features";
  return `All ${suffix.split(".").map(toTitleCase).join(" / ")}`;
}
function buildRoleSummaries(items, allowedNames) {
  const summaries = [];
  for (const role of items) {
    const name = typeof role?.name === "string" ? role.name : "";
    if (!name || !allowedNames.includes(name)) continue;
    const hasValidId = typeof role?.id === "string" && role.id.length > 0;
    const id = hasValidId ? role.id : name;
    summaries.push({ id, name });
  }
  return summaries;
}
function normalizeOrganizationOptions(items) {
  if (!Array.isArray(items)) return [];
  return items.reduce((acc, org) => {
    if (!org) return acc;
    const id = typeof org.id === "string" && org.id.trim().length > 0 ? org.id : null;
    if (!id) return acc;
    const name = typeof org.name === "string" && org.name.trim().length > 0 ? org.name : id;
    acc.push({ id, name });
    return acc;
  }, []);
}
async function readJsonOr(url, init, fallback) {
  const call = await apiCall(url, init, { fallback });
  if (!call.ok) return fallback;
  return call.result ?? fallback;
}
function AclEditor({
  kind,
  targetId,
  canEditOrganizations,
  value,
  onChange,
  onVersionChange,
  userRoles,
  currentUserIsSuperAdmin,
  tenantId,
  preserveOnTenantChange = false
}) {
  const actorIsSuperAdmin = !!currentUserIsSuperAdmin;
  const [loading, setLoading] = React.useState(true);
  const [features, setFeatures] = React.useState([]);
  const t = useT();
  const [modules, setModules] = React.useState([]);
  const [granted, setGranted] = React.useState(() => {
    const normalized = normalizeFeatureArray(value?.features);
    return actorIsSuperAdmin ? normalized : normalized.filter((feature) => !isTenantRestrictedFeature(feature));
  });
  const [isSuperAdmin, setIsSuperAdmin] = React.useState(value?.isSuperAdmin || false);
  const [organizations, setOrganizations] = React.useState(value?.organizations ?? null);
  const [orgOptions, setOrgOptions] = React.useState([]);
  const [hasCustomAcl, setHasCustomAcl] = React.useState(true);
  const [overrideEnabled, setOverrideEnabled] = React.useState(false);
  const [roleDetails, setRoleDetails] = React.useState([]);
  const actorSanitizeFeatures = React.useCallback(
    (list) => {
      const normalized = normalizeFeatureArray(list);
      if (actorIsSuperAdmin) return normalized;
      return normalized.filter((feature) => !isTenantRestrictedFeature(feature));
    },
    [actorIsSuperAdmin]
  );
  const updateGranted = React.useCallback(
    (updater) => {
      setGranted((prev) => actorSanitizeFeatures(updater(prev)));
    },
    [actorSanitizeFeatures]
  );
  const tenantIdRef = React.useRef(tenantId);
  React.useEffect(() => {
    tenantIdRef.current = tenantId;
  }, [tenantId]);
  const hasMountedRef = React.useRef(false);
  const fetchAclState = React.useCallback(async (forTenantId, cancelledRef) => {
    try {
      const aclQuery = new URLSearchParams();
      aclQuery.set(kind === "user" ? "userId" : "roleId", targetId);
      if (forTenantId) aclQuery.set("tenantId", forTenantId);
      const aclQueryString = aclQuery.toString();
      const aclJson = await readJsonOr(
        `/api/auth/${kind === "user" ? "users" : "roles"}/acl${aclQueryString ? `?${aclQueryString}` : ""}`,
        void 0,
        { hasCustomAcl: true, isSuperAdmin: false, features: [], organizations: null }
      );
      if (cancelledRef.current) return;
      const customAclExists = aclJson.hasCustomAcl !== false;
      setHasCustomAcl(customAclExists);
      setOverrideEnabled(customAclExists);
      setIsSuperAdmin(!!aclJson.isSuperAdmin);
      setGranted(actorSanitizeFeatures(aclJson.features));
      setOrganizations(aclJson.organizations == null ? null : Array.isArray(aclJson.organizations) ? aclJson.organizations : []);
      onVersionChange?.(typeof aclJson.updatedAt === "string" ? aclJson.updatedAt : null);
    } catch {
    }
  }, [kind, targetId, actorSanitizeFeatures, onVersionChange]);
  React.useEffect(() => {
    const cancelled = { current: false };
    async function load() {
      setLoading(true);
      try {
        const fJson = await readJsonOr(
          "/api/auth/features",
          void 0,
          { items: [], modules: [] }
        );
        if (!cancelled.current) {
          setFeatures(fJson.items || []);
          setModules(fJson.modules || []);
        }
      } catch {
      }
      await fetchAclState(tenantIdRef.current, cancelled);
      hasMountedRef.current = true;
      if (!cancelled.current) setLoading(false);
    }
    load();
    return () => {
      cancelled.current = true;
    };
  }, [kind, targetId, fetchAclState]);
  React.useEffect(() => {
    if (!hasMountedRef.current) return;
    if (preserveOnTenantChange) return;
    const cancelled = { current: false };
    fetchAclState(tenantId, cancelled);
    return () => {
      cancelled.current = true;
    };
  }, [tenantId, preserveOnTenantChange, fetchAclState]);
  React.useEffect(() => {
    let cancelled = false;
    async function loadTenantScoped() {
      if (canEditOrganizations) {
        try {
          const orgQuery = new URLSearchParams();
          if (tenantId) orgQuery.set("tenantId", tenantId);
          const orgQueryString = orgQuery.toString();
          const oJson = await readJsonOr(
            `/api/directory/organizations${orgQueryString ? `?${orgQueryString}` : ""}`,
            void 0,
            { items: [] }
          );
          if (!cancelled) setOrgOptions(normalizeOrganizationOptions(oJson.items));
        } catch {
        }
      }
      if (kind === "user" && userRoles && userRoles.length > 0) {
        try {
          const roleQuery = new URLSearchParams({ pageSize: "100" });
          if (tenantId) roleQuery.set("tenantId", tenantId);
          const roleQueryString = roleQuery.toString();
          const rolesJson = await readJsonOr(
            `/api/auth/roles${roleQueryString ? `?${roleQueryString}` : ""}`,
            void 0,
            { items: [] }
          );
          if (!cancelled) {
            const allRoles = Array.isArray(rolesJson.items) ? rolesJson.items : [];
            const userRoleDetails = buildRoleSummaries(allRoles, userRoles);
            setRoleDetails(userRoleDetails);
          }
        } catch {
        }
      }
    }
    loadTenantScoped();
    return () => {
      cancelled = true;
    };
  }, [kind, canEditOrganizations, userRoles, tenantId]);
  React.useEffect(() => {
    onChange?.({ isSuperAdmin, features: granted, organizations });
  }, [isSuperAdmin, granted, organizations, onChange]);
  const grouped = React.useMemo(() => {
    const moduleMap = /* @__PURE__ */ new Map();
    for (const m of modules) {
      moduleMap.set(m.id, m.title);
    }
    const map = /* @__PURE__ */ new Map();
    for (const f of features) {
      const moduleId = f.module;
      const moduleTitle = moduleMap.get(moduleId) || moduleId;
      if (!map.has(moduleId)) {
        map.set(moduleId, { moduleId, moduleTitle, features: [] });
      }
      map.get(moduleId).features.push(f);
    }
    return Array.from(map.values()).sort((a, b) => a.moduleTitle.localeCompare(b.moduleTitle));
  }, [features, modules]);
  const hasGlobalWildcard = granted.includes("*");
  const hasOrganizationRestriction = Array.isArray(organizations) && organizations.length > 0;
  const showOrganizationWarning = (kind === "role" || overrideEnabled) && canEditOrganizations && !isSuperAdmin && hasOrganizationRestriction && granted.length === 0;
  const toggleWildcard = React.useCallback((wildcard, enable) => {
    if (!actorIsSuperAdmin && enable && isTenantRestrictedFeature(wildcard)) return;
    updateGranted((prev) => {
      if (enable) {
        if (prev.includes(wildcard)) return prev;
        return [...prev, wildcard];
      }
      return prev.filter((feature) => feature !== wildcard);
    });
  }, [actorIsSuperAdmin, updateGranted]);
  const toggleModuleWildcard = React.useCallback((moduleId, enable) => {
    toggleWildcard(`${moduleId}.*`, enable);
  }, [toggleWildcard]);
  const isModuleWildcardEnabled = (moduleId) => {
    return granted.includes(`${moduleId}.*`);
  };
  const isFeatureCoveredByWildcard = (featureId) => granted.some((feature) => (feature === "*" || feature.endsWith(".*")) && matchFeature(featureId, feature));
  const isFeatureChecked = (featureId) => hasFeature(granted, featureId);
  if (loading) return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: "Loading ACL\u2026" });
  const showRoleBanner = kind === "user" && !hasCustomAcl && !overrideEnabled;
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
    showRoleBanner && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-blue-200 bg-blue-50 p-4", children: [
      /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-blue-900 mb-2", children: "Permissions inherited from roles" }),
      /* @__PURE__ */ jsxs("div", { className: "text-sm text-blue-700 mb-3", children: [
        "This user currently inherits permissions from their assigned roles.",
        roleDetails.length > 0 && /* @__PURE__ */ jsxs("span", { children: [
          " ",
          "Assigned roles:",
          " ",
          roleDetails.map((role, idx) => {
            const roleId = typeof role?.id === "string" && role.id.length > 0 ? role.id : `role-${idx}`;
            const roleName = typeof role?.name === "string" && role.name.length > 0 ? role.name : roleId;
            return /* @__PURE__ */ jsxs(React.Fragment, { children: [
              idx > 0 && ", ",
              /* @__PURE__ */ jsx(
                Link,
                {
                  href: `/backend/roles/${roleId}/edit`,
                  className: "font-semibold text-blue-900 underline hover:text-blue-950 transition-colors",
                  children: roleName
                }
              )
            ] }, roleId);
          })
        ] })
      ] }),
      /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
        /* @__PURE__ */ jsx(
          "input",
          {
            id: "overrideAcl",
            type: "checkbox",
            className: "h-4 w-4",
            checked: overrideEnabled,
            onChange: (e) => setOverrideEnabled(e.target.checked)
          }
        ),
        /* @__PURE__ */ jsx("label", { htmlFor: "overrideAcl", className: "text-sm text-blue-900 font-medium", children: "Override permissions for this user only" })
      ] })
    ] }),
    (kind === "role" || overrideEnabled) && /* @__PURE__ */ jsxs(Fragment, { children: [
      /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
        /* @__PURE__ */ jsx(
          "input",
          {
            id: "isSuperAdmin",
            type: "checkbox",
            className: "h-4 w-4",
            checked: isSuperAdmin,
            disabled: !actorIsSuperAdmin,
            onChange: (e) => setIsSuperAdmin(!!e.target.checked)
          }
        ),
        /* @__PURE__ */ jsx("label", { htmlFor: "isSuperAdmin", className: "text-sm", children: "Super Admin (all features)" })
      ] }),
      !actorIsSuperAdmin && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Only super administrators can change this option." }),
      !isSuperAdmin && /* @__PURE__ */ jsxs(Fragment, { children: [
        hasGlobalWildcard && /* @__PURE__ */ jsxs("div", { className: "rounded border border-blue-200 bg-blue-50 p-3", children: [
          /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-blue-900", children: "Global wildcard (*) enabled" }),
          /* @__PURE__ */ jsx("div", { className: "text-xs text-blue-700 mt-1", children: "This grants access to all features in the system." }),
          /* @__PURE__ */ jsx(
            Button,
            {
              variant: "outline",
              size: "sm",
              className: "mt-2",
              onClick: () => updateGranted((prev) => prev.filter((x) => x !== "*")),
              children: "Remove global wildcard"
            }
          )
        ] }),
        !hasGlobalWildcard && /* @__PURE__ */ jsx(
          AclDependencyDiagnosticsPanel,
          {
            granted,
            catalog: features,
            onGrantedChange: updateGranted,
            hideUnknownReferences: process.env.NODE_ENV === "production"
          }
        ),
        /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: grouped.map((group) => {
          const moduleWildcard = isModuleWildcardEnabled(group.moduleId);
          const nestedWildcards = Array.from(
            new Set(
              granted.filter(
                (feature) => feature !== "*" && feature.endsWith(".*") && feature.startsWith(`${group.moduleId}.`) && feature !== `${group.moduleId}.*`
              )
            )
          ).map((wildcard) => {
            const prefix = wildcard.slice(0, -1);
            const relatedFeatures = group.features.filter((feature) => feature.id.startsWith(prefix));
            return { wildcard, features: relatedFeatures };
          }).sort((a, b) => a.wildcard.localeCompare(b.wildcard));
          const nestedCoveredIds = /* @__PURE__ */ new Set();
          for (const entry of nestedWildcards) {
            for (const feature of entry.features) nestedCoveredIds.add(feature.id);
          }
          const moduleRestricted = !actorIsSuperAdmin && isTenantRestrictedFeature(`${group.moduleId}.*`);
          const moduleCheckboxDisabled = hasGlobalWildcard || moduleRestricted;
          return /* @__PURE__ */ jsxs("div", { className: "rounded border p-3", children: [
            /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3 pb-2 border-b", children: [
              /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: group.moduleTitle }),
              /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
                /* @__PURE__ */ jsx(
                  "input",
                  {
                    id: `module-${group.moduleId}`,
                    type: "checkbox",
                    className: "h-4 w-4",
                    checked: moduleWildcard || hasGlobalWildcard,
                    disabled: moduleCheckboxDisabled,
                    onChange: (e) => toggleModuleWildcard(group.moduleId, e.target.checked)
                  }
                ),
                /* @__PURE__ */ jsxs("label", { htmlFor: `module-${group.moduleId}`, className: "text-sm text-muted-foreground", children: [
                  "All ",
                  moduleWildcard && !hasGlobalWildcard ? /* @__PURE__ */ jsxs("span", { className: "font-medium text-blue-600", children: [
                    "(",
                    group.moduleId,
                    ".*)"
                  ] }) : "",
                  moduleRestricted ? /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs font-medium text-muted-foreground", children: "(manage via super admin)" }) : null
                ] })
              ] })
            ] }),
            nestedWildcards.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-3 mb-3", children: nestedWildcards.map(({ wildcard, features: wildcardFeatures }) => {
              const checked = granted.includes(wildcard) || hasGlobalWildcard || moduleWildcard;
              const wildcardRestricted = !actorIsSuperAdmin && isTenantRestrictedFeature(wildcard);
              const disabled = hasGlobalWildcard || moduleWildcard || wildcardRestricted;
              return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
                /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
                  /* @__PURE__ */ jsx(
                    "input",
                    {
                      id: `wildcard-${wildcard}`,
                      type: "checkbox",
                      className: "h-4 w-4",
                      checked,
                      disabled,
                      onChange: (e) => toggleWildcard(wildcard, !!e.target.checked)
                    }
                  ),
                  /* @__PURE__ */ jsxs(
                    "label",
                    {
                      htmlFor: `wildcard-${wildcard}`,
                      className: `text-sm ${disabled ? "text-muted-foreground" : ""}`,
                      children: [
                        formatWildcardLabel(group.moduleId, wildcard),
                        " ",
                        /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs font-mono", children: [
                          "(",
                          wildcard,
                          ")"
                        ] }),
                        wildcardRestricted ? /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs font-medium text-muted-foreground", children: t("auth.acl.restricted", "Restricted") }) : null
                      ]
                    }
                  )
                ] }),
                wildcardFeatures.length > 0 && /* @__PURE__ */ jsxs("div", { className: "relative ml-6 pl-4 text-sm text-muted-foreground space-y-1", children: [
                  /* @__PURE__ */ jsx("div", { className: "absolute left-0 top-1 bottom-1 w-px bg-border", "aria-hidden": true }),
                  wildcardFeatures.map((wf) => /* @__PURE__ */ jsx("div", { className: "pl-2", children: /* @__PURE__ */ jsxs("span", { children: [
                    wf.title,
                    " ",
                    /* @__PURE__ */ jsxs("span", { className: "text-xs font-mono text-muted-foreground", children: [
                      "(",
                      wf.id,
                      ")"
                    ] })
                  ] }) }, `${wildcard}-${wf.id}`))
                ] })
              ] }, wildcard);
            }) }),
            /* @__PURE__ */ jsx("div", { className: "space-y-2", children: group.features.map((f) => {
              if (nestedCoveredIds.has(f.id)) return null;
              const checked = isFeatureChecked(f.id);
              const isWildcardCovered = isFeatureCoveredByWildcard(f.id);
              const restricted = !actorIsSuperAdmin && isTenantRestrictedFeature(f.id);
              const disabled = isWildcardCovered || restricted;
              return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
                /* @__PURE__ */ jsx(
                  "input",
                  {
                    id: `f-${f.id}`,
                    type: "checkbox",
                    className: "h-4 w-4",
                    checked,
                    disabled,
                    onChange: (e) => {
                      const on = !!e.target.checked;
                      updateGranted((prev) => {
                        if (on) return [...prev, f.id];
                        return prev.filter((x) => x !== f.id);
                      });
                    }
                  }
                ),
                /* @__PURE__ */ jsxs(
                  "label",
                  {
                    htmlFor: `f-${f.id}`,
                    className: `text-sm ${disabled ? "text-muted-foreground" : ""}`,
                    children: [
                      f.title,
                      " ",
                      /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
                        "(",
                        f.id,
                        ")"
                      ] }),
                      restricted ? /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs font-medium text-muted-foreground", children: t("auth.acl.restricted", "Restricted") }) : null
                    ]
                  }
                )
              ] }, f.id);
            }) })
          ] }, group.moduleId);
        }) })
      ] }),
      canEditOrganizations && /* @__PURE__ */ jsxs("div", { className: "rounded border p-3", children: [
        /* @__PURE__ */ jsx("div", { className: "text-sm font-medium mb-2", children: t("auth.acl.organizationsScope", "Organizations scope") }),
        /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground mb-2", children: "Empty = all organizations. Select one or more to restrict." }),
        /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-2", children: orgOptions.map((o) => {
          const checked = organizations == null ? false : (organizations || []).includes(o.id);
          return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
            /* @__PURE__ */ jsx("input", { id: `org-${o.id}`, type: "checkbox", className: "h-4 w-4", checked, onChange: (e) => {
              const on = !!e.target.checked;
              setOrganizations((prev) => {
                if (prev == null) return on ? [o.id] : [];
                return on ? Array.from(/* @__PURE__ */ new Set([...prev || [], o.id])) : (prev || []).filter((x) => x !== o.id);
              });
            } }),
            /* @__PURE__ */ jsx("label", { htmlFor: `org-${o.id}`, className: "text-sm", children: o.name })
          ] }, o.id);
        }) }),
        /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setOrganizations(null), children: t("auth.acl.allowAllOrganizations", "Allow all organizations") }) }),
        showOrganizationWarning && /* @__PURE__ */ jsx("div", { className: "mt-3 rounded border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: t("auth.acl.organizationWarning", "Organization restrictions are saved only when at least one feature override is selected. Add a feature or enable a module wildcard before saving.") })
      ] })
    ] })
  ] });
}
export {
  AclEditor
};
//# sourceMappingURL=AclEditor.js.map
