import { registerCommand } from "@open-mercato/shared/lib/commands";
import { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges, requireId, 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 { StaffTeamMemberComment } from "../data/entities.js";
import {
  staffTeamMemberCommentCreateSchema,
  staffTeamMemberCommentUpdateSchema
} from "../data/validators.js";
import { staffTeamMemberCommentCrudEvents } from "../lib/crud.js";
import {
  applyScopeToWhere,
  commandActorScope,
  commandInputScope,
  ensureOrganizationScope,
  ensureTenantScope,
  explicitStaffCommandScope,
  extractUndoPayload,
  requireTeamMember,
  scopedStaffSnapshotWhere,
  staffSnapshotScopeFromContext,
  staffSnapshotScopeFromSnapshot
} from "./shared.js";
import { makeCreateRedo } from "@open-mercato/shared/lib/commands/redo";
import { E } from "../../../generated/entities.ids.generated.js";
const commentCrudIndexer = {
  entityType: E.staff.staff_team_member_comment
};
async function loadCommentSnapshot(em, id, scope) {
  const comment = await em.findOne(StaffTeamMemberComment, scopedStaffSnapshotWhere(id, scope));
  if (!comment) return null;
  return {
    id: comment.id,
    organizationId: comment.organizationId,
    tenantId: comment.tenantId,
    memberId: typeof comment.member === "string" ? comment.member : comment.member.id,
    body: comment.body,
    authorUserId: comment.authorUserId ?? null,
    appearanceIcon: comment.appearanceIcon ?? null,
    appearanceColor: comment.appearanceColor ?? null
  };
}
const createCommentCommand = {
  id: "staff.team-member-comments.create",
  async execute(rawInput, ctx) {
    const parsed = staffTeamMemberCommentCreateSchema.parse(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 comment = em.create(StaffTeamMemberComment, {
      organizationId: parsed.organizationId,
      tenantId: parsed.tenantId,
      member,
      body: parsed.body,
      authorUserId: normalizedAuthor,
      appearanceIcon: parsed.appearanceIcon ?? null,
      appearanceColor: parsed.appearanceColor ?? null,
      createdAt: /* @__PURE__ */ new Date(),
      updatedAt: /* @__PURE__ */ new Date()
    });
    em.persist(comment);
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "created",
      entity: comment,
      identifiers: {
        id: comment.id,
        organizationId: comment.organizationId,
        tenantId: comment.tenantId
      },
      events: staffTeamMemberCommentCrudEvents,
      indexer: commentCrudIndexer
    });
    return { commentId: comment.id, authorUserId: comment.authorUserId ?? null };
  },
  captureAfter: async (_input, result, ctx) => {
    const em = ctx.container.resolve("em").fork();
    return await loadCommentSnapshot(em, result.commentId, staffSnapshotScopeFromContext(ctx));
  },
  buildLog: async ({ result, snapshots }) => {
    const { translate } = await resolveTranslations();
    const snapshot = snapshots.after;
    return {
      actionLabel: translate("staff.audit.teamMemberComments.create", "Create note"),
      resourceKind: "staff.team_member_comment",
      resourceId: result.commentId,
      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;
    const commentId = after?.id ?? logEntry?.resourceId ?? null;
    if (!commentId) return;
    const em = ctx.container.resolve("em").fork();
    const existing = await em.findOne(StaffTeamMemberComment, scopedStaffSnapshotWhere(commentId, staffSnapshotScopeFromSnapshot(after)));
    if (existing) {
      em.remove(existing);
      await em.flush();
    }
  },
  redo: makeCreateRedo({
    entityClass: StaffTeamMemberComment,
    events: staffTeamMemberCommentCrudEvents,
    indexer: commentCrudIndexer,
    seedFromSnapshot: (snapshot) => ({
      id: snapshot.id,
      organizationId: snapshot.organizationId,
      tenantId: snapshot.tenantId,
      body: snapshot.body,
      authorUserId: snapshot.authorUserId,
      appearanceIcon: snapshot.appearanceIcon,
      appearanceColor: snapshot.appearanceColor
    }),
    beforeRestore: async ({ em, snapshot }) => {
      const member = await requireTeamMember(
        em,
        snapshot.memberId,
        explicitStaffCommandScope(snapshot.tenantId, snapshot.organizationId),
        "Team member not found"
      );
      return { member };
    },
    buildResult: (entity) => ({ commentId: entity.id, authorUserId: entity.authorUserId ?? null })
  })
};
const updateCommentCommand = {
  id: "staff.team-member-comments.update",
  async prepare(rawInput, ctx) {
    const parsed = staffTeamMemberCommentUpdateSchema.parse(rawInput);
    const em = ctx.container.resolve("em");
    const snapshot = await loadCommentSnapshot(em, parsed.id, staffSnapshotScopeFromContext(ctx));
    return snapshot ? { before: snapshot } : {};
  },
  async execute(rawInput, ctx) {
    const parsed = staffTeamMemberCommentUpdateSchema.parse(rawInput);
    const em = ctx.container.resolve("em").fork();
    const scope = commandActorScope(ctx);
    const comment = await em.findOne(
      StaffTeamMemberComment,
      applyScopeToWhere({ id: parsed.id }, scope)
    );
    if (!comment) throw new CrudHttpError(404, { error: "Comment not found" });
    ensureTenantScope(ctx, comment.tenantId);
    ensureOrganizationScope(ctx, comment.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);
      comment.member = member;
    }
    if (parsed.body !== void 0) comment.body = parsed.body;
    if (parsed.authorUserId !== void 0) comment.authorUserId = parsed.authorUserId ?? null;
    if (parsed.appearanceIcon !== void 0) comment.appearanceIcon = parsed.appearanceIcon ?? null;
    if (parsed.appearanceColor !== void 0) comment.appearanceColor = parsed.appearanceColor ?? null;
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "updated",
      entity: comment,
      identifiers: {
        id: comment.id,
        organizationId: comment.organizationId,
        tenantId: comment.tenantId
      },
      events: staffTeamMemberCommentCrudEvents,
      indexer: commentCrudIndexer
    });
    return { commentId: comment.id };
  },
  captureAfter: async (_input, result, ctx) => {
    const em = ctx.container.resolve("em").fork();
    return await loadCommentSnapshot(em, result.commentId, 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", "body", "authorUserId", "appearanceIcon", "appearanceColor"]
    ) : {};
    return {
      actionLabel: translate("staff.audit.teamMemberComments.update", "Update note"),
      resourceKind: "staff.team_member_comment",
      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 comment = await em.findOne(StaffTeamMemberComment, scopedStaffSnapshotWhere(before.id, snapshotScope));
    const member = await requireTeamMember(
      em,
      before.memberId,
      explicitStaffCommandScope(before.tenantId, before.organizationId),
      "Team member not found"
    );
    if (!comment) {
      comment = em.create(StaffTeamMemberComment, {
        id: before.id,
        organizationId: before.organizationId,
        tenantId: before.tenantId,
        member,
        body: before.body,
        authorUserId: before.authorUserId,
        appearanceIcon: before.appearanceIcon,
        appearanceColor: before.appearanceColor,
        createdAt: /* @__PURE__ */ new Date(),
        updatedAt: /* @__PURE__ */ new Date()
      });
      em.persist(comment);
    } else {
      comment.member = member;
      comment.body = before.body;
      comment.authorUserId = before.authorUserId;
      comment.appearanceIcon = before.appearanceIcon;
      comment.appearanceColor = before.appearanceColor;
    }
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudUndoSideEffects({
      dataEngine: de,
      action: "updated",
      entity: comment,
      identifiers: {
        id: comment.id,
        organizationId: comment.organizationId,
        tenantId: comment.tenantId
      },
      events: staffTeamMemberCommentCrudEvents,
      indexer: commentCrudIndexer
    });
  }
};
const deleteCommentCommand = {
  id: "staff.team-member-comments.delete",
  async prepare(input, ctx) {
    const id = requireId(input, "Comment id required");
    const em = ctx.container.resolve("em");
    const snapshot = await loadCommentSnapshot(em, id, staffSnapshotScopeFromContext(ctx));
    return snapshot ? { before: snapshot } : {};
  },
  async execute(input, ctx) {
    const id = requireId(input, "Comment id required");
    const em = ctx.container.resolve("em").fork();
    const scope = commandActorScope(ctx);
    const comment = await em.findOne(
      StaffTeamMemberComment,
      applyScopeToWhere({ id }, scope)
    );
    if (!comment) throw new CrudHttpError(404, { error: "Comment not found" });
    ensureTenantScope(ctx, comment.tenantId);
    ensureOrganizationScope(ctx, comment.organizationId);
    em.remove(comment);
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine: de,
      action: "deleted",
      entity: comment,
      identifiers: {
        id: comment.id,
        organizationId: comment.organizationId,
        tenantId: comment.tenantId
      },
      events: staffTeamMemberCommentCrudEvents,
      indexer: commentCrudIndexer
    });
    return { commentId: comment.id };
  },
  buildLog: async ({ snapshots }) => {
    const before = snapshots.before;
    if (!before) return null;
    const { translate } = await resolveTranslations();
    return {
      actionLabel: translate("staff.audit.teamMemberComments.delete", "Delete note"),
      resourceKind: "staff.team_member_comment",
      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 comment = await em.findOne(StaffTeamMemberComment, scopedStaffSnapshotWhere(before.id, snapshotScope));
    if (!comment) {
      comment = em.create(StaffTeamMemberComment, {
        id: before.id,
        organizationId: before.organizationId,
        tenantId: before.tenantId,
        member,
        body: before.body,
        authorUserId: before.authorUserId,
        appearanceIcon: before.appearanceIcon,
        appearanceColor: before.appearanceColor,
        createdAt: /* @__PURE__ */ new Date(),
        updatedAt: /* @__PURE__ */ new Date()
      });
      em.persist(comment);
    } else {
      comment.member = member;
      comment.body = before.body;
      comment.authorUserId = before.authorUserId;
      comment.appearanceIcon = before.appearanceIcon;
      comment.appearanceColor = before.appearanceColor;
    }
    await em.flush();
    const de = ctx.container.resolve("dataEngine");
    await emitCrudUndoSideEffects({
      dataEngine: de,
      action: "created",
      entity: comment,
      identifiers: {
        id: comment.id,
        organizationId: comment.organizationId,
        tenantId: comment.tenantId
      },
      events: staffTeamMemberCommentCrudEvents,
      indexer: commentCrudIndexer
    });
  }
};
registerCommand(createCommentCommand);
registerCommand(updateCommentCommand);
registerCommand(deleteCommentCommand);
//# sourceMappingURL=comments.js.map
