import type { Config } from '../config/index.js';
import type { HookEngine } from '../hooks/index.js';
import { ChannelRegistry, TelegramAdapter, WebChatAdapter, DiscordAdapter, SlackAdapter, WhatsAppAdapter, MatrixAdapter, SignalAdapter, MattermostAdapter, TeamsAdapter, GoogleChatAdapter, BlueBubblesAdapter, LineAdapter, FeishuAdapter, ZaloAdapter, PairingManager } from '../channels/index.js';
import { CronScheduler, WebhookHandler, GmailWatcher, buildPresetCronJobs } from '../automation/index.js';
import type { GatewayServer } from '../gateway/index.js';

export interface ChannelsDeps {
  config: Config;
  channelRegistry: ChannelRegistry;
  hookEngine: HookEngine;
  pairingManager?: PairingManager;
  gateway: GatewayServer;
}

export interface ChannelsResult {
  cronScheduler?: CronScheduler;
  webhookHandler?: WebhookHandler;
  gmailWatcher?: GmailWatcher;
}

function resolveChannelMinioShare(config: Config): {
  enabled: boolean;
  endpoint: string;
  accessKey: string;
  secretKey: string;
  bucket: string;
  prefix: string;
  secure: boolean;
  expires?: string;
  mcPath?: string;
} | undefined {
  const minio = config.backup.minio;
  if (!minio.enabled || !minio.endpoint || !minio.access_key || !minio.secret_key || !minio.bucket) {
    return undefined;
  }
  return {
    enabled: true,
    endpoint: minio.endpoint,
    accessKey: minio.access_key,
    secretKey: minio.secret_key,
    bucket: minio.bucket,
    prefix: minio.prefix,
    secure: minio.secure,
  };
}

function resolveChannelMinioShareWithOverrides(
  base: ReturnType<typeof resolveChannelMinioShare>,
  override: {
    enabled: boolean;
    endpoint?: string;
    access_key?: string;
    secret_key?: string;
    bucket?: string;
    prefix: string;
    secure: boolean;
    expires: string;
    mc_path?: string;
  } | undefined,
): {
  enabled: boolean;
  endpoint: string;
  accessKey: string;
  secretKey: string;
  bucket: string;
  prefix: string;
  secure: boolean;
  expires?: string;
  mcPath?: string;
} | undefined {
  if (!override?.enabled) {
    return base;
  }

  const endpoint = override.endpoint ?? base?.endpoint;
  const accessKey = override.access_key ?? base?.accessKey;
  const secretKey = override.secret_key ?? base?.secretKey;
  const bucket = override.bucket ?? base?.bucket;
  if (!endpoint || !accessKey || !secretKey || !bucket) {
    return undefined;
  }

  return {
    enabled: true,
    endpoint,
    accessKey,
    secretKey,
    bucket,
    prefix: override.prefix,
    secure: override.secure,
    expires: override.expires,
    mcPath: override.mc_path,
  };
}

