import { registerCommand } from "@open-mercato/shared/lib/commands";
import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import { CustomerPipelineStage, CustomerDeal } from "../data/entities.js";
import {
  pipelineStageCreateSchema,
  pipelineStageUpdateSchema,
  pipelineStageDeleteSchema,
  pipelineStageReorderSchema
} from "../data/validators.js";
import { ensureOrganizationScope, ensureTenantScope, ensureDictionaryEntry } from "./shared.js";
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
import {
  enforceCommandOptimisticLockWithGuards,
  enforceRecordGoneIsConflict
} from "@open-mercato/shared/lib/crud/optimistic-lock-command";
const createPipelineStageCommand = {
  id: "customers.pipeline-stages.create",
  async execute(rawInput, ctx) {
    const parsed = pipelineStageCreateSchema.parse(rawInput);
    ensureTenantScope(ctx, parsed.tenantId);
    ensureOrganizationScope(ctx, parsed.organizationId);
    const em = ctx.container.resolve("em").fork();
    const existingStages = await findWithDecryption(
      em,
      CustomerPipelineStage,
      {
        organizationId: parsed.organizationId,
        tenantId: parsed.tenantId,
        pipelineId: parsed.pipelineId
      },
      { orderBy: { order: "ASC" } },
      { tenantId: parsed.tenantId, organizationId: parsed.organizationId }
    );
    const requestedOrder = parsed.order;
    const insertOrder = requestedOrder === void 0 ? existingStages.length : Math.max(0, Math.min(requestedOrder, existingStages.length));
    const stage = em.create(CustomerPipelineStage, {
      organizationId: parsed.organizationId,
      tenantId: parsed.tenantId,
      pipelineId: parsed.pipelineId,
      label: parsed.label,
      order: insertOrder,
      createdAt: /* @__PURE__ */ new Date(),
      updatedAt: /* @__PURE__ */ new Date()
    });
    await withAtomicFlush(em, [
      () => {
        if (requestedOrder !== void 0) {
          for (const existing of existingStages) {
            if (existing.order >= insertOrder) {
              existing.order += 1;
              existing.updatedAt = /* @__PURE__ */ new Date();
            }
          }
        }
        em.persist(stage);
      },
      async () => {
        await ensureDictionaryEntry(em, {
          tenantId: parsed.tenantId,
          organizationId: parsed.organizationId,
          kind: "pipeline_stage",
          value: stage.label,
          color: parsed.color,
          icon: parsed.icon
        });
      }
    ], { transaction: true });
    return { stageId: stage.id };
  }
};
const updatePipelineStageCommand = {
  id: "customers.pipeline-stages.update",
  async execute(rawInput, ctx) {
    const parsed = pipelineStageUpdateSchema.parse(rawInput);
    const callerTenantId = ctx.auth?.tenantId ?? null;
    const callerOrganizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
    const em = ctx.container.resolve("em").fork();
    const stage = await findOneWithDecryption(em, CustomerPipelineStage, {
      id: parsed.id,
      ...callerTenantId ? { tenantId: callerTenantId } : {},
      ...callerOrganizationId ? { organizationId: callerOrganizationId } : {}
    });
    if (!stage) {
      enforceRecordGoneIsConflict({ resourceKind: "customers.pipelineStage", resourceId: parsed.id, request: ctx.request ?? null });
      throw new CrudHttpError(404, { error: "Pipeline stage not found" });
    }
    ensureTenantScope(ctx, stage.tenantId);
    ensureOrganizationScope(ctx, stage.organizationId);
    await enforceCommandOptimisticLockWithGuards(ctx.container, {
      resourceKind: "customers.pipelineStage",
      resourceId: stage.id,
      current: stage.updatedAt,
      request: ctx.request ?? null
    });
    await withAtomicFlush(em, [
      () => {
        if (parsed.label !== void 0) stage.label = parsed.label;
        if (parsed.order !== void 0) stage.order = parsed.order;
        stage.updatedAt = /* @__PURE__ */ new Date();
      },
      async () => {
        if (parsed.label !== void 0 || parsed.color !== void 0 || parsed.icon !== void 0) {
          await ensureDictionaryEntry(em, {
            tenantId: stage.tenantId,
            organizationId: stage.organizationId,
            kind: "pipeline_stage",
            value: stage.label,
            color: parsed.color,
            icon: parsed.icon
          });
        }
      }
    ], { transaction: true });
  }
};
const deletePipelineStageCommand = {
  id: "customers.pipeline-stages.delete",
  async execute(rawInput, ctx) {
    const parsed = pipelineStageDeleteSchema.parse(rawInput);
    const callerTenantId = ctx.auth?.tenantId ?? null;
    const callerOrganizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
    const em = ctx.container.resolve("em").fork();
    const stage = await findOneWithDecryption(em, CustomerPipelineStage, {
      id: parsed.id,
      ...callerTenantId ? { tenantId: callerTenantId } : {},
      ...callerOrganizationId ? { organizationId: callerOrganizationId } : {}
    });
    if (!stage) {
      enforceRecordGoneIsConflict({ resourceKind: "customers.pipelineStage", resourceId: parsed.id, request: ctx.request ?? null });
      throw new CrudHttpError(404, { error: "Pipeline stage not found" });
    }
    ensureTenantScope(ctx, stage.tenantId);
    ensureOrganizationScope(ctx, stage.organizationId);
    await enforceCommandOptimisticLockWithGuards(ctx.container, {
      resourceKind: "customers.pipelineStage",
      resourceId: stage.id,
      current: stage.updatedAt,
      request: ctx.request ?? null
    });
    const activeDealsCount = await em.count(CustomerDeal, {
      pipelineStageId: parsed.id,
      deletedAt: null
    });
    if (activeDealsCount > 0) {
      throw new CrudHttpError(409, { error: "Cannot delete pipeline stage with active deals" });
    }
    em.remove(stage);
    await em.flush();
  }
};
const reorderPipelineStagesCommand = {
  id: "customers.pipeline-stages.reorder",
  async execute(rawInput, ctx) {
    const parsed = pipelineStageReorderSchema.parse(rawInput);
    ensureTenantScope(ctx, parsed.tenantId);
    ensureOrganizationScope(ctx, parsed.organizationId);
    const em = ctx.container.resolve("em").fork();
    const ids = parsed.stages.map((s) => s.id);
    const stages = await findWithDecryption(
      em,
      CustomerPipelineStage,
      {
        id: { $in: ids },
        organizationId: parsed.organizationId,
        tenantId: parsed.tenantId
      },
      void 0,
      { tenantId: parsed.tenantId, organizationId: parsed.organizationId }
    );
    const stageMap = /* @__PURE__ */ new Map();
    stages.forEach((stage) => stageMap.set(stage.id, stage));
    for (const { id, order } of parsed.stages) {
      const stage = stageMap.get(id);
      if (!stage) continue;
      stage.order = order;
      stage.updatedAt = /* @__PURE__ */ new Date();
    }
    await em.flush();
  }
};
registerCommand(createPipelineStageCommand);
registerCommand(updatePipelineStageCommand);
registerCommand(deletePipelineStageCommand);
registerCommand(reorderPipelineStagesCommand);
export {
  createPipelineStageCommand,
  deletePipelineStageCommand,
  reorderPipelineStagesCommand,
  updatePipelineStageCommand
};
//# sourceMappingURL=pipeline-stages.js.map
