import { registerCommand } from "@open-mercato/shared/lib/commands";
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import { buildChanges, emitCrudSideEffects, emitCrudUndoSideEffects, parseWithCustomFields, setCustomFieldsIfAny } from "@open-mercato/shared/lib/commands/helpers";
import { buildCustomFieldResetMap, diffCustomFieldChanges, loadCustomFieldSnapshot } from "@open-mercato/shared/lib/commands/customFieldSnapshots";
import { makeCreateRedo } from "@open-mercato/shared/lib/commands/redo";
import { StaffTeam, StaffTeamMember } from "../data/entities.js";
import {
  staffTeamCreateSchema,
  staffTeamUpdateSchema
} from "../data/validators.js";
import { staffTeamCrudEvents } from "../lib/crud.js";
import {
  applyScopeToWhere,
  commandActorScope,
  commandInputScope,
  ensureOrganizationScope,
  ensureTenantScope,
  extractUndoPayload,
  scopeForDecryption,
  scopedStaffSnapshotWhere,
  staffSnapshotDecryptionScope,
  staffSnapshotScopeFromContext,
  staffSnapshotScopeFromSnapshot
} from "./shared.js";
import { E } from "../../../generated/entities.ids.generated.js";
const teamCrudIndexer = {
  entityType: E.staff.staff_team
};
async function loadTeamSnapshot(em, id, scope) {
  const team = await findOneWithDecryption(
    em,
    StaffTeam,
    scopedStaffSnapshotWhere(id, scope),
    void 0,
    staffSnapshotDecryptionScope(scope)
  );
  if (!team) return null;
  return {
    id: team.id,
    tenantId: team.tenantId,
    organizationId: team.organizationId,
    name: team.name,
    description: team.description ?? null,
    isActive: team.isActive ?? true,
    deletedAt: team.deletedAt ? team.deletedAt.toISOString() : null
  };
}
async function loadTeamCustomSnapshot(em, snapshot) {
  return loadCustomFieldSnapshot(em, {
    entityId: E.staff.staff_team,
    recordId: snapshot.id,
    tenantId: snapshot.tenantId,
    organizationId: snapshot.organizationId
  });
}
const redoTeamCreate = makeCreateRedo({
  entityClass: StaffTeam,
  buildResult: (entity) => ({ teamId: entity.id }),
  events: staffTeamCrudEvents,
  indexer: teamCrudIndexer
});
const createTeamCommand = {
  id: "staff.teams.create",
  async execute(rawInput, ctx) {
    const { parsed, custom } = parseWithCustomFields(staffTeamCreateSchema, rawInput);
    ensureTenantScope(ctx, parsed.tenantId);
    ensureOrganizationScope(ctx, parsed.organizationId);
    commandInputScope(ctx, parsed.tenantId, parsed.organizationId);
    const em = ctx.container.resolve("em").fork();
    const now = /* @__PURE__ */ new Date();
    const team = em.create(StaffTeam, {
      tenantId: parsed.tenantId,
      organizationId: parsed.organizationId,
      name: parsed.name,
      description: parsed.description ?? null,
      isActive: parsed.isActive ?? true,
      createdAt: now,
      updatedAt: now,
      deletedAt: null
    });
    em.persist(team);
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await setCustomFieldsIfAny({
      dataEngine: de,
      entityId: E.staff.staff_team,
      recordId: team.id,
      tenantId: team.tenantId,
      organizationId: team.organizationId,
      values: custom
    });
    await emitCrudSideEffects({
      dataEngine: de,
      action: "created",
      entity: team,
      identifiers: {
        id: team.id,
        organizationId: team.organizationId,
        tenantId: team.tenantId
      },
      events: staffTeamCrudEvents,
      indexer: teamCrudIndexer
    });
    return { teamId: team.id };
  },
  captureAfter: async (_input, result, ctx) => {
    const em = ctx.container.resolve("em").fork();
    const snapshot = await loadTeamSnapshot(em, result.teamId, staffSnapshotScopeFromContext(ctx));
    if (!snapshot) return null;
    const custom = await loadTeamCustomSnapshot(em, snapshot);
    return { snapshot, custom };
  },
  buildLog: async ({ result, ctx }) => {
    const em = ctx.container.resolve("em").fork();
    const snapshot = await loadTeamSnapshot(em, result.teamId, staffSnapshotScopeFromContext(ctx));
    if (!snapshot) return null;
    const custom = await loadTeamCustomSnapshot(em, snapshot);
    const { translate } = await resolveTranslations();
    return {
      actionLabel: translate("staff.audit.teams.create", "Create team"),
      resourceKind: "staff.team",
      resourceId: snapshot.id,
      tenantId: snapshot.tenantId,
      organizationId: snapshot.organizationId,
      snapshotAfter: snapshot,
      payload: {
        undo: {
          after: snapshot,
          customAfter: custom
        }
      }
    };
  },
  undo: async ({ logEntry, ctx }) => {
    const payload = extractUndoPayload(logEntry);
    const after = payload?.after;
    if (!after) return;
    const em = ctx.container.resolve("em").fork();
    const team = await em.findOne(StaffTeam, scopedStaffSnapshotWhere(after.id, staffSnapshotScopeFromSnapshot(after)));
    if (team) {
      team.deletedAt = /* @__PURE__ */ new Date();
      await em.flush();
      const de = ctx.container.resolve("dataEngine");
      await emitCrudUndoSideEffects({
        dataEngine: de,
        action: "deleted",
        entity: team,
        identifiers: {
          id: team.id,
          organizationId: team.organizationId,
          tenantId: team.tenantId
        },
        events: staffTeamCrudEvents,
        indexer: teamCrudIndexer
      });
    }
  },
  redo: async ({ logEntry, ctx }) => {
    const result = await redoTeamCreate({ input: void 0, ctx, logEntry });
    const payload = extractUndoPayload(logEntry);
    const customAfter = payload?.customAfter;
    if (customAfter && Object.keys(customAfter).length) {
      await setCustomFieldsIfAny({
        dataEngine: ctx.container.resolve("dataEngine"),
        entityId: E.staff.staff_team,
        recordId: result.teamId,
        tenantId: payload?.after?.tenantId ?? "",
        organizationId: payload?.after?.organizationId ?? "",
        values: customAfter
      });
    }
    return result;
  }
};
const updateTeamCommand = {
  id: "staff.teams.update",
  async prepare(rawInput, ctx) {
    const { parsed } = parseWithCustomFields(staffTeamUpdateSchema, rawInput);
    const em = ctx.container.resolve("em");
    const snapshot = await loadTeamSnapshot(em, parsed.id, staffSnapshotScopeFromContext(ctx));
    if (!snapshot) return {};
    const custom = await loadTeamCustomSnapshot(em, snapshot);
    return { before: snapshot, customBefore: custom };
  },
  async execute(rawInput, ctx) {
    const { parsed, custom } = parseWithCustomFields(staffTeamUpdateSchema, rawInput);
    const em = ctx.container.resolve("em").fork();
    const scope = commandActorScope(ctx);
    const team = await findOneWithDecryption(
      em,
      StaffTeam,
      applyScopeToWhere({ id: parsed.id, deletedAt: null }, scope),
      void 0,
      scopeForDecryption(scope)
    );
    if (!team) throw new CrudHttpError(404, { error: "Team not found." });
    ensureTenantScope(ctx, team.tenantId);
    ensureOrganizationScope(ctx, team.organizationId);
    if (parsed.name !== void 0) team.name = parsed.name;
    if (parsed.description !== void 0) team.description = parsed.description ?? null;
    if (parsed.isActive !== void 0) team.isActive = parsed.isActive;
    team.updatedAt = /* @__PURE__ */ new Date();
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await setCustomFieldsIfAny({
      dataEngine: de,
      entityId: E.staff.staff_team,
      recordId: team.id,
      tenantId: team.tenantId,
      organizationId: team.organizationId,
      values: custom
    });
    await emitCrudSideEffects({
      dataEngine: de,
      action: "updated",
      entity: team,
      identifiers: {
        id: team.id,
        organizationId: team.organizationId,
        tenantId: team.tenantId
      },
      events: staffTeamCrudEvents,
      indexer: teamCrudIndexer
    });
    return { teamId: team.id };
  },
  buildLog: async ({ snapshots, ctx }) => {
    const before = snapshots.before;
    if (!before) return null;
    const em = ctx.container.resolve("em").fork();
    const after = await loadTeamSnapshot(em, before.id, staffSnapshotScopeFromSnapshot(before));
    if (!after) return null;
    const customBefore = snapshots.customBefore ?? void 0;
    const customAfter = await loadTeamCustomSnapshot(em, after);
    const changes = buildChanges(before, after, [
      "name",
      "description",
      "isActive",
      "deletedAt"
    ]);
    const customChanges = diffCustomFieldChanges(customBefore, customAfter);
    if (Object.keys(customChanges).length) {
      changes.customFields = { from: customBefore ?? null, to: customAfter ?? null };
    }
    const { translate } = await resolveTranslations();
    return {
      actionLabel: translate("staff.audit.teams.update", "Update team"),
      resourceKind: "staff.team",
      resourceId: before.id,
      tenantId: before.tenantId,
      organizationId: before.organizationId,
      snapshotBefore: before,
      snapshotAfter: after,
      changes,
      payload: {
        undo: {
          before,
          after,
          customBefore: customBefore ?? null,
          customAfter
        }
      }
    };
  },
  undo: async ({ logEntry, ctx }) => {
    const payload = extractUndoPayload(logEntry);
    const before = payload?.before;
    if (!before) return;
    const em = ctx.container.resolve("em").fork();
    const team = await em.findOne(StaffTeam, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)));
    if (!team) return;
    team.name = before.name;
    team.description = before.description ?? null;
    team.isActive = before.isActive;
    team.deletedAt = before.deletedAt ? new Date(before.deletedAt) : null;
    team.updatedAt = /* @__PURE__ */ new Date();
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    if (payload.customBefore || payload.customAfter) {
      const reset = buildCustomFieldResetMap(payload.customBefore ?? void 0, payload.customAfter ?? void 0);
      await setCustomFieldsIfAny({
        dataEngine: de,
        entityId: E.staff.staff_team,
        recordId: team.id,
        tenantId: team.tenantId,
        organizationId: team.organizationId,
        values: reset
      });
    }
    await emitCrudUndoSideEffects({
      dataEngine: de,
      action: "updated",
      entity: team,
      identifiers: {
        id: team.id,
        organizationId: team.organizationId,
        tenantId: team.tenantId
      },
      events: staffTeamCrudEvents,
      indexer: teamCrudIndexer
    });
  }
};
const deleteTeamCommand = {
  id: "staff.teams.delete",
  async prepare(input, ctx) {
    const id = input?.id;
    if (!id) throw new CrudHttpError(400, { error: "Team id is required." });
    const em = ctx.container.resolve("em");
    const snapshot = await loadTeamSnapshot(em, id, staffSnapshotScopeFromContext(ctx));
    if (!snapshot) return {};
    const custom = await loadTeamCustomSnapshot(em, snapshot);
    return { before: snapshot, customBefore: custom };
  },
  async execute(input, ctx) {
    const id = input?.id;
    if (!id) throw new CrudHttpError(400, { error: "Team id is required." });
    const em = ctx.container.resolve("em").fork();
    const scope = commandActorScope(ctx);
    const team = await findOneWithDecryption(
      em,
      StaffTeam,
      applyScopeToWhere({ id, deletedAt: null }, scope),
      void 0,
      scopeForDecryption(scope)
    );
    if (!team) throw new CrudHttpError(404, { error: "Team not found." });
    ensureTenantScope(ctx, team.tenantId);
    ensureOrganizationScope(ctx, team.organizationId);
    const assignedMemberCount = await em.count(StaffTeamMember, {
      tenantId: team.tenantId,
      organizationId: team.organizationId,
      teamId: team.id,
      deletedAt: null
    });
    if (assignedMemberCount > 0) {
      const { t } = await resolveTranslations();
      throw new CrudHttpError(409, {
        error: t("staff.teams.errors.deleteAssigned", "Team has assigned members and cannot be deleted.")
      });
    }
    team.deletedAt = /* @__PURE__ */ new Date();
    team.updatedAt = /* @__PURE__ */ new Date();
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "deleted",
      entity: team,
      identifiers: {
        id: team.id,
        organizationId: team.organizationId,
        tenantId: team.tenantId
      },
      events: staffTeamCrudEvents,
      indexer: teamCrudIndexer
    });
    return { teamId: team.id };
  },
  buildLog: async ({ snapshots }) => {
    const before = snapshots.before;
    if (!before) return null;
    const customBefore = snapshots.customBefore ?? void 0;
    const { translate } = await resolveTranslations();
    return {
      actionLabel: translate("staff.audit.teams.delete", "Delete team"),
      resourceKind: "staff.team",
      resourceId: before.id,
      tenantId: before.tenantId,
      organizationId: before.organizationId,
      snapshotBefore: before,
      payload: {
        undo: {
          before,
          customBefore: customBefore ?? null
        }
      }
    };
  },
  undo: async ({ logEntry, ctx }) => {
    const payload = extractUndoPayload(logEntry);
    const before = payload?.before;
    if (!before) return;
    const em = ctx.container.resolve("em").fork();
    let team = await em.findOne(StaffTeam, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)));
    if (!team) {
      team = em.create(StaffTeam, {
        id: before.id,
        tenantId: before.tenantId,
        organizationId: before.organizationId,
        name: before.name,
        description: before.description ?? null,
        isActive: before.isActive,
        deletedAt: null,
        createdAt: /* @__PURE__ */ new Date(),
        updatedAt: /* @__PURE__ */ new Date()
      });
      em.persist(team);
    } else {
      team.name = before.name;
      team.description = before.description ?? null;
      team.isActive = before.isActive;
      team.deletedAt = null;
      team.updatedAt = /* @__PURE__ */ new Date();
    }
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    if (payload.customBefore) {
      const reset = buildCustomFieldResetMap(payload.customBefore, void 0);
      await setCustomFieldsIfAny({
        dataEngine: de,
        entityId: E.staff.staff_team,
        recordId: team.id,
        tenantId: team.tenantId,
        organizationId: team.organizationId,
        values: reset
      });
    }
    await emitCrudUndoSideEffects({
      dataEngine: de,
      action: "created",
      entity: team,
      identifiers: {
        id: team.id,
        organizationId: team.organizationId,
        tenantId: team.tenantId
      },
      events: staffTeamCrudEvents,
      indexer: teamCrudIndexer
    });
  }
};
registerCommand(createTeamCommand);
registerCommand(updateTeamCommand);
registerCommand(deleteTeamCommand);
//# sourceMappingURL=teams.js.map
