import type { ChannelAdapter } from "./protocol/ChannelAdapter.js";
import type { PilotAdaptersConfig, PilotPlatformAdapterConfig } from "../../pilot/config/types.js";

/**
 * Lazily import + instantiate every channel whose config has `enabled: true`.
 * Each entry maps a config key to a dynamic loader for the matching channel folder.
 */
const CHANNEL_LOADERS: Record<
  string,
  (cfg: PilotPlatformAdapterConfig) => Promise<ChannelAdapter>
> = {
  telegram: async (cfg) => {
    const { TelegramChannel } = await import("./telegram/TelegramChannel.js");
    return new TelegramChannel({
      token: cfg.token,
      webhookUrl: cfg.webhookUrl,
    });
  },
  discord: async (cfg) => {
    const { DiscordChannel } = await import("./discord/DiscordChannel.js");
    return new DiscordChannel({ token: cfg.token });
  },
  slack: async (cfg) => {
    const { SlackChannel } = await import("./slack/SlackChannel.js");
    return new SlackChannel({
      botToken: cfg.token,
      appToken: cfg.extra?.appToken as string | undefined,
    });
  },
  matrix: async (cfg) => {
    const { MatrixChannel } = await import("./matrix/MatrixChannel.js");
    return new MatrixChannel({
      accessToken: cfg.token,
      homeserver: cfg.extra?.homeserver as string | undefined,
      userId: cfg.extra?.userId as string | undefined,
    });
  },
  mattermost: async (cfg) => {
    const { MattermostChannel } = await import("./mattermost/MattermostChannel.js");
    return new MattermostChannel({
      token: cfg.token,
      serverUrl: cfg.extra?.serverUrl as string | undefined,
      teamId: cfg.extra?.teamId as string | undefined,
    });
  },
  signal: async (cfg) => {
    const { SignalChannel } = await import("./signal/SignalChannel.js");
    return new SignalChannel({
      restUrl: cfg.extra?.restUrl as string | undefined,
      account: cfg.extra?.account as string | undefined,
    });
  },
  whatsapp: async (cfg) => {
    const { WhatsAppChannel } = await import("./whatsapp/WhatsAppChannel.js");
    return new WhatsAppChannel({
      bridgePath: cfg.extra?.bridgePath as string | undefined,
      bridgeUrl: cfg.extra?.bridgeUrl as string | undefined,
    });
  },
  bluebubbles: async (cfg) => {
    const { BlueBubblesChannel } = await import("./bluebubbles/BlueBubblesChannel.js");
    return new BlueBubblesChannel({
      serverUrl: cfg.extra?.serverUrl as string | undefined,
      password: cfg.token ?? (cfg.extra?.password as string | undefined),
    });
  },
  dingtalk: async (cfg) => {
    const { DingTalkChannel } = await import("./dingtalk/DingTalkChannel.js");
    return new DingTalkChannel({
      clientId: cfg.extra?.clientId as string | undefined,
      clientSecret: cfg.extra?.clientSecret as string | undefined,
    });
  },
  wecom: async (cfg) => {
    const { WeComChannel } = await import("./wecom/WeComChannel.js");
    return new WeComChannel({
      botKey: cfg.token,
      extra: cfg.extra,
    });
  },
  wecomCallback: async (cfg) => {
    const { WeComCallbackChannel } = await import("./wecom-callback/WeComCallbackChannel.js");
    return new WeComCallbackChannel({
      corpId: cfg.extra?.corpId as string | undefined,
      agentId: cfg.extra?.agentId as string | undefined,
      secret: cfg.extra?.secret as string | undefined,
      token: cfg.token,
      encodingAesKey: cfg.extra?.encodingAesKey as string | undefined,
      port: cfg.extra?.port as number | undefined,
    });
  },
  email: async (cfg) => {
    const { EmailChannel } = await import("./email/EmailChannel.js");
    return new EmailChannel({ extra: cfg.extra });
  },
  sms: async (cfg) => {
    const { SmsChannel } = await import("./sms/SmsChannel.js");
    return new SmsChannel({ extra: cfg.extra });
  },
  homeassistant: async (cfg) => {
    const { HomeAssistantChannel } = await import("./homeassistant/HomeAssistantChannel.js");
    return new HomeAssistantChannel({
      url: cfg.extra?.url as string | undefined,
      token: cfg.token,
    });
  },
  apiServer: async (cfg) => {
    const { ApiServerChannel } = await import("./api-server/ApiServerChannel.js");
    return new ApiServerChannel({
      port: cfg.extra?.port as number | undefined,
      apiKey: cfg.apiKey,
    });
  },
  webhook: async (cfg) => {
    const { WebhookChannel } = await import("./webhook/WebhookChannel.js");
    return new WebhookChannel({
      port: cfg.extra?.port as number | undefined,
      secret: cfg.extra?.secret as string | undefined,
    });
  },
};

export async function loadEnabledChannels(adapters: PilotAdaptersConfig | undefined): Promise<ChannelAdapter[]> {
  if (!adapters) return [];
  const channels: ChannelAdapter[] = [];

  for (const [key, loader] of Object.entries(CHANNEL_LOADERS)) {
    const cfg = (adapters as Record<string, unknown>)[key] as PilotPlatformAdapterConfig | undefined;
    if (!cfg?.enabled) continue;

    try {
      channels.push(await loader(cfg));
    } catch (e) {
      console.error(`[adapters] Failed to load channel "${key}": ${e}`);
    }
  }

  return channels;
}