import { randomUUID } from "node:crypto";
import { findAndCountWithDecryption, findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import { enforceCommandOptimisticLockWithGuards, enforceRecordGoneIsConflict } from "@open-mercato/shared/lib/crud/optimistic-lock-command";
import { SyncSchedule } from "../data/entities.js";
function createSyncScheduleService(em, schedulerService) {
  function requireScheduler() {
    if (!schedulerService) {
      throw new Error("Scheduler module is not available");
    }
    return schedulerService;
  }
  function buildScheduleName(row) {
    return `Data sync: ${row.integrationId} ${row.entityType} ${row.direction}`;
  }
  function buildScheduleDescription(row) {
    return `Scheduled ${row.direction} for ${row.integrationId} (${row.entityType})`;
  }
  async function getById(id, scope) {
    return findOneWithDecryption(
      em,
      SyncSchedule,
      {
        id,
        organizationId: scope.organizationId,
        tenantId: scope.tenantId,
        deletedAt: null
      },
      void 0,
      scope
    );
  }
  async function getByKey(integrationId, entityType, direction, scope) {
    return findOneWithDecryption(
      em,
      SyncSchedule,
      {
        integrationId,
        entityType,
        direction,
        organizationId: scope.organizationId,
        tenantId: scope.tenantId,
        deletedAt: null
      },
      void 0,
      scope
    );
  }
  return {
    getById,
    getByKey,
    async listSchedules(query, scope) {
      const where = {
        organizationId: scope.organizationId,
        tenantId: scope.tenantId,
        deletedAt: null
      };
      if (query.integrationId) where.integrationId = query.integrationId;
      if (query.entityType) where.entityType = query.entityType;
      if (query.direction) where.direction = query.direction;
      const [items, total] = await findAndCountWithDecryption(
        em,
        SyncSchedule,
        where,
        {
          orderBy: { createdAt: "DESC" },
          limit: query.pageSize,
          offset: (query.page - 1) * query.pageSize
        },
        scope
      );
      return { items, total };
    },
    async saveSchedule(input, scope, container) {
      const existing = input.id ? await getById(input.id, scope) : await getByKey(input.integrationId, input.entityType, input.direction, scope);
      if (existing && container) {
        await enforceCommandOptimisticLockWithGuards(container, {
          resourceKind: "data_sync.schedule",
          resourceId: existing.id,
          current: existing.updatedAt ?? null,
          expected: input.expectedUpdatedAt ?? null
        });
      } else if (!existing && input.expectedUpdatedAt) {
        enforceRecordGoneIsConflict({
          resourceKind: "data_sync.schedule",
          resourceId: input.id ?? `${input.integrationId}:${input.entityType}:${input.direction}`,
          expected: input.expectedUpdatedAt
        });
      }
      const row = existing ?? em.create(SyncSchedule, {
        id: randomUUID(),
        integrationId: input.integrationId,
        entityType: input.entityType,
        direction: input.direction,
        scheduleType: input.scheduleType,
        scheduleValue: input.scheduleValue,
        timezone: input.timezone,
        fullSync: input.fullSync,
        isEnabled: input.isEnabled,
        organizationId: scope.organizationId,
        tenantId: scope.tenantId
      });
      row.integrationId = input.integrationId;
      row.entityType = input.entityType;
      row.direction = input.direction;
      row.scheduleType = input.scheduleType;
      row.scheduleValue = input.scheduleValue;
      row.timezone = input.timezone;
      row.fullSync = input.fullSync;
      row.isEnabled = input.isEnabled;
      row.scheduledJobId = row.scheduledJobId ?? row.id;
      if (!existing) {
        em.persist(row);
      }
      await em.flush();
      await requireScheduler().register({
        id: row.scheduledJobId,
        name: buildScheduleName(row),
        description: buildScheduleDescription(row),
        scopeType: "organization",
        organizationId: scope.organizationId,
        tenantId: scope.tenantId,
        scheduleType: row.scheduleType,
        scheduleValue: row.scheduleValue,
        timezone: row.timezone,
        targetType: "queue",
        targetQueue: "data-sync-scheduled",
        targetPayload: {
          scheduleId: row.id,
          scope
        },
        requireFeature: "data_sync.run",
        sourceType: "module",
        sourceModule: "data_sync",
        isEnabled: row.isEnabled
      });
      return row;
    },
    async deleteSchedule(id, scope, container, expectedUpdatedAt) {
      const row = await getById(id, scope);
      if (!row) return false;
      if (container) {
        await enforceCommandOptimisticLockWithGuards(container, {
          resourceKind: "data_sync.schedule",
          resourceId: row.id,
          current: row.updatedAt ?? null,
          expected: expectedUpdatedAt ?? null
        });
      }
      const scheduledJobId = row.scheduledJobId ?? row.id;
      await requireScheduler().unregister(scheduledJobId);
      row.deletedAt = /* @__PURE__ */ new Date();
      row.isEnabled = false;
      await em.flush();
      return true;
    }
  };
}
export {
  createSyncScheduleService
};
//# sourceMappingURL=sync-schedule-service.js.map
