// Discord provider module implements model/runtime integration.
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
import type { ChannelRuntimeSurface } from "openclaw/plugin-sdk/channel-contract";
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
import type { DiscordAccountConfig, OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
import { createDiscordActivityButton } from "../activities/interaction.js";
import {
  getDiscordExecApprovalApprovers,
  isDiscordExecApprovalClientEnabled,
} from "../exec-approvals.js";
import type { BaseCommand, BaseMessageInteractiveComponent, Modal } from "../internal/discord.js";
import { createDiscordVoiceCommand, DISCORD_VOICE_COMMAND_SPEC } from "../voice/command.js";
import {
  createAgentComponentControls,
  createDiscordComponentControls,
  createDiscordComponentModal,
} from "./agent-components.js";
import {
  createDiscordExecApprovalButtonContext,
  createExecApprovalButton,
} from "./exec-approvals.js";
import {
  createDiscordCommandArgFallbackButton,
  createDiscordModelPickerFallbackButton,
  createDiscordModelPickerFallbackSelect,
  createDiscordNativeCommand,
} from "./native-command.js";
import type { DiscordProviderCommandSpec } from "./provider.commands.js";
import { createDiscordQuestionButton } from "./questions.js";
import type { ThreadBindingManager } from "./thread-bindings.types.js";

type DiscordVoiceManager = import("../voice/voice-runtime.js").DiscordVoiceManager;

export function createDiscordProviderInteractionSurface(params: {
  cfg: OpenClawConfig;
  discordConfig: DiscordAccountConfig;
  accountId: string;
  applicationId?: string;
  token: string;
  commandSpecs: DiscordProviderCommandSpec[];
  nativeEnabled: boolean;
  voiceEnabled: boolean;
  groupPolicy: "open" | "disabled" | "allowlist";
  useAccessGroups: boolean;
  sessionPrefix: string;
  ephemeralDefault: boolean;
  threadBindings: ThreadBindingManager;
  voiceManagerRef: { current: DiscordVoiceManager | null };
  guildEntries: DiscordAccountConfig["guilds"];
  allowFrom: DiscordAccountConfig["allowFrom"];
  dmPolicy: NonNullable<DiscordAccountConfig["dmPolicy"]>;
  runtime: RuntimeEnv;
  channelRuntime?: ChannelRuntimeSurface;
  abortSignal?: AbortSignal;
  createNativeCommand?: typeof createDiscordNativeCommand;
}): {
  commands: BaseCommand[];
  components: BaseMessageInteractiveComponent[];
  modals: Modal[];
} {
  const createNativeCommand = params.createNativeCommand ?? createDiscordNativeCommand;
  const commands: BaseCommand[] = params.commandSpecs.map((spec) => {
    if (
      params.nativeEnabled &&
      params.voiceEnabled &&
      spec.name === DISCORD_VOICE_COMMAND_SPEC.name
    ) {
      return createDiscordVoiceCommand({
        cfg: params.cfg,
        discordConfig: params.discordConfig,
        accountId: params.accountId,
        groupPolicy: params.groupPolicy,
        useAccessGroups: params.useAccessGroups,
        getManager: () => params.voiceManagerRef.current,
        ephemeralDefault: params.ephemeralDefault,
      });
    }
    return createNativeCommand({
      command: spec,
      cfg: params.cfg,
      discordConfig: params.discordConfig,
      accountId: params.accountId,
      sessionPrefix: params.sessionPrefix,
      ephemeralDefault: params.ephemeralDefault,
      threadBindings: params.threadBindings,
    });
  });

  const execApprovalsConfig = params.discordConfig.execApprovals ?? {};
  const execApprovalsEnabled = isDiscordExecApprovalClientEnabled({
    cfg: params.cfg,
    accountId: params.accountId,
    configOverride: execApprovalsConfig,
  });
  const approvalActionsEnabled =
    getDiscordExecApprovalApprovers({
      cfg: params.cfg,
      accountId: params.accountId,
      configOverride: execApprovalsConfig,
    }).length > 0;
  if (execApprovalsEnabled) {
    registerChannelRuntimeContext({
      channelRuntime: params.channelRuntime,
      channelId: "discord",
      accountId: params.accountId,
      capability: CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY,
      context: {
        token: params.token,
        config: execApprovalsConfig,
      },
      abortSignal: params.abortSignal,
    });
  }

  const components: BaseMessageInteractiveComponent[] = [
    createDiscordQuestionButton({
      cfg: params.cfg,
      accountId: params.accountId,
      authContext: {
        cfg: params.cfg,
        accountId: params.accountId,
        discordConfig: params.discordConfig,
        runtime: params.runtime,
        token: params.token,
        guildEntries: params.guildEntries,
        allowFrom: params.allowFrom,
        dmPolicy: params.dmPolicy,
      },
    }),
    createDiscordCommandArgFallbackButton({
      cfg: params.cfg,
      discordConfig: params.discordConfig,
      accountId: params.accountId,
      sessionPrefix: params.sessionPrefix,
      threadBindings: params.threadBindings,
    }),
    createDiscordModelPickerFallbackButton({
      cfg: params.cfg,
      discordConfig: params.discordConfig,
      accountId: params.accountId,
      sessionPrefix: params.sessionPrefix,
      threadBindings: params.threadBindings,
    }),
    createDiscordModelPickerFallbackSelect({
      cfg: params.cfg,
      discordConfig: params.discordConfig,
      accountId: params.accountId,
      sessionPrefix: params.sessionPrefix,
      threadBindings: params.threadBindings,
    }),
  ];
  const activityButton = createDiscordActivityButton(
    {
      cfg: params.cfg,
      discordConfig: params.discordConfig,
      accountId: params.accountId,
      guildEntries: params.guildEntries,
      allowFrom: params.allowFrom,
      dmPolicy: params.dmPolicy,
      runtime: params.runtime,
      token: params.token,
    },
    params.applicationId,
  );
  if (activityButton) {
    components.push(activityButton);
  }
  const modals: Modal[] = [];

  if (approvalActionsEnabled) {
    components.push(
      createExecApprovalButton(
        createDiscordExecApprovalButtonContext({
          cfg: params.cfg,
          accountId: params.accountId,
          config: execApprovalsConfig,
        }),
      ),
    );
  }

  const agentComponentsConfig = params.discordConfig.agentComponents ?? {};
  if (agentComponentsConfig.enabled ?? true) {
    const componentContext = {
      cfg: params.cfg,
      discordConfig: params.discordConfig,
      accountId: params.accountId,
      guildEntries: params.guildEntries,
      allowFrom: params.allowFrom,
      dmPolicy: params.dmPolicy,
      runtime: params.runtime,
      token: params.token,
    };
    components.push(...createAgentComponentControls.map((create) => create(componentContext)));
    components.push(...createDiscordComponentControls.map((create) => create(componentContext)));
    modals.push(createDiscordComponentModal(componentContext));
  }

  return { commands, components, modals };
}
