import { registerCommand } from "@open-mercato/shared/lib/commands";
import { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges, requireId } from "@open-mercato/shared/lib/commands/helpers";
import { StaffTeamMemberJobHistory } from "../data/entities.js";
import {
  staffTeamMemberJobHistoryCreateSchema,
  staffTeamMemberJobHistoryUpdateSchema
} from "../data/validators.js";
import { staffTeamMemberJobHistoryCrudEvents } from "../lib/crud.js";
import {
  applyScopeToWhere,
  commandActorScope,
  commandInputScope,
  ensureOrganizationScope,
  ensureTenantScope,
  explicitStaffCommandScope,
  extractUndoPayload,
  requireTeamMember,
  scopedStaffSnapshotWhere,
  staffSnapshotScopeFromContext,
  staffSnapshotScopeFromSnapshot
} from "./shared.js";
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
import { resolveRedoSnapshot } from "@open-mercato/shared/lib/commands/redo";
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import {
  enforceCommandOptimisticLockWithGuards,
  enforceRecordGoneIsConflict
} from "@open-mercato/shared/lib/crud/optimistic-lock-command";
import { E } from "../../../generated/entities.ids.generated.js";
const JOB_HISTORY_LOCK_RESOURCE_KIND = "staff.jobHistory";
const jobHistoryCrudIndexer = {
  entityType: E.staff.staff_team_member_job_history
};
async function loadJobHistorySnapshot(em, id, scope) {
  const record = await em.findOne(StaffTeamMemberJobHistory, scopedStaffSnapshotWhere(id, scope));
  if (!record) return null;
  return {
    id: record.id,
    organizationId: record.organizationId,
    tenantId: record.tenantId,
    memberId: typeof record.member === "string" ? record.member : record.member.id,
    name: record.name,
    companyName: record.companyName ?? null,
    description: record.description ?? null,
    startDate: record.startDate.toISOString(),
    endDate: record.endDate ? record.endDate.toISOString() : null,
    updatedAt: record.updatedAt.toISOString()
  };
}
const createJobHistoryCommand = {
  id: "staff.team-member-job-histories.create",
  async execute(rawInput, ctx) {
    const parsed = staffTeamMemberJobHistoryCreateSchema.parse(rawInput);
    ensureTenantScope(ctx, parsed.tenantId);
    ensureOrganizationScope(ctx, parsed.organizationId);
    const scope = commandInputScope(ctx, parsed.tenantId, parsed.organizationId);
    const em = ctx.container.resolve("em").fork();
    const member = await requireTeamMember(
      em,
      parsed.entityId,
      scope,
      "Team member not found"
    );
    ensureTenantScope(ctx, member.tenantId);
    ensureOrganizationScope(ctx, member.organizationId);
    const record = em.create(StaffTeamMemberJobHistory, {
      organizationId: parsed.organizationId,
      tenantId: parsed.tenantId,
      member,
      name: parsed.name,
      companyName: parsed.companyName ?? null,
      description: parsed.description ?? null,
      startDate: parsed.startDate,
      endDate: parsed.endDate ?? null,
      createdAt: /* @__PURE__ */ new Date(),
      updatedAt: /* @__PURE__ */ new Date()
    });
    em.persist(record);
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "created",
      entity: record,
      identifiers: {
        id: record.id,
        organizationId: record.organizationId,
        tenantId: record.tenantId
      },
      events: staffTeamMemberJobHistoryCrudEvents,
      indexer: jobHistoryCrudIndexer
    });
    return { jobHistoryId: record.id };
  },
  captureAfter: async (_input, result, ctx) => {
    const em = ctx.container.resolve("em").fork();
    return await loadJobHistorySnapshot(em, result.jobHistoryId, staffSnapshotScopeFromContext(ctx));
  },
  buildLog: async ({ result, snapshots }) => {
    const { translate } = await resolveTranslations();
    const snapshot = snapshots.after;
    return {
      actionLabel: translate("staff.audit.teamMemberJobHistories.create", "Create job history entry"),
      resourceKind: "staff.team_member_job_history",
      resourceId: result.jobHistoryId,
      parentResourceKind: "staff.teamMember",
      parentResourceId: snapshot?.memberId ?? null,
      tenantId: snapshot?.tenantId ?? null,
      organizationId: snapshot?.organizationId ?? null,
      snapshotAfter: snapshot ?? null,
      payload: {
        undo: {
          after: snapshot ?? null
        }
      }
    };
  },
  undo: async ({ logEntry, ctx }) => {
    const payload = extractUndoPayload(logEntry);
    const after = payload?.after ?? null;
    const jobHistoryId = after?.id ?? logEntry?.resourceId ?? null;
    if (!jobHistoryId) return;
    const em = ctx.container.resolve("em").fork();
    const record = await em.findOne(
      StaffTeamMemberJobHistory,
      scopedStaffSnapshotWhere(jobHistoryId, staffSnapshotScopeFromSnapshot(after))
    );
    if (record) {
      em.remove(record);
      await em.flush();
    }
  },
  redo: async ({ logEntry, ctx }) => {
    const after = resolveRedoSnapshot(logEntry);
    if (!after) {
      throw new CrudHttpError(400, { error: "[internal] redo snapshot unavailable for job history create" });
    }
    const em = ctx.container.resolve("em").fork();
    const snapshotScope = staffSnapshotScopeFromSnapshot(after);
    const member = await requireTeamMember(
      em,
      after.memberId,
      explicitStaffCommandScope(after.tenantId, after.organizationId),
      "Team member not found"
    );
    let record = await em.findOne(StaffTeamMemberJobHistory, scopedStaffSnapshotWhere(after.id, snapshotScope));
    if (!record) {
      record = em.create(StaffTeamMemberJobHistory, {
        id: after.id,
        organizationId: after.organizationId,
        tenantId: after.tenantId,
        member,
        name: after.name,
        companyName: after.companyName,
        description: after.description,
        startDate: new Date(after.startDate),
        endDate: after.endDate ? new Date(after.endDate) : null,
        createdAt: /* @__PURE__ */ new Date(),
        updatedAt: /* @__PURE__ */ new Date()
      });
      em.persist(record);
    } else {
      record.member = member;
      record.name = after.name;
      record.companyName = after.companyName;
      record.description = after.description;
      record.startDate = new Date(after.startDate);
      record.endDate = after.endDate ? new Date(after.endDate) : null;
    }
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "created",
      entity: record,
      identifiers: {
        id: record.id,
        organizationId: record.organizationId,
        tenantId: record.tenantId
      },
      events: staffTeamMemberJobHistoryCrudEvents,
      indexer: jobHistoryCrudIndexer
    });
    return { jobHistoryId: record.id };
  }
};
const updateJobHistoryCommand = {
  id: "staff.team-member-job-histories.update",
  async prepare(rawInput, ctx) {
    const parsed = staffTeamMemberJobHistoryUpdateSchema.parse(rawInput);
    const em = ctx.container.resolve("em");
    const snapshot = await loadJobHistorySnapshot(em, parsed.id, staffSnapshotScopeFromContext(ctx));
    return snapshot ? { before: snapshot } : {};
  },
  async execute(rawInput, ctx) {
    const parsed = staffTeamMemberJobHistoryUpdateSchema.parse(rawInput);
    const em = ctx.container.resolve("em").fork();
    const scope = commandActorScope(ctx);
    const record = await em.findOne(
      StaffTeamMemberJobHistory,
      applyScopeToWhere({ id: parsed.id }, scope)
    );
    if (!record) {
      enforceRecordGoneIsConflict({
        resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,
        resourceId: parsed.id,
        expected: parsed.updatedAt ?? null,
        request: ctx.request ?? null
      });
      throw new CrudHttpError(404, { error: "Job history entry not found" });
    }
    ensureTenantScope(ctx, record.tenantId);
    ensureOrganizationScope(ctx, record.organizationId);
    await enforceCommandOptimisticLockWithGuards(ctx.container, {
      resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,
      resourceId: record.id,
      current: record.updatedAt ?? null,
      expected: parsed.updatedAt ?? null,
      request: ctx.request ?? null
    });
    if (parsed.entityId !== void 0) {
      const member = await requireTeamMember(em, parsed.entityId, scope, "Team member not found");
      ensureTenantScope(ctx, member.tenantId);
      ensureOrganizationScope(ctx, member.organizationId);
      record.member = member;
    }
    if (parsed.name !== void 0) record.name = parsed.name;
    if (parsed.companyName !== void 0) record.companyName = parsed.companyName ?? null;
    if (parsed.description !== void 0) record.description = parsed.description ?? null;
    if (parsed.startDate !== void 0) record.startDate = parsed.startDate;
    if (parsed.endDate !== void 0) record.endDate = parsed.endDate ?? null;
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "updated",
      entity: record,
      identifiers: {
        id: record.id,
        organizationId: record.organizationId,
        tenantId: record.tenantId
      },
      events: staffTeamMemberJobHistoryCrudEvents,
      indexer: jobHistoryCrudIndexer
    });
    return { jobHistoryId: record.id };
  },
  captureAfter: async (_input, result, ctx) => {
    const em = ctx.container.resolve("em").fork();
    return await loadJobHistorySnapshot(em, result.jobHistoryId, staffSnapshotScopeFromContext(ctx));
  },
  buildLog: async ({ snapshots }) => {
    const { translate } = await resolveTranslations();
    const before = snapshots.before;
    if (!before) return null;
    const afterSnapshot = snapshots.after;
    const changes = afterSnapshot && before ? buildChanges(
      before,
      afterSnapshot,
      ["memberId", "name", "companyName", "description", "startDate", "endDate"]
    ) : {};
    return {
      actionLabel: translate("staff.audit.teamMemberJobHistories.update", "Update job history entry"),
      resourceKind: "staff.team_member_job_history",
      resourceId: before.id,
      parentResourceKind: "staff.teamMember",
      parentResourceId: before.memberId ?? null,
      tenantId: before.tenantId,
      organizationId: before.organizationId,
      snapshotBefore: before,
      snapshotAfter: afterSnapshot ?? null,
      changes,
      payload: {
        undo: {
          before,
          after: afterSnapshot ?? null
        }
      }
    };
  },
  undo: async ({ logEntry, ctx }) => {
    const payload = extractUndoPayload(logEntry);
    const before = payload?.before;
    if (!before) return;
    const em = ctx.container.resolve("em").fork();
    const snapshotScope = staffSnapshotScopeFromSnapshot(before);
    let record = await em.findOne(StaffTeamMemberJobHistory, scopedStaffSnapshotWhere(before.id, snapshotScope));
    const member = await requireTeamMember(
      em,
      before.memberId,
      explicitStaffCommandScope(before.tenantId, before.organizationId),
      "Team member not found"
    );
    if (!record) {
      record = em.create(StaffTeamMemberJobHistory, {
        id: before.id,
        organizationId: before.organizationId,
        tenantId: before.tenantId,
        member,
        name: before.name,
        companyName: before.companyName,
        description: before.description,
        startDate: new Date(before.startDate),
        endDate: before.endDate ? new Date(before.endDate) : null,
        createdAt: /* @__PURE__ */ new Date(),
        updatedAt: /* @__PURE__ */ new Date()
      });
      em.persist(record);
    } else {
      record.member = member;
      record.name = before.name;
      record.companyName = before.companyName;
      record.description = before.description;
      record.startDate = new Date(before.startDate);
      record.endDate = before.endDate ? new Date(before.endDate) : null;
    }
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudUndoSideEffects({
      dataEngine: de,
      action: "updated",
      entity: record,
      identifiers: {
        id: record.id,
        organizationId: record.organizationId,
        tenantId: record.tenantId
      },
      events: staffTeamMemberJobHistoryCrudEvents,
      indexer: jobHistoryCrudIndexer
    });
  }
};
const deleteJobHistoryCommand = {
  id: "staff.team-member-job-histories.delete",
  async prepare(input, ctx) {
    const id = requireId(input, "Job history id required");
    const em = ctx.container.resolve("em");
    const snapshot = await loadJobHistorySnapshot(em, id, staffSnapshotScopeFromContext(ctx));
    return snapshot ? { before: snapshot } : {};
  },
  async execute(input, ctx) {
    const id = requireId(input, "Job history id required");
    const expectedUpdatedAt = typeof input.updatedAt === "string" ? input.updatedAt : void 0;
    const em = ctx.container.resolve("em").fork();
    const scope = commandActorScope(ctx);
    const record = await em.findOne(
      StaffTeamMemberJobHistory,
      applyScopeToWhere({ id }, scope)
    );
    if (!record) {
      enforceRecordGoneIsConflict({
        resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,
        resourceId: id,
        expected: expectedUpdatedAt ?? null,
        request: ctx.request ?? null
      });
      throw new CrudHttpError(404, { error: "Job history entry not found" });
    }
    ensureTenantScope(ctx, record.tenantId);
    ensureOrganizationScope(ctx, record.organizationId);
    await enforceCommandOptimisticLockWithGuards(ctx.container, {
      resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,
      resourceId: record.id,
      current: record.updatedAt ?? null,
      expected: expectedUpdatedAt ?? null,
      request: ctx.request ?? null
    });
    em.remove(record);
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "deleted",
      entity: record,
      identifiers: {
        id: record.id,
        organizationId: record.organizationId,
        tenantId: record.tenantId
      },
      events: staffTeamMemberJobHistoryCrudEvents,
      indexer: jobHistoryCrudIndexer
    });
    return { jobHistoryId: record.id };
  },
  buildLog: async ({ snapshots }) => {
    const before = snapshots.before;
    if (!before) return null;
    const { translate } = await resolveTranslations();
    return {
      actionLabel: translate("staff.audit.teamMemberJobHistories.delete", "Delete job history entry"),
      resourceKind: "staff.team_member_job_history",
      resourceId: before.id,
      parentResourceKind: "staff.teamMember",
      parentResourceId: before.memberId ?? null,
      tenantId: before.tenantId,
      organizationId: before.organizationId,
      snapshotBefore: before,
      payload: {
        undo: {
          before
        }
      }
    };
  },
  undo: async ({ logEntry, ctx }) => {
    const payload = extractUndoPayload(logEntry);
    const before = payload?.before;
    if (!before) return;
    const em = ctx.container.resolve("em").fork();
    const snapshotScope = staffSnapshotScopeFromSnapshot(before);
    const member = await requireTeamMember(
      em,
      before.memberId,
      explicitStaffCommandScope(before.tenantId, before.organizationId),
      "Team member not found"
    );
    let record = await em.findOne(StaffTeamMemberJobHistory, scopedStaffSnapshotWhere(before.id, snapshotScope));
    if (!record) {
      record = em.create(StaffTeamMemberJobHistory, {
        id: before.id,
        organizationId: before.organizationId,
        tenantId: before.tenantId,
        member,
        name: before.name,
        companyName: before.companyName,
        description: before.description,
        startDate: new Date(before.startDate),
        endDate: before.endDate ? new Date(before.endDate) : null,
        createdAt: /* @__PURE__ */ new Date(),
        updatedAt: /* @__PURE__ */ new Date()
      });
      em.persist(record);
    } else {
      record.member = member;
      record.name = before.name;
      record.companyName = before.companyName;
      record.description = before.description;
      record.startDate = new Date(before.startDate);
      record.endDate = before.endDate ? new Date(before.endDate) : null;
    }
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudUndoSideEffects({
      dataEngine: de,
      action: "created",
      entity: record,
      identifiers: {
        id: record.id,
        organizationId: record.organizationId,
        tenantId: record.tenantId
      },
      events: staffTeamMemberJobHistoryCrudEvents,
      indexer: jobHistoryCrudIndexer
    });
  }
};
registerCommand(createJobHistoryCommand);
registerCommand(updateJobHistoryCommand);
registerCommand(deleteJobHistoryCommand);
//# sourceMappingURL=job-histories.js.map
