import { Fragment, jsx } from "react/jsx-runtime";
import {
  buildAdminNav,
  buildSettingsSections,
  computeSettingsPathPrefixes,
  convertToSectionNavGroups
} from "@open-mercato/ui/backend/utils/nav";
import { resolveRegisteredLucideIconNode } from "@open-mercato/ui/backend/icons/lucideRegistry";
import { profilePathPrefixes, profileSections } from "./profile-sections.js";
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
import { filterGrantsByEnabledModules } from "@open-mercato/shared/security/enabledModulesRegistry";
import {
  getSelectedOrganizationFromRequest,
  resolveFeatureCheckContext
} from "@open-mercato/core/modules/directory/utils/organizationScope";
import { isAllOrganizationsSelection } from "@open-mercato/core/modules/directory/constants";
import { Organization } from "@open-mercato/core/modules/directory/data/entities";
import { CustomEntity } from "@open-mercato/core/modules/entities/data/entities";
import { Role } from "@open-mercato/core/modules/auth/data/entities";
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import {
  applySidebarPreference,
  loadFirstRoleSidebarPreference,
  loadSidebarPreference
} from "@open-mercato/core/modules/auth/services/sidebarPreferencesService";
function groupBackendRoutesByModule(routes) {
  return Array.from(
    routes.reduce((grouped, route) => {
      const list = grouped.get(route.moduleId) ?? [];
      list.push(route);
      grouped.set(route.moduleId, list);
      return grouped;
    }, /* @__PURE__ */ new Map())
  ).map(([id, backendRoutes]) => ({ id, backendRoutes }));
}
const settingsSectionOrder = {
  system: 1,
  auth: 2,
  "customer-portal": 3,
  "data-designer": 4,
  "module-configs": 5,
  currencies: 6,
  directory: 7,
  "feature-toggles": 8
};
let renderToStaticMarkupPromise = null;
async function serializeIconMarkup(icon) {
  if (!icon) return void 0;
  if (!renderToStaticMarkupPromise) {
    renderToStaticMarkupPromise = import("react-dom/server");
  }
  const { renderToStaticMarkup } = await renderToStaticMarkupPromise;
  const normalizedIcon = typeof icon === "string" ? resolveRegisteredLucideIconNode(icon, "size-4") : icon;
  if (!normalizedIcon) return void 0;
  try {
    const markup = renderToStaticMarkup(/* @__PURE__ */ jsx(Fragment, { children: normalizedIcon }));
    return markup.trim().length > 0 ? markup : void 0;
  } catch {
    return void 0;
  }
}
async function serializeNavItem(item) {
  return {
    id: item.href,
    href: item.href,
    title: item.title,
    defaultTitle: item.defaultTitle,
    enabled: item.enabled,
    hidden: item.hidden,
    pageContext: item.pageContext,
    iconName: typeof item.icon === "string" ? item.icon : void 0,
    iconMarkup: await serializeIconMarkup(item.icon),
    children: item.children ? await Promise.all(item.children.map((child) => serializeNavItem(child))) : void 0
  };
}
function normalizeGroupWeights(groups) {
  const defaultGroupOrder = [
    "customers.nav.group",
    "catalog.nav.group",
    "customers~sales.nav.group",
    "resources.nav.group",
    "staff.nav.group",
    "entities.nav.group",
    "directory.nav.group",
    "customers.storage.nav.group"
  ];
  const groupOrderIndex = new Map(defaultGroupOrder.map((id, index) => [id, index]));
  groups.sort((a, b) => {
    const aIndex = groupOrderIndex.get(a.id);
    const bIndex = groupOrderIndex.get(b.id);
    if (aIndex !== void 0 || bIndex !== void 0) {
      if (aIndex === void 0) return 1;
      if (bIndex === void 0) return -1;
      if (aIndex !== bIndex) return aIndex - bIndex;
    }
    if (a.weight !== b.weight) return a.weight - b.weight;
    return a.name.localeCompare(b.name);
  });
  const defaultGroupCount = defaultGroupOrder.length;
  groups.forEach((group, index) => {
    const rank = groupOrderIndex.get(group.id);
    const fallbackWeight = typeof group.weight === "number" ? group.weight : 1e4;
    group.weight = (rank !== void 0 ? rank : defaultGroupCount + index) * 1e6 + Math.min(Math.max(fallbackWeight, 0), 999999);
  });
  return groups;
}
async function groupEntries(entries) {
  const groupMap = /* @__PURE__ */ new Map();
  for (const entry of entries) {
    const weight = entry.priority ?? entry.order ?? 1e4;
    const serializedItem = await serializeNavItem(entry);
    const existing = groupMap.get(entry.groupId);
    if (existing) {
      existing.items.push(serializedItem);
      if (weight < existing.weight) existing.weight = weight;
      continue;
    }
    groupMap.set(entry.groupId, {
      id: entry.groupId,
      name: entry.group,
      defaultName: entry.groupDefaultName,
      items: [serializedItem],
      weight
    });
  }
  return normalizeGroupWeights(Array.from(groupMap.values()));
}
function adoptSidebarDefaults(groups) {
  const adoptItems = (items) => items.map((item) => ({
    ...item,
    defaultTitle: item.title,
    children: item.children ? adoptItems(item.children) : void 0
  }));
  return groups.map((group) => ({
    ...group,
    defaultName: group.name,
    items: adoptItems(group.items)
  }));
}
async function serializeSectionItem(item) {
  return {
    id: item.id,
    label: item.label,
    labelKey: item.labelKey,
    href: item.href,
    order: item.order,
    iconName: typeof item.icon === "string" ? item.icon : void 0,
    iconMarkup: await serializeIconMarkup(item.icon),
    children: item.children ? await Promise.all(item.children.map((child) => serializeSectionItem(child))) : void 0
  };
}
async function serializeSectionGroups(groups) {
  return Promise.all(groups.map(async (group) => ({
    id: group.id,
    label: group.label,
    labelKey: group.labelKey,
    order: group.order,
    items: await Promise.all(group.items.map((item) => serializeSectionItem(item)))
  })));
}
async function loadScopedContainer() {
  return createRequestContainer();
}
async function resolveBackendChromePayload({
  auth,
  locale,
  modules,
  translate,
  request,
  selectedOrganizationId,
  selectedTenantId
}) {
  const container = await loadScopedContainer();
  const em = container.resolve("em");
  const rbac = container.resolve("rbacService");
  let scopedOrganizationId = auth.orgId ?? null;
  let scopedTenantId = auth.tenantId ?? null;
  let allowNavigation = true;
  try {
    const { organizationId, scope, allowedOrganizationIds } = await resolveFeatureCheckContext({
      container,
      auth,
      request,
      selectedId: selectedOrganizationId,
      tenantId: selectedTenantId
    });
    scopedOrganizationId = organizationId;
    scopedTenantId = scope.tenantId ?? auth.tenantId ?? null;
    if (Array.isArray(allowedOrganizationIds) && allowedOrganizationIds.length === 0) {
      allowNavigation = false;
    }
  } catch {
    scopedOrganizationId = auth.orgId ?? null;
    scopedTenantId = auth.tenantId ?? null;
  }
  const acl = allowNavigation ? await rbac.loadAcl(auth.sub, {
    tenantId: scopedTenantId,
    organizationId: scopedOrganizationId
  }) : { isSuperAdmin: false, features: [] };
  const rawGrantedFeatures = acl.isSuperAdmin ? ["*"] : acl.features;
  const grantedFeatures = filterGrantsByEnabledModules(rawGrantedFeatures);
  const featureChecker = async (features) => {
    if (!allowNavigation || !features.length) return [];
    const context = {
      tenantId: scopedTenantId ?? auth.tenantId ?? null,
      organizationId: scopedOrganizationId ?? null
    };
    const hasAll = await rbac.userHasAllFeatures(auth.sub, features, context);
    if (hasAll) return features;
    const granted = [];
    for (const feature of features) {
      const hasFeature = await rbac.userHasAllFeatures(auth.sub, [feature], context);
      if (hasFeature) granted.push(feature);
    }
    return granted;
  };
  let userEntities = [];
  if (allowNavigation) {
    try {
      const where = {
        isActive: true,
        showInSidebar: true
      };
      where.$and = [
        { $or: [{ organizationId: scopedOrganizationId ?? void 0 }, { organizationId: null }] },
        { $or: [{ tenantId: scopedTenantId ?? void 0 }, { tenantId: null }] }
      ];
      const entities = await em.find(CustomEntity, where, { orderBy: { label: "asc" } });
      userEntities = entities.map((entity) => ({
        entityId: entity.entityId,
        label: entity.label,
        href: `/backend/entities/user/${encodeURIComponent(entity.entityId)}/records`
      }));
    } catch {
      userEntities = [];
    }
  }
  const ctxAuth = {
    roles: auth.roles || [],
    sub: auth.sub,
    tenantId: scopedTenantId,
    orgId: scopedOrganizationId
  };
  const entries = allowNavigation ? await buildAdminNav(
    modules,
    { auth: ctxAuth },
    userEntities,
    translate,
    { checkFeatures: featureChecker }
  ) : [];
  let rolePreference = null;
  let userPreference = null;
  if (Array.isArray(auth.roles) && auth.roles.length > 0) {
    const roleRecords = scopedTenantId ? await em.find(Role, {
      name: { $in: auth.roles },
      tenantId: scopedTenantId
    }) : [];
    const roleIds = Array.isArray(roleRecords) ? roleRecords.map((role) => role.id) : [];
    if (roleIds.length > 0) {
      rolePreference = await loadFirstRoleSidebarPreference(em, {
        roleIds,
        tenantId: scopedTenantId,
        locale
      });
    }
  }
  const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub;
  if (effectiveUserId) {
    userPreference = await loadSidebarPreference(em, {
      userId: effectiveUserId,
      tenantId: scopedTenantId,
      organizationId: scopedOrganizationId,
      locale
    });
  }
  const baseGroups = await groupEntries(entries);
  const groupsWithRole = rolePreference ? applySidebarPreference(baseGroups, rolePreference) : baseGroups;
  const baseForUser = adoptSidebarDefaults(groupsWithRole);
  const appliedGroups = userPreference ? applySidebarPreference(baseForUser, userPreference) : baseForUser;
  const settingsSections = await serializeSectionGroups(
    convertToSectionNavGroups(
      buildSettingsSections(entries, settingsSectionOrder),
      translate
    )
  );
  const requestOrganizationId = request ? getSelectedOrganizationFromRequest(request) : null;
  const fallbackOrganizationId = selectedOrganizationId ?? requestOrganizationId ?? auth.orgId ?? null;
  const brandOrganizationId = scopedOrganizationId ?? (fallbackOrganizationId && !isAllOrganizationsSelection(fallbackOrganizationId) ? fallbackOrganizationId : null);
  let brand = null;
  if (brandOrganizationId && scopedTenantId) {
    try {
      const organization = await findOneWithDecryption(
        em,
        Organization,
        { id: brandOrganizationId, tenant: scopedTenantId, deletedAt: null },
        void 0,
        { tenantId: scopedTenantId, organizationId: brandOrganizationId }
      );
      if (organization?.logoUrl) {
        brand = {
          name: organization.name,
          logo: {
            src: organization.logoUrl,
            alt: `${organization.name} logo`
          }
        };
      }
    } catch {
      brand = null;
    }
  }
  return {
    groups: appliedGroups.map(({ weight: _weight, ...group }) => group),
    settingsSections,
    settingsPathPrefixes: computeSettingsPathPrefixes(buildSettingsSections(entries, settingsSectionOrder)),
    profileSections: await serializeSectionGroups(profileSections),
    profilePathPrefixes,
    grantedFeatures,
    roles: Array.isArray(auth.roles) ? auth.roles : [],
    brand
  };
}
export {
  groupBackendRoutesByModule,
  resolveBackendChromePayload
};
//# sourceMappingURL=backendChrome.js.map
