import { registerCommand } from "@open-mercato/shared/lib/commands";
import {
  emitCrudSideEffects,
  emitCrudUndoSideEffects,
  buildChanges,
  requireId,
  parseWithCustomFields,
  setCustomFieldsIfAny,
  normalizeAuthorUserId
} from "@open-mercato/shared/lib/commands/helpers";
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
import { StaffTeamMemberActivity } from "../data/entities.js";
import {
  staffTeamMemberActivityCreateSchema,
  staffTeamMemberActivityUpdateSchema
} from "../data/validators.js";
import { staffTeamMemberActivityCrudEvents } from "../lib/crud.js";
import {
  applyScopeToWhere,
  commandActorScope,
  commandInputScope,
  ensureOrganizationScope,
  ensureTenantScope,
  explicitStaffCommandScope,
  extractUndoPayload,
  requireTeamMember,
  scopedStaffSnapshotWhere,
  staffSnapshotScopeFromContext,
  staffSnapshotScopeFromSnapshot
} from "./shared.js";
import { resolveRedoSnapshot } from "@open-mercato/shared/lib/commands/redo";
import { E } from "../../../generated/entities.ids.generated.js";
import {
  loadCustomFieldSnapshot,
  diffCustomFieldChanges,
  buildCustomFieldResetMap
} from "@open-mercato/shared/lib/commands/customFieldSnapshots";
const activityCrudIndexer = {
  entityType: E.staff.staff_team_member_activity
};
async function loadActivitySnapshot(em, id, scope) {
  const activity = await em.findOne(StaffTeamMemberActivity, scopedStaffSnapshotWhere(id, scope));
  if (!activity) return null;
  const custom = await loadCustomFieldSnapshot(em, {
    entityId: E.staff.staff_team_member_activity,
    recordId: activity.id,
    tenantId: activity.tenantId,
    organizationId: activity.organizationId
  });
  return {
    activity: {
      id: activity.id,
      organizationId: activity.organizationId,
      tenantId: activity.tenantId,
      memberId: typeof activity.member === "string" ? activity.member : activity.member.id,
      activityType: activity.activityType,
      subject: activity.subject ?? null,
      body: activity.body ?? null,
      occurredAt: activity.occurredAt ?? null,
      authorUserId: activity.authorUserId ?? null,
      appearanceIcon: activity.appearanceIcon ?? null,
      appearanceColor: activity.appearanceColor ?? null
    },
    custom
  };
}
async function setActivityCustomFields(ctx, activityId, organizationId, tenantId, values) {
  if (!values || !Object.keys(values).length) return;
  const de = ctx.container.resolve("dataEngine");
  await setCustomFieldsIfAny({
    dataEngine: de,
    entityId: E.staff.staff_team_member_activity,
    recordId: activityId,
    organizationId,
    tenantId,
    values,
    notify: false
  });
}
const createActivityCommand = {
  id: "staff.team-member-activities.create",
  async execute(rawInput, ctx) {
    const { parsed, custom } = parseWithCustomFields(staffTeamMemberActivityCreateSchema, rawInput);
    ensureTenantScope(ctx, parsed.tenantId);
    ensureOrganizationScope(ctx, parsed.organizationId);
    const scope = commandInputScope(ctx, parsed.tenantId, parsed.organizationId);
    const normalizedAuthor = normalizeAuthorUserId(parsed.authorUserId, ctx.auth);
    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 activity = em.create(StaffTeamMemberActivity, {
      organizationId: parsed.organizationId,
      tenantId: parsed.tenantId,
      member,
      activityType: parsed.activityType,
      subject: parsed.subject ?? null,
      body: parsed.body ?? null,
      occurredAt: parsed.occurredAt ?? null,
      authorUserId: normalizedAuthor,
      appearanceIcon: parsed.appearanceIcon ?? null,
      appearanceColor: parsed.appearanceColor ?? null,
      createdAt: /* @__PURE__ */ new Date(),
      updatedAt: /* @__PURE__ */ new Date()
    });
    em.persist(activity);
    await em.flush();
    await setActivityCustomFields(ctx, activity.id, parsed.organizationId, parsed.tenantId, custom);
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "created",
      entity: activity,
      identifiers: {
        id: activity.id,
        organizationId: activity.organizationId,
        tenantId: activity.tenantId
      },
      events: staffTeamMemberActivityCrudEvents,
      indexer: activityCrudIndexer
    });
    return { activityId: activity.id, authorUserId: activity.authorUserId ?? null };
  },
  captureAfter: async (_input, result, ctx) => {
    const em = ctx.container.resolve("em").fork();
    return await loadActivitySnapshot(em, result.activityId, staffSnapshotScopeFromContext(ctx));
  },
  buildLog: async ({ result, snapshots }) => {
    const { translate } = await resolveTranslations();
    const snapshot = snapshots.after;
    return {
      actionLabel: translate("staff.audit.teamMemberActivities.create", "Create activity"),
      resourceKind: "staff.team_member_activity",
      resourceId: result.activityId,
      parentResourceKind: "staff.teamMember",
      parentResourceId: snapshot?.activity?.memberId ?? null,
      tenantId: snapshot?.activity.tenantId ?? null,
      organizationId: snapshot?.activity.organizationId ?? null,
      snapshotAfter: snapshot ?? null,
      payload: {
        undo: {
          after: snapshot ?? null
        }
      }
    };
  },
  undo: async ({ logEntry, ctx }) => {
    const payload = extractUndoPayload(logEntry);
    const after = payload?.after;
    const activityId = after?.activity.id ?? logEntry?.resourceId ?? null;
    if (!activityId) return;
    const em = ctx.container.resolve("em").fork();
    const existing = await em.findOne(
      StaffTeamMemberActivity,
      scopedStaffSnapshotWhere(activityId, staffSnapshotScopeFromSnapshot(after?.activity))
    );
    if (existing) {
      em.remove(existing);
      await em.flush();
    }
  },
  redo: async ({ logEntry, ctx }) => {
    const after = resolveRedoSnapshot(logEntry);
    if (!after) {
      throw new CrudHttpError(400, { error: "[internal] redo snapshot unavailable for activity create" });
    }
    const em = ctx.container.resolve("em").fork();
    const snapshotScope = staffSnapshotScopeFromSnapshot(after.activity);
    const member = await requireTeamMember(
      em,
      after.activity.memberId,
      explicitStaffCommandScope(after.activity.tenantId, after.activity.organizationId),
      "Team member not found"
    );
    let activity = await em.findOne(StaffTeamMemberActivity, scopedStaffSnapshotWhere(after.activity.id, snapshotScope));
    if (!activity) {
      activity = em.create(StaffTeamMemberActivity, {
        id: after.activity.id,
        organizationId: after.activity.organizationId,
        tenantId: after.activity.tenantId,
        member,
        activityType: after.activity.activityType,
        subject: after.activity.subject,
        body: after.activity.body,
        occurredAt: after.activity.occurredAt ?? null,
        authorUserId: after.activity.authorUserId,
        appearanceIcon: after.activity.appearanceIcon,
        appearanceColor: after.activity.appearanceColor,
        createdAt: /* @__PURE__ */ new Date(),
        updatedAt: /* @__PURE__ */ new Date()
      });
      em.persist(activity);
    } else {
      activity.member = member;
      activity.activityType = after.activity.activityType;
      activity.subject = after.activity.subject;
      activity.body = after.activity.body;
      activity.occurredAt = after.activity.occurredAt ?? null;
      activity.authorUserId = after.activity.authorUserId;
      activity.appearanceIcon = after.activity.appearanceIcon;
      activity.appearanceColor = after.activity.appearanceColor;
    }
    await em.flush();
    await setActivityCustomFields(ctx, activity.id, activity.organizationId, activity.tenantId, after.custom ?? {});
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "created",
      entity: activity,
      identifiers: {
        id: activity.id,
        organizationId: activity.organizationId,
        tenantId: activity.tenantId
      },
      events: staffTeamMemberActivityCrudEvents,
      indexer: activityCrudIndexer
    });
    return { activityId: activity.id, authorUserId: activity.authorUserId ?? null };
  }
};
const updateActivityCommand = {
  id: "staff.team-member-activities.update",
  async prepare(rawInput, ctx) {
    const parsed = staffTeamMemberActivityUpdateSchema.parse(rawInput);
    const em = ctx.container.resolve("em");
    const snapshot = await loadActivitySnapshot(em, parsed.id, staffSnapshotScopeFromContext(ctx));
    return snapshot ? { before: snapshot } : {};
  },
  async execute(rawInput, ctx) {
    const { parsed, custom } = parseWithCustomFields(staffTeamMemberActivityUpdateSchema, rawInput);
    const em = ctx.container.resolve("em").fork();
    const scope = commandActorScope(ctx);
    const activity = await em.findOne(
      StaffTeamMemberActivity,
      applyScopeToWhere({ id: parsed.id }, scope)
    );
    if (!activity) throw new CrudHttpError(404, { error: "Activity not found" });
    ensureTenantScope(ctx, activity.tenantId);
    ensureOrganizationScope(ctx, activity.organizationId);
    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);
      activity.member = member;
    }
    if (parsed.activityType !== void 0) activity.activityType = parsed.activityType;
    if (parsed.subject !== void 0) activity.subject = parsed.subject ?? null;
    if (parsed.body !== void 0) activity.body = parsed.body ?? null;
    if (parsed.occurredAt !== void 0) activity.occurredAt = parsed.occurredAt ?? null;
    if (parsed.authorUserId !== void 0) activity.authorUserId = parsed.authorUserId ?? null;
    if (parsed.appearanceIcon !== void 0) activity.appearanceIcon = parsed.appearanceIcon ?? null;
    if (parsed.appearanceColor !== void 0) activity.appearanceColor = parsed.appearanceColor ?? null;
    await em.flush();
    await setActivityCustomFields(ctx, activity.id, activity.organizationId, activity.tenantId, custom);
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "updated",
      entity: activity,
      identifiers: {
        id: activity.id,
        organizationId: activity.organizationId,
        tenantId: activity.tenantId
      },
      events: staffTeamMemberActivityCrudEvents,
      indexer: activityCrudIndexer
    });
    return { activityId: activity.id };
  },
  captureAfter: async (_input, result, ctx) => {
    const em = ctx.container.resolve("em").fork();
    return await loadActivitySnapshot(em, result.activityId, staffSnapshotScopeFromContext(ctx));
  },
  buildLog: async ({ snapshots }) => {
    const { translate } = await resolveTranslations();
    const before = snapshots.before;
    if (!before) return null;
    const afterSnapshot = snapshots.after;
    const changeKeys = [
      "memberId",
      "activityType",
      "subject",
      "body",
      "occurredAt",
      "authorUserId",
      "appearanceIcon",
      "appearanceColor"
    ];
    const changes = afterSnapshot && before ? buildChanges(
      before.activity,
      afterSnapshot.activity,
      changeKeys
    ) : {};
    const customChanges = diffCustomFieldChanges(before.custom, afterSnapshot?.custom);
    if (Object.keys(customChanges).length) changes.custom = customChanges;
    return {
      actionLabel: translate("staff.audit.teamMemberActivities.update", "Update activity"),
      resourceKind: "staff.team_member_activity",
      resourceId: before.activity.id,
      parentResourceKind: "staff.teamMember",
      parentResourceId: before.activity.memberId ?? null,
      tenantId: before.activity.tenantId,
      organizationId: before.activity.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.activity);
    let activity = await em.findOne(StaffTeamMemberActivity, scopedStaffSnapshotWhere(before.activity.id, snapshotScope));
    const member = await requireTeamMember(
      em,
      before.activity.memberId,
      explicitStaffCommandScope(before.activity.tenantId, before.activity.organizationId),
      "Team member not found"
    );
    if (!activity) {
      activity = em.create(StaffTeamMemberActivity, {
        id: before.activity.id,
        organizationId: before.activity.organizationId,
        tenantId: before.activity.tenantId,
        member,
        activityType: before.activity.activityType,
        subject: before.activity.subject,
        body: before.activity.body,
        occurredAt: before.activity.occurredAt ?? null,
        authorUserId: before.activity.authorUserId,
        appearanceIcon: before.activity.appearanceIcon,
        appearanceColor: before.activity.appearanceColor,
        createdAt: /* @__PURE__ */ new Date(),
        updatedAt: /* @__PURE__ */ new Date()
      });
      em.persist(activity);
    } else {
      activity.member = member;
      activity.activityType = before.activity.activityType;
      activity.subject = before.activity.subject;
      activity.body = before.activity.body;
      activity.occurredAt = before.activity.occurredAt ?? null;
      activity.authorUserId = before.activity.authorUserId;
      activity.appearanceIcon = before.activity.appearanceIcon;
      activity.appearanceColor = before.activity.appearanceColor;
    }
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudUndoSideEffects({
      dataEngine: de,
      action: "updated",
      entity: activity,
      identifiers: {
        id: activity.id,
        organizationId: activity.organizationId,
        tenantId: activity.tenantId
      },
      events: staffTeamMemberActivityCrudEvents,
      indexer: activityCrudIndexer
    });
    const resetValues = buildCustomFieldResetMap(before.custom, payload?.after?.custom);
    if (Object.keys(resetValues).length) {
      await setCustomFieldsIfAny({
        dataEngine: de,
        entityId: E.staff.staff_team_member_activity,
        recordId: activity.id,
        organizationId: activity.organizationId,
        tenantId: activity.tenantId,
        values: resetValues,
        notify: false
      });
    }
  }
};
const deleteActivityCommand = {
  id: "staff.team-member-activities.delete",
  async prepare(input, ctx) {
    const id = requireId(input, "Activity id required");
    const em = ctx.container.resolve("em");
    const snapshot = await loadActivitySnapshot(em, id, staffSnapshotScopeFromContext(ctx));
    return snapshot ? { before: snapshot } : {};
  },
  async execute(input, ctx) {
    const id = requireId(input, "Activity id required");
    const em = ctx.container.resolve("em").fork();
    const scope = commandActorScope(ctx);
    const activity = await em.findOne(
      StaffTeamMemberActivity,
      applyScopeToWhere({ id }, scope)
    );
    if (!activity) throw new CrudHttpError(404, { error: "Activity not found" });
    ensureTenantScope(ctx, activity.tenantId);
    ensureOrganizationScope(ctx, activity.organizationId);
    em.remove(activity);
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "deleted",
      entity: activity,
      identifiers: {
        id: activity.id,
        organizationId: activity.organizationId,
        tenantId: activity.tenantId
      },
      events: staffTeamMemberActivityCrudEvents,
      indexer: activityCrudIndexer
    });
    return { activityId: activity.id };
  },
  buildLog: async ({ snapshots }) => {
    const before = snapshots.before;
    if (!before) return null;
    const { translate } = await resolveTranslations();
    return {
      actionLabel: translate("staff.audit.teamMemberActivities.delete", "Delete activity"),
      resourceKind: "staff.team_member_activity",
      resourceId: before.activity.id,
      parentResourceKind: "staff.teamMember",
      parentResourceId: before.activity.memberId ?? null,
      tenantId: before.activity.tenantId,
      organizationId: before.activity.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.activity);
    const member = await requireTeamMember(
      em,
      before.activity.memberId,
      explicitStaffCommandScope(before.activity.tenantId, before.activity.organizationId),
      "Team member not found"
    );
    let activity = await em.findOne(StaffTeamMemberActivity, scopedStaffSnapshotWhere(before.activity.id, snapshotScope));
    if (!activity) {
      activity = em.create(StaffTeamMemberActivity, {
        id: before.activity.id,
        organizationId: before.activity.organizationId,
        tenantId: before.activity.tenantId,
        member,
        activityType: before.activity.activityType,
        subject: before.activity.subject,
        body: before.activity.body,
        occurredAt: before.activity.occurredAt ?? null,
        authorUserId: before.activity.authorUserId,
        appearanceIcon: before.activity.appearanceIcon,
        appearanceColor: before.activity.appearanceColor,
        createdAt: /* @__PURE__ */ new Date(),
        updatedAt: /* @__PURE__ */ new Date()
      });
      em.persist(activity);
    } else {
      activity.member = member;
      activity.activityType = before.activity.activityType;
      activity.subject = before.activity.subject;
      activity.body = before.activity.body;
      activity.occurredAt = before.activity.occurredAt ?? null;
      activity.authorUserId = before.activity.authorUserId;
      activity.appearanceIcon = before.activity.appearanceIcon;
      activity.appearanceColor = before.activity.appearanceColor;
    }
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudUndoSideEffects({
      dataEngine: de,
      action: "created",
      entity: activity,
      identifiers: {
        id: activity.id,
        organizationId: activity.organizationId,
        tenantId: activity.tenantId
      },
      events: staffTeamMemberActivityCrudEvents,
      indexer: activityCrudIndexer
    });
    const resetValues = buildCustomFieldResetMap(before.custom, void 0);
    if (Object.keys(resetValues).length) {
      await setCustomFieldsIfAny({
        dataEngine: de,
        entityId: E.staff.staff_team_member_activity,
        recordId: activity.id,
        organizationId: activity.organizationId,
        tenantId: activity.tenantId,
        values: resetValues,
        notify: false
      });
    }
  }
};
registerCommand(createActivityCommand);
registerCommand(updateActivityCommand);
registerCommand(deleteActivityCommand);
//# sourceMappingURL=activities.js.map
