import { runWithCacheTenant } from "@open-mercato/cache";
import { parseBooleanToken } from "../boolean.js";
import { createLogger } from "../logger/index.js";
const logger = createLogger("shared").child({ component: "crud-cache" });
let crudCacheEnabledFlag = null;
function isCrudCacheEnabled() {
  if (crudCacheEnabledFlag !== null) return crudCacheEnabledFlag;
  crudCacheEnabledFlag = parseBooleanToken(process.env.ENABLE_CRUD_API_CACHE ?? "") === true;
  return crudCacheEnabledFlag;
}
let crudCacheDebugFlag = null;
function isCrudCacheDebugEnabled() {
  if (crudCacheDebugFlag !== null) return crudCacheDebugFlag;
  crudCacheDebugFlag = parseBooleanToken(process.env.QUERY_ENGINE_DEBUG_SQL ?? "") === true;
  return crudCacheDebugFlag;
}
function debugCrudCache(event, context) {
  if (!isCrudCacheDebugEnabled()) return;
  try {
    logger.debug(event, context);
  } catch {
  }
}
function resolveCrudCache(container) {
  try {
    const cache = container.resolve("cache");
    if (cache && typeof cache.get === "function" && typeof cache.set === "function") {
      return cache;
    }
  } catch {
  }
  return null;
}
function normalizeTagSegment(value) {
  if (value === null || value === void 0 || value === "") return "null";
  return value.toString().trim().replace(/[^a-zA-Z0-9._-]/g, "-");
}
function canonicalizeResourceTag(value) {
  if (value === null || value === void 0) return null;
  const trimmed = String(value).trim();
  if (!trimmed.length) return null;
  const withSeparators = trimmed.replace(/::/g, ".").replace(/[/\\]+/g, ".").replace(/[\s]+/g, ".").replace(/_/g, ".").replace(/-+/g, ".");
  const withCamelBreaks = withSeparators.replace(/([a-z0-9])([A-Z])/g, "$1.$2");
  const collapsed = withCamelBreaks.replace(/\.{2,}/g, ".").replace(/(?:^\.+|\.+$)/g, "");
  const lowered = collapsed.toLowerCase();
  return lowered.length ? lowered : null;
}
function buildRecordTag(resource, tenantId, recordId) {
  return [
    "crud",
    normalizeTagSegment(resource),
    "tenant",
    normalizeTagSegment(tenantId),
    "record",
    normalizeTagSegment(recordId)
  ].join(":");
}
function buildCollectionTags(resource, tenantId, organizationIds) {
  const normalizedResource = normalizeTagSegment(resource);
  const normalizedTenant = normalizeTagSegment(tenantId);
  const tags = /* @__PURE__ */ new Set();
  if (!organizationIds.length) {
    tags.add(["crud", normalizedResource, "tenant", normalizedTenant, "org", "null", "collection"].join(":"));
    return Array.from(tags);
  }
  for (const orgId of organizationIds) {
    tags.add(["crud", normalizedResource, "tenant", normalizedTenant, "org", normalizeTagSegment(orgId), "collection"].join(":"));
  }
  return Array.from(tags);
}
function normalizeIdentifierValue(value) {
  if (value === null || value === void 0) return null;
  if (typeof value === "string") return value;
  if (typeof value === "number" || typeof value === "bigint") return String(value);
  if (typeof value === "object") {
    if (value instanceof Date) return value.toISOString();
    if (value && typeof value.id !== "undefined") {
      return normalizeIdentifierValue(value.id);
    }
  }
  return String(value);
}
function pickFirstIdentifier(...values) {
  for (const value of values) {
    const normalized = normalizeIdentifierValue(value);
    if (normalized) return normalized;
  }
  return null;
}
const IRREGULAR_PLURALS = {
  people: "person",
  children: "child",
  mice: "mouse",
  men: "man",
  women: "woman",
  geese: "goose",
  feet: "foot",
  teeth: "tooth",
  oxen: "ox"
};
function singularizeSegment(segment) {
  const lower = segment.toLowerCase();
  const irregular = IRREGULAR_PLURALS[lower];
  if (irregular) return irregular;
  if (lower.endsWith("ies") && lower.length > 3) return lower.slice(0, -3) + "y";
  if (lower.endsWith("ses") && lower.length > 3) return lower.slice(0, -2);
  if ((lower.endsWith("xes") || lower.endsWith("zes") || lower.endsWith("ches") || lower.endsWith("shes")) && lower.length > 3) {
    return lower.slice(0, -2);
  }
  if (lower.endsWith("s") && !lower.endsWith("ss") && lower.length > 1) return lower.slice(0, -1);
  return lower;
}
function singularizeResourceSegment(segment) {
  return segment.split("-").map((part) => singularizeSegment(part)).join("-");
}
function deriveResourceFromCommandId(commandId) {
  if (!commandId || typeof commandId !== "string") return null;
  const parts = commandId.split(".");
  if (parts.length < 2) return null;
  const modulePart = parts[0];
  const entityPart = singularizeResourceSegment(parts[1]);
  if (!modulePart || !entityPart) return null;
  return `${modulePart}.${entityPart}`;
}
function expandResourceAliases(resource, aliases) {
  const set = /* @__PURE__ */ new Set();
  const inputs = [resource, ...aliases ?? []];
  for (const candidate of inputs) {
    const canonical = canonicalizeResourceTag(candidate);
    if (canonical) set.add(canonical);
  }
  if (!set.size) return [];
  return Array.from(set);
}
async function invalidateCrudCache(container, resource, identifiers, fallbackTenant, reason, aliases) {
  if (!isCrudCacheEnabled()) return;
  const cache = resolveCrudCache(container);
  if (!cache || typeof cache.deleteByTags !== "function") return;
  const resources = expandResourceAliases(resource, aliases);
  const tenantId = identifiers.tenantId ?? fallbackTenant ?? null;
  const recordId = normalizeIdentifierValue(identifiers.id);
  const tags = /* @__PURE__ */ new Set();
  for (const key of resources) {
    if (recordId) {
      tags.add(buildRecordTag(key, tenantId, recordId));
    }
    const organizationIds = [null];
    const recordOrganizationId = identifiers.organizationId ?? null;
    if (recordOrganizationId) organizationIds.push(recordOrganizationId);
    for (const tag of buildCollectionTags(key, tenantId, organizationIds)) {
      tags.add(tag);
    }
  }
  if (!tags.size) return;
  const tagList = Array.from(tags);
  debugCrudCache("invalidate", {
    resource,
    aliases: resources,
    reason,
    tenantId: tenantId ?? "null",
    tags: tagList,
    action: "clearing"
  });
  const deleted = await runWithCacheTenant(tenantId, () => cache.deleteByTags(tagList));
  debugCrudCache("invalidate", {
    resource,
    reason,
    tenantId: tenantId ?? "null",
    tags: tagList,
    action: "cleared",
    deleted
  });
}
export {
  buildCollectionTags,
  buildRecordTag,
  canonicalizeResourceTag,
  debugCrudCache,
  deriveResourceFromCommandId,
  expandResourceAliases,
  invalidateCrudCache,
  isCrudCacheDebugEnabled,
  isCrudCacheEnabled,
  normalizeIdentifierValue,
  normalizeTagSegment,
  pickFirstIdentifier,
  resolveCrudCache
};
//# sourceMappingURL=cache.js.map
