import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import {
  CommunicationChannel,
  ExternalConversation,
  MessageChannelLink
} from "../data/entities.js";
class ChannelMutationBlockedError extends Error {
  constructor(reason, channelId, message) {
    super(message);
    this.name = "ChannelMutationBlockedError";
    this.reason = reason;
    this.channelId = channelId;
    this.errors = { channelId: message };
  }
}
async function guardChannelDelete(em, input) {
  const channel = await findOneWithDecryption(
    em,
    CommunicationChannel,
    {
      id: input.channelId,
      tenantId: input.scope.tenantId,
      organizationId: input.scope.organizationId ?? null,
      deletedAt: null
    },
    void 0,
    input.scope
  );
  if (!channel) {
    throw new ChannelMutationBlockedError(
      "channel_not_found",
      input.channelId,
      "Channel not found in this tenant scope."
    );
  }
  if (input.force) return;
  const inboundCount = await countInboundLinksForChannel(em, input.channelId, input.scope);
  if (inboundCount > 0) {
    throw new ChannelMutationBlockedError(
      "channel_has_inbound_history",
      input.channelId,
      `Channel has ${inboundCount} inbound message${inboundCount === 1 ? "" : "s"} in history. Pass force=true to delete anyway.`
    );
  }
}
async function guardOutboundCreate(em, input) {
  const channel = await findOneWithDecryption(
    em,
    CommunicationChannel,
    {
      id: input.channelId,
      tenantId: input.scope.tenantId,
      organizationId: input.scope.organizationId ?? null,
      deletedAt: null
    },
    void 0,
    input.scope
  );
  if (!channel) {
    throw new ChannelMutationBlockedError(
      "channel_not_found",
      input.channelId,
      "Channel not found in this tenant scope."
    );
  }
  if (channel.status === "requires_reauth") {
    throw new ChannelMutationBlockedError(
      "channel_requires_reauth",
      input.channelId,
      "This channel needs reconnection before it can send messages. Open Profile -> Communication channels to reconnect."
    );
  }
  if (channel.status === "disconnected") {
    throw new ChannelMutationBlockedError(
      "channel_disconnected",
      input.channelId,
      "This channel is disconnected and cannot send messages."
    );
  }
}
async function countInboundLinksForChannel(em, channelId, scope) {
  const conversations = await findWithDecryption(
    em,
    ExternalConversation,
    {
      channelId,
      tenantId: scope.tenantId,
      organizationId: scope.organizationId ?? null
    },
    { fields: ["id"] },
    scope
  );
  if (conversations.length === 0) return 0;
  const conversationIds = conversations.map((c) => c.id);
  const count = await em.count(
    MessageChannelLink,
    {
      externalConversationId: { $in: conversationIds },
      direction: "inbound",
      tenantId: scope.tenantId,
      organizationId: scope.organizationId ?? null
    }
  );
  return typeof count === "number" ? count : 0;
}
const countUnreadInboundForChannel = countInboundLinksForChannel;
export {
  ChannelMutationBlockedError,
  countInboundLinksForChannel,
  countUnreadInboundForChannel,
  guardChannelDelete,
  guardOutboundCreate
};
//# sourceMappingURL=mutation-guards.js.map
