import { z } from "zod";
import { registerCommand } from "@open-mercato/shared/lib/commands";
import { createConnectedChannelRow, MailboxAlreadyConnectedError } from "../lib/connect-channel.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("communication_channels").child({ component: "connect-credential-channel" });
const connectCredentialChannelSchema = z.object({
  providerKey: z.string().min(1).max(64),
  displayName: z.string().min(1).max(255),
  /** Provider-specific credential fields — opaque to the hub; the adapter validates. */
  credentials: z.record(z.string(), z.unknown()),
  /** Optional polling interval (seconds) — set when adapter is polling-based. */
  pollIntervalSeconds: z.number().int().positive().max(86400).optional(),
  userId: z.string().uuid(),
  scope: z.object({
    tenantId: z.string().uuid(),
    organizationId: z.string().uuid().nullable()
  })
});
const COMMUNICATION_CHANNELS_CONNECT_CREDENTIAL_CHANNEL_COMMAND_ID = "communication_channels.channel.connect_credential";
const connectCredentialChannelCommand = {
  id: COMMUNICATION_CHANNELS_CONNECT_CREDENTIAL_CHANNEL_COMMAND_ID,
  async execute(rawInput, ctx) {
    const input = connectCredentialChannelSchema.parse(rawInput);
    const em = ctx.container.resolve("em").fork();
    const adapterRegistry = ctx.container.resolve("channelAdapterRegistry");
    const adapter = adapterRegistry.get(input.providerKey);
    if (!adapter) {
      return {
        status: "no_adapter",
        reason: `No adapter registered for provider '${input.providerKey}'`
      };
    }
    if (typeof adapter.validateCredentials === "function") {
      const validation = await adapter.validateCredentials({
        providerKey: input.providerKey,
        credentials: input.credentials,
        scope: {
          tenantId: input.scope.tenantId,
          organizationId: input.scope.organizationId ?? input.scope.tenantId
        }
      });
      if (!validation.ok) {
        return {
          status: "validation_failed",
          errors: validation.errors ?? { _form: "Credential validation failed" }
        };
      }
    }
    let credentialsService = null;
    try {
      credentialsService = ctx.container.resolve("integrationCredentialsService");
    } catch {
      credentialsService = null;
    }
    const credentialsScope = {
      tenantId: input.scope.tenantId,
      organizationId: input.scope.organizationId ?? input.scope.tenantId,
      userId: input.userId
    };
    let credentialsRefId = null;
    let credentialsPersisted = false;
    if (credentialsService?.save) {
      try {
        await credentialsService.save(
          `channel_${input.providerKey}`,
          { ...input.credentials, userId: input.userId },
          credentialsScope
        );
        credentialsPersisted = true;
      } catch (err) {
        logger.warn("credentials persist failed for provider", { providerKey: input.providerKey, err });
      }
      if (credentialsPersisted) {
        try {
          const { IntegrationCredentials } = await import("@open-mercato/core/modules/integrations/data/entities");
          const { findOneWithDecryption } = await import("@open-mercato/shared/lib/encryption/find");
          const row = await findOneWithDecryption(
            em,
            IntegrationCredentials,
            {
              integrationId: `channel_${input.providerKey}`,
              tenantId: credentialsScope.tenantId,
              organizationId: credentialsScope.organizationId,
              userId: credentialsScope.userId,
              deletedAt: null
            },
            void 0,
            credentialsScope
          );
          credentialsRefId = row?.id ?? null;
        } catch {
          credentialsRefId = null;
        }
      }
    }
    const credBag = input.credentials;
    const rawIdentifier = (typeof credBag.username === "string" && credBag.username.length > 0 ? credBag.username : null) ?? (typeof credBag.email === "string" && credBag.email.length > 0 ? credBag.email : null) ?? (typeof credBag.fromAddress === "string" && credBag.fromAddress.length > 0 ? credBag.fromAddress : null);
    const externalIdentifier = rawIdentifier && rawIdentifier.includes("@") ? rawIdentifier.toLowerCase() : rawIdentifier;
    const credentialsAvailable = credentialsRefId !== null;
    let channel;
    try {
      channel = await createConnectedChannelRow({
        em,
        adapter,
        providerKey: input.providerKey,
        displayName: input.displayName,
        externalIdentifier,
        credentialsRefId,
        userId: input.userId,
        scope: { tenantId: input.scope.tenantId, organizationId: input.scope.organizationId ?? null },
        pollIntervalSeconds: input.pollIntervalSeconds
      });
    } catch (err) {
      if (err instanceof MailboxAlreadyConnectedError) {
        return {
          status: "duplicate_mailbox",
          externalIdentifier: err.externalIdentifier,
          existingProviderKey: err.existingProviderKey
        };
      }
      throw err;
    }
    if (credentialsAvailable && input.providerKey === "gmail") {
      const adapterSupportsPush = typeof adapter.registerPush === "function" && typeof adapter.unregisterPush === "function";
      const organizationId = input.scope.organizationId;
      if (adapterSupportsPush && organizationId) {
        try {
          const { pushRegister } = await import("./push-register.js");
          await pushRegister({
            container: ctx.container,
            scope: {
              tenantId: input.scope.tenantId,
              organizationId,
              userId: input.userId
            },
            input: { channelId: channel.id }
          });
        } catch (err) {
          logger.warn("best-effort pushRegister failed for channel", { channelId: channel.id, err });
        }
      }
    }
    return { status: "connected", channelId: channel.id, externalIdentifier };
  }
};
registerCommand(connectCredentialChannelCommand);
var connect_credential_channel_default = connectCredentialChannelCommand;
export {
  COMMUNICATION_CHANNELS_CONNECT_CREDENTIAL_CHANNEL_COMMAND_ID,
  connect_credential_channel_default as default
};
//# sourceMappingURL=connect-credential-channel.js.map
