import { ModuleConfig } from "../data/entities.js";
import { moduleConfigKeySchema } from "../data/validators.js";
const CACHE_VERSION = "v2";
const CACHE_TTL_MS = 6e4;
const scopeKeyPart = (tenantId) => tenantId ?? "global";
const cacheKey = (moduleId, name, tenantId) => `module-config:${CACHE_VERSION}:${moduleId}:${name}:${scopeKeyPart(tenantId)}`;
const moduleTag = (moduleId) => `module-config:module:${moduleId}`;
const resolveEm = (container) => {
  try {
    return container.resolve("em");
  } catch {
    return null;
  }
};
const resolveCache = (container) => {
  try {
    return container.resolve("cache");
  } catch {
    return null;
  }
};
const toRecord = (entity, source) => ({
  moduleId: entity.moduleId,
  name: entity.name,
  value: entity.valueJson ?? null,
  tenantId: entity.tenantId ?? null,
  organizationId: entity.organizationId ?? null,
  source,
  createdAt: entity.createdAt.toISOString(),
  updatedAt: entity.updatedAt.toISOString()
});
const readCache = async (cache, key) => {
  if (!cache) return null;
  try {
    const cached = await cache.get(key);
    if (cached && typeof cached === "object" && "found" in cached) {
      return cached;
    }
  } catch {
  }
  return null;
};
const writeCache = async (cache, key, payload, moduleId) => {
  if (!cache) return;
  try {
    await cache.set(key, payload, { ttl: CACHE_TTL_MS, tags: [moduleTag(moduleId)] });
  } catch {
  }
};
const deleteCacheKey = async (cache, key) => {
  if (!cache) return;
  try {
    await cache.delete(key);
  } catch {
  }
};
const deleteCacheByModule = async (cache, moduleId) => {
  if (!cache) return;
  try {
    await cache.deleteByTags([moduleTag(moduleId)]);
  } catch {
  }
};
const normalizeKey = (moduleId, name) => moduleConfigKeySchema.parse({ moduleId, name });
function createModuleConfigService(container) {
  const getRecord = async (rawModuleId, rawName, scope) => {
    const { moduleId, name } = normalizeKey(rawModuleId, rawName);
    const tenantId = scope?.tenantId ?? null;
    const cache = resolveCache(container);
    const key = cacheKey(moduleId, name, tenantId);
    const cached = await readCache(cache, key);
    if (cached) {
      if (!cached.found) return null;
      if (cached.record) return cached.record;
    }
    const em = resolveEm(container);
    if (!em) return null;
    const repo = em.getRepository(ModuleConfig);
    if (tenantId) {
      const scoped = await repo.findOne({ moduleId, name, tenantId });
      if (scoped) {
        const record3 = toRecord(scoped, "tenant");
        await writeCache(cache, key, { found: true, record: record3 }, moduleId);
        return record3;
      }
      const global2 = await repo.findOne({ moduleId, name, tenantId: null });
      if (!global2) {
        await writeCache(cache, key, { found: false }, moduleId);
        return null;
      }
      const record2 = toRecord(global2, "instance");
      await writeCache(cache, key, { found: true, record: record2 }, moduleId);
      return record2;
    }
    const global = await repo.findOne({ moduleId, name, tenantId: null });
    if (!global) {
      await writeCache(cache, key, { found: false }, moduleId);
      return null;
    }
    const record = toRecord(global, "instance");
    await writeCache(cache, key, { found: true, record }, moduleId);
    return record;
  };
  const getValue = async (rawModuleId, rawName, options) => {
    const record = await getRecord(rawModuleId, rawName, options?.scope);
    if (!record) return options?.defaultValue ?? null;
    const value = record.value;
    if (value === void 0 || value === null) return options?.defaultValue ?? null;
    return value;
  };
  const setValue = async (rawModuleId, rawName, value, scope) => {
    const em = resolveEm(container);
    if (!em) return null;
    const { moduleId, name } = normalizeKey(rawModuleId, rawName);
    const tenantId = scope?.tenantId ?? null;
    const organizationId = scope?.organizationId ?? null;
    const repo = em.getRepository(ModuleConfig);
    const now = /* @__PURE__ */ new Date();
    let entity = await repo.findOne({ moduleId, name, tenantId });
    if (!entity) {
      entity = repo.create({
        moduleId,
        name,
        valueJson: value ?? null,
        tenantId,
        organizationId,
        createdAt: now,
        updatedAt: now
      });
      em.persist(entity);
    } else {
      entity.valueJson = value ?? null;
      entity.organizationId = organizationId;
      entity.updatedAt = now;
    }
    await em.flush();
    const record = toRecord(entity, tenantId ? "tenant" : "instance");
    const cache = resolveCache(container);
    if (tenantId) {
      await writeCache(cache, cacheKey(moduleId, name, tenantId), { found: true, record }, moduleId);
    } else {
      await deleteCacheByModule(cache, moduleId);
    }
    return record;
  };
  const restoreDefaults = async (defaults, options) => {
    if (!Array.isArray(defaults) || defaults.length === 0) return;
    const em = resolveEm(container);
    if (!em) return;
    const repo = em.getRepository(ModuleConfig);
    const cache = resolveCache(container);
    let dirty = false;
    const touched = [];
    for (const entry of defaults) {
      let entity = null;
      try {
        const { moduleId, name } = normalizeKey(entry.moduleId, entry.name);
        entity = await repo.findOne({ moduleId, name, tenantId: null });
        if (!entity) {
          entity = repo.create({
            moduleId,
            name,
            valueJson: entry.value ?? null,
            tenantId: null,
            organizationId: null
          });
          em.persist(entity);
          dirty = true;
          touched.push(entity);
        } else if (options?.force) {
          entity.valueJson = entry.value ?? null;
          entity.updatedAt = /* @__PURE__ */ new Date();
          dirty = true;
          touched.push(entity);
        }
      } catch {
      }
    }
    if (!dirty) return;
    await em.flush();
    for (const entity of touched) {
      const record = toRecord(entity, "instance");
      await writeCache(cache, cacheKey(entity.moduleId, entity.name, null), { found: true, record }, entity.moduleId);
    }
  };
  const invalidate = async (rawModuleId, rawName, scope) => {
    const cache = resolveCache(container);
    if (!cache) return;
    if (rawName) {
      const { moduleId: moduleId2, name } = normalizeKey(rawModuleId, rawName);
      await deleteCacheKey(cache, cacheKey(moduleId2, name, scope?.tenantId ?? null));
      return;
    }
    const moduleId = moduleConfigKeySchema.shape.moduleId.parse(rawModuleId);
    await deleteCacheByModule(cache, moduleId);
  };
  return {
    getRecord,
    getValue,
    setValue,
    restoreDefaults,
    invalidate
  };
}
export {
  createModuleConfigService
};
//# sourceMappingURL=module-config-service.js.map