export function registerChannels(deps: ChannelsDeps): ChannelsResult {
  const { config, channelRegistry, hookEngine, pairingManager, gateway } = deps;
  const channelMinioShare = resolveChannelMinioShare(config);

  // Register Telegram adapter (if configured)
  if (config.telegram) {
    const telegramAdapter = new TelegramAdapter({
      botToken: config.telegram.bot_token,
      allowedChatIds: config.telegram.allowed_chat_ids,
      requireMention: config.telegram.require_mention,
      hookEngine,
      pairingManager,
    });
    channelRegistry.register(telegramAdapter);
  }

  // Register Discord adapter (if configured)
  if (config.discord) {
    const discordAdapter = new DiscordAdapter({
      botToken: config.discord.bot_token,
      allowedGuildIds: config.discord.allowed_guild_ids.length > 0 ? config.discord.allowed_guild_ids : undefined,
      allowedChannelIds: config.discord.allowed_channel_ids.length > 0 ? config.discord.allowed_channel_ids : undefined,
      requireMention: config.discord.require_mention,
      pairingManager,
    });
    channelRegistry.register(discordAdapter);
  }

  // Register Slack adapter (if configured)
  if (config.slack) {
    const slackAdapter = new SlackAdapter({
      botToken: config.slack.bot_token,
      appToken: config.slack.app_token,
      signingSecret: config.slack.signing_secret,
      allowedChannelIds: config.slack.allowed_channel_ids.length > 0 ? config.slack.allowed_channel_ids : undefined,
      requireMention: config.slack.require_mention,
      pairingManager,
    });
    channelRegistry.register(slackAdapter);
  }

  // Register WhatsApp adapter (if configured)
  if (config.whatsapp) {
    const whatsappAdapter = new WhatsAppAdapter({
      allowedNumbers: config.whatsapp.allowed_numbers.length > 0 ? config.whatsapp.allowed_numbers : undefined,
      allowedGroupIds: config.whatsapp.allowed_group_ids.length > 0 ? config.whatsapp.allowed_group_ids : undefined,
      requireMention: config.whatsapp.require_mention,
      dataDir: config.whatsapp.data_dir,
      pairingManager,
      allowNoSandbox: config.whatsapp.no_sandbox,
    });
    channelRegistry.register(whatsappAdapter);
  }

  // Register Matrix adapter (if configured)
  if (config.matrix) {
    const matrixAdapter = new MatrixAdapter({
      homeserverUrl: config.matrix.homeserver_url,
      accessToken: config.matrix.access_token,
      allowedRoomIds: config.matrix.allowed_room_ids.length > 0 ? config.matrix.allowed_room_ids : undefined,
      requireMention: config.matrix.require_mention,
      syncTimeoutMs: config.matrix.sync_timeout_ms,
      displayName: config.matrix.display_name,
      pairingManager,
    });
    channelRegistry.register(matrixAdapter);
  }

  // Register Signal adapter (if configured)
  if (config.signal) {
    const signalAdapter = new SignalAdapter({
      account: config.signal.account,
      signalCliPath: config.signal.signal_cli_path,
      allowedNumbers: config.signal.allowed_numbers.length > 0 ? config.signal.allowed_numbers : undefined,
      allowedGroupIds: config.signal.allowed_group_ids.length > 0 ? config.signal.allowed_group_ids : undefined,
      requireMention: config.signal.require_mention,
      mentionName: config.signal.mention_name,
      pollIntervalMs: config.signal.poll_interval_ms,
      sendTimeoutMs: config.signal.send_timeout_ms,
      pairingManager,
    });
    channelRegistry.register(signalAdapter);
  }

  // Register Mattermost adapter (if configured)
  if (config.mattermost) {
    const mattermostAdapter = new MattermostAdapter({
      serverUrl: config.mattermost.server_url,
      botToken: config.mattermost.bot_token,
      allowedChannelIds: config.mattermost.allowed_channel_ids.length > 0 ? config.mattermost.allowed_channel_ids : undefined,
      requireMention: config.mattermost.require_mention,
      mentionName: config.mattermost.mention_name,
      pollIntervalMs: config.mattermost.poll_interval_ms,
      pairingManager,
    });
    channelRegistry.register(mattermostAdapter);
  }

  // Register Microsoft Teams adapter (if configured)
  if (config.teams) {
    const teamsAdapter = new TeamsAdapter({
      appId: config.teams.app_id,
      appPassword: config.teams.app_password,
      allowedConversationIds: config.teams.allowed_conversation_ids.length > 0 ? config.teams.allowed_conversation_ids : undefined,
      requireMention: config.teams.require_mention,
    });
    channelRegistry.register(teamsAdapter);
    gateway.setTeamsHandler(teamsAdapter);
  }

  // Register Google Chat adapter (if configured)
  if (config.google_chat) {
    const googleChatAdapter = new GoogleChatAdapter({
      serviceAccountKeyFile: config.google_chat.service_account_key_file,
      serviceAccountJson: config.google_chat.service_account_json,
      webhookToken: config.google_chat.webhook_token,
      allowedSpaceNames: config.google_chat.allowed_space_names.length > 0 ? config.google_chat.allowed_space_names : undefined,
      requireMention: config.google_chat.require_mention,
    });
    channelRegistry.register(googleChatAdapter);
    gateway.setGoogleChatHandler(googleChatAdapter);
  }

  // Register BlueBubbles adapter (if configured)
  if (config.bluebubbles) {
    const blueBubblesAdapter = new BlueBubblesAdapter({
      endpoint: config.bluebubbles.endpoint,
      apiKey: config.bluebubbles.api_key,
      webhookToken: config.bluebubbles.webhook_token,
      allowedChatGuids: config.bluebubbles.allowed_chat_guids.length > 0 ? config.bluebubbles.allowed_chat_guids : undefined,
      requireMention: config.bluebubbles.require_mention,
      mentionName: config.bluebubbles.mention_name,
    });
    channelRegistry.register(blueBubblesAdapter);
    gateway.setBlueBubblesHandler(blueBubblesAdapter);
  }

  // Register LINE adapter (if configured)
  if (config.line) {
    const lineMinioShare = resolveChannelMinioShareWithOverrides(channelMinioShare, config.line.minio);
    const effectiveLineMinioShare = lineMinioShare && !config.line.minio.enabled
      ? { ...lineMinioShare, prefix: `${lineMinioShare.prefix.replace(/\/+$/, '')}/channels/line` }
      : lineMinioShare;
    const lineAdapter = new LineAdapter({
      channelAccessToken: config.line.channel_access_token,
      channelSecret: config.line.channel_secret,
      allowedSourceIds: config.line.allowed_source_ids.length > 0 ? config.line.allowed_source_ids : undefined,
      requireMention: config.line.require_mention,
      mentionName: config.line.mention_name,
      minio: effectiveLineMinioShare,
    });
    channelRegistry.register(lineAdapter);
    gateway.setLineHandler(lineAdapter);
  }

  // Register Feishu adapter (if configured)
  if (config.feishu) {
    const feishuAdapter = new FeishuAdapter({
      appId: config.feishu.app_id,
      appSecret: config.feishu.app_secret,
      webhookToken: config.feishu.webhook_token,
      allowedChatIds: config.feishu.allowed_chat_ids.length > 0 ? config.feishu.allowed_chat_ids : undefined,
      requireMention: config.feishu.require_mention,
      mentionName: config.feishu.mention_name,
      endpoint: config.feishu.endpoint,
    });
    channelRegistry.register(feishuAdapter);
    gateway.setFeishuHandler(feishuAdapter);
  }

  // Register Zalo adapter (if configured)
  if (config.zalo) {
    const zaloMinioShare = resolveChannelMinioShareWithOverrides(channelMinioShare, config.zalo.minio);
    const effectiveZaloMinioShare = zaloMinioShare && !config.zalo.minio.enabled
      ? { ...zaloMinioShare, prefix: `${zaloMinioShare.prefix.replace(/\/+$/, '')}/channels/zalo` }
      : zaloMinioShare;
    const zaloAdapter = new ZaloAdapter({
      oaAccessToken: config.zalo.oa_access_token,
      endpoint: config.zalo.endpoint,
      webhookToken: config.zalo.webhook_token,
      allowedUserIds: config.zalo.allowed_user_ids.length > 0 ? config.zalo.allowed_user_ids : undefined,
      requireMention: config.zalo.require_mention,
      mentionName: config.zalo.mention_name,
      minio: effectiveZaloMinioShare,
    });
    channelRegistry.register(zaloAdapter);
    gateway.setZaloHandler(zaloAdapter);
  }

  // Register WebChat adapter (wraps the gateway)
  const webChatAdapter = new WebChatAdapter({ gateway });
  channelRegistry.register(webChatAdapter);

  // Register cron scheduler adapter (if any cron jobs configured)
  let cronScheduler: CronScheduler | undefined;
  const presetCronJobs = buildPresetCronJobs(config);
  const cronJobs = [...config.automation.cron, ...presetCronJobs];
  if (cronJobs.length > 0) {
    cronScheduler = new CronScheduler(cronJobs, channelRegistry, config.automation.delivery_mode);
    channelRegistry.register(cronScheduler);
    console.log(`Registered ${cronJobs.length} cron job(s)`);
  }

  // Register webhook handler adapter (if any webhooks configured)
  let webhookHandler: WebhookHandler | undefined;
  if (config.automation.webhooks.length > 0) {
    webhookHandler = new WebhookHandler(
      config.automation.webhooks,
      channelRegistry,
      config.automation.delivery_mode,
      config.server.max_request_body_bytes,
    );
    channelRegistry.register(webhookHandler);
    gateway.setWebhookHandler(webhookHandler);
    console.log(`Registered ${config.automation.webhooks.length} webhook(s)`);
  }

  // Register Gmail watcher adapter (if configured and enabled)
  let gmailWatcher: GmailWatcher | undefined;
  if (config.automation.gmail?.enabled) {
    gmailWatcher = new GmailWatcher(config.automation.gmail, channelRegistry);
    channelRegistry.register(gmailWatcher);
    gateway.setGmailHandler(gmailWatcher);
    console.log('Registered Gmail watcher');
  }

  return { cronScheduler, webhookHandler, gmailWatcher };
}
