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 { emitCrudSideEffects, emitCrudUndoSideEffects } from "@open-mercato/shared/lib/commands/helpers";
import { StaffTeamMember } from "../data/entities.js";
import {
  staffTeamMemberTagAssignmentSchema
} from "../data/validators.js";
import { staffTeamMemberCrudEvents } from "../lib/crud.js";
import {
  applyScopeToWhere,
  commandInputScope,
  ensureOrganizationScope,
  ensureTenantScope,
  explicitStaffCommandScope,
  extractUndoPayload,
  scopeForDecryption,
  scopedStaffSnapshotWhere,
  staffSnapshotDecryptionScope,
  staffSnapshotScopeFromSnapshot
} from "./shared.js";
function normalizeTagList(values) {
  const set = /* @__PURE__ */ new Set();
  values.forEach((value) => {
    if (typeof value !== "string") return;
    const trimmed = value.trim();
    if (trimmed.length > 0) set.add(trimmed);
  });
  return Array.from(set);
}
const assignTeamMemberTagCommand = {
  id: "staff.team-members.tags.assign",
  async execute(rawInput, ctx) {
    const parsed = staffTeamMemberTagAssignmentSchema.parse(rawInput);
    const tagValue = parsed.tag.trim();
    ensureTenantScope(ctx, parsed.tenantId);
    ensureOrganizationScope(ctx, parsed.organizationId);
    const em = ctx.container.resolve("em").fork();
    const scope = commandInputScope(ctx, parsed.tenantId, parsed.organizationId);
    const member = await findOneWithDecryption(
      em,
      StaffTeamMember,
      applyScopeToWhere({ id: parsed.memberId, deletedAt: null }, scope),
      void 0,
      scopeForDecryption(scope)
    );
    if (!member) throw new CrudHttpError(404, { error: "Team member not found." });
    ensureTenantScope(ctx, member.tenantId);
    ensureOrganizationScope(ctx, member.organizationId);
    const currentTags = normalizeTagList(Array.isArray(member.tags) ? member.tags : []);
    if (currentTags.includes(tagValue)) {
      throw new CrudHttpError(409, { error: "Tag already assigned." });
    }
    member.tags = normalizeTagList([...currentTags, tagValue]);
    member.updatedAt = /* @__PURE__ */ new Date();
    await em.flush();
    const dataEngine = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine,
      action: "updated",
      entity: member,
      identifiers: {
        id: member.id,
        tenantId: member.tenantId,
        organizationId: member.organizationId
      },
      events: staffTeamMemberCrudEvents
    });
    return { memberId: member.id };
  },
  buildLog: async ({ input }) => {
    const { translate } = await resolveTranslations();
    const parsed = staffTeamMemberTagAssignmentSchema.parse(input);
    return {
      actionLabel: translate("staff.audit.teamMembers.tags.assign", "Assign team member tag"),
      resourceKind: "staff.teamMemberTagAssignment",
      resourceId: parsed.memberId,
      parentResourceKind: "staff.teamMember",
      parentResourceId: parsed.memberId,
      tenantId: parsed.tenantId,
      organizationId: parsed.organizationId,
      payload: {
        undo: {
          before: {
            tag: parsed.tag.trim(),
            memberId: parsed.memberId,
            tenantId: parsed.tenantId,
            organizationId: parsed.organizationId
          }
        }
      }
    };
  },
  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 findOneWithDecryption(
      em,
      StaffTeamMember,
      scopedStaffSnapshotWhere(before.memberId, snapshotScope),
      void 0,
      staffSnapshotDecryptionScope(snapshotScope)
    );
    if (!member) return;
    const nextTags = normalizeTagList(
      Array.isArray(member.tags) ? member.tags.filter((tag) => tag !== before.tag) : []
    );
    member.tags = nextTags;
    member.updatedAt = /* @__PURE__ */ new Date();
    await em.flush();
    const dataEngine = ctx.container.resolve("dataEngine");
    await emitCrudUndoSideEffects({
      dataEngine,
      action: "updated",
      entity: member,
      identifiers: {
        id: member.id,
        tenantId: member.tenantId,
        organizationId: member.organizationId
      },
      events: staffTeamMemberCrudEvents
    });
  },
  redo: async ({ logEntry, ctx }) => {
    const payload = extractUndoPayload(logEntry);
    const before = payload?.before;
    if (!before) return { memberId: logEntry.resourceId ?? "" };
    const em = ctx.container.resolve("em").fork();
    const scope = explicitStaffCommandScope(before.tenantId, before.organizationId);
    const member = await findOneWithDecryption(
      em,
      StaffTeamMember,
      applyScopeToWhere({ id: before.memberId, deletedAt: null }, scope),
      void 0,
      scopeForDecryption(scope)
    );
    if (!member) throw new CrudHttpError(404, { error: "Team member not found." });
    const currentTags = normalizeTagList(Array.isArray(member.tags) ? member.tags : []);
    if (!currentTags.includes(before.tag)) {
      member.tags = normalizeTagList([...currentTags, before.tag]);
      member.updatedAt = /* @__PURE__ */ new Date();
      await em.flush();
    }
    const dataEngine = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine,
      action: "updated",
      entity: member,
      identifiers: {
        id: member.id,
        tenantId: member.tenantId,
        organizationId: member.organizationId
      },
      events: staffTeamMemberCrudEvents
    });
    return { memberId: member.id };
  }
};
const unassignTeamMemberTagCommand = {
  id: "staff.team-members.tags.unassign",
  async execute(rawInput, ctx) {
    const parsed = staffTeamMemberTagAssignmentSchema.parse(rawInput);
    const tagValue = parsed.tag.trim();
    ensureTenantScope(ctx, parsed.tenantId);
    ensureOrganizationScope(ctx, parsed.organizationId);
    const em = ctx.container.resolve("em").fork();
    const scope = commandInputScope(ctx, parsed.tenantId, parsed.organizationId);
    const member = await findOneWithDecryption(
      em,
      StaffTeamMember,
      applyScopeToWhere({ id: parsed.memberId, deletedAt: null }, scope),
      void 0,
      scopeForDecryption(scope)
    );
    if (!member) throw new CrudHttpError(404, { error: "Team member not found." });
    ensureTenantScope(ctx, member.tenantId);
    ensureOrganizationScope(ctx, member.organizationId);
    const currentTags = normalizeTagList(Array.isArray(member.tags) ? member.tags : []);
    if (!currentTags.includes(tagValue)) {
      throw new CrudHttpError(404, { error: "Tag assignment not found." });
    }
    member.tags = normalizeTagList(currentTags.filter((tag) => tag !== tagValue));
    member.updatedAt = /* @__PURE__ */ new Date();
    await em.flush();
    const dataEngine = ctx.container.resolve("dataEngine");
    await emitCrudSideEffects({
      dataEngine,
      action: "updated",
      entity: member,
      identifiers: {
        id: member.id,
        tenantId: member.tenantId,
        organizationId: member.organizationId
      },
      events: staffTeamMemberCrudEvents
    });
    return { memberId: member.id };
  },
  buildLog: async ({ input }) => {
    const { translate } = await resolveTranslations();
    const parsed = staffTeamMemberTagAssignmentSchema.parse(input);
    return {
      actionLabel: translate("staff.audit.teamMembers.tags.unassign", "Unassign team member tag"),
      resourceKind: "staff.teamMemberTagAssignment",
      resourceId: parsed.memberId,
      parentResourceKind: "staff.teamMember",
      parentResourceId: parsed.memberId,
      tenantId: parsed.tenantId,
      organizationId: parsed.organizationId,
      payload: {
        undo: {
          before: {
            tag: parsed.tag.trim(),
            memberId: parsed.memberId,
            tenantId: parsed.tenantId,
            organizationId: parsed.organizationId
          }
        }
      }
    };
  },
  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 findOneWithDecryption(
      em,
      StaffTeamMember,
      scopedStaffSnapshotWhere(before.memberId, snapshotScope),
      void 0,
      staffSnapshotDecryptionScope(snapshotScope)
    );
    if (!member) return;
    const currentTags = Array.isArray(member.tags) ? member.tags : [];
    if (!currentTags.includes(before.tag)) {
      member.tags = normalizeTagList([...currentTags, before.tag]);
      member.updatedAt = /* @__PURE__ */ new Date();
      await em.flush();
    }
    const dataEngine = ctx.container.resolve("dataEngine");
    await emitCrudUndoSideEffects({
      dataEngine,
      action: "updated",
      entity: member,
      identifiers: {
        id: member.id,
        tenantId: member.tenantId,
        organizationId: member.organizationId
      },
      events: staffTeamMemberCrudEvents
    });
  }
};
registerCommand(assignTeamMemberTagCommand);
registerCommand(unassignTeamMemberTagCommand);
//# sourceMappingURL=tag-assignments.js.map
