// Discord plugin module implements setup surface behavior.
import { resolveBasicAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
import {
  createSetupTranslator,
  type ChannelSetupWizard,
  type OpenClawConfig,
  type WizardPrompter,
} from "openclaw/plugin-sdk/setup-runtime";
import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
import { resolveDiscordAccountAllowFrom } from "./accounts.js";
import { resolveDiscordChannelAllowlist } from "./resolve-channels.js";
import { resolveDiscordUserAllowlist } from "./resolve-users.js";
import {
  resolveDefaultDiscordSetupAccountId,
  resolveDiscordSetupAccountConfig,
} from "./setup-account-state.js";
import { createDiscordSetupWizardBase, parseDiscordAllowFromId } from "./setup-core.js";
import {
  patchChannelConfigForAccount,
  promptResolvedAllowFrom,
  resolveEntriesWithOptionalToken,
  resolveSetupAccountId,
  splitSetupEntries,
} from "./setup-runtime-helpers.js";
import { resolveDiscordToken } from "./token.js";

const t = createSetupTranslator();

const channel = "discord" as const;

async function resolveDiscordAllowFromEntries(params: { token?: string; entries: string[] }) {
  return await resolveBasicAllowFromEntries({
    token: params.token,
    entries: params.entries,
    resolveEntries: async ({ token, entries }) =>
      await resolveDiscordUserAllowlist({ token, entries }),
  });
}

async function promptDiscordAllowFrom(params: {
  cfg: OpenClawConfig;
  prompter: WizardPrompter;
  accountId?: string;
}): Promise<OpenClawConfig> {
  const accountId = resolveSetupAccountId({
    accountId: params.accountId,
    defaultAccountId: resolveDefaultDiscordSetupAccountId(params.cfg),
  });
  const account = resolveDiscordSetupAccountConfig({ cfg: params.cfg, accountId });
  const noteTitle = t("wizard.discord.allowlistTitle");
  await params.prompter.note(
    [
      t("wizard.discord.allowlistIntro"),
      t("wizard.discord.examples"),
      "- 123456789012345678",
      "- @alice",
      "- alice#1234",
      t("wizard.discord.multipleEntries"),
      t("wizard.channels.docs", { link: formatDocsLink("/discord", "discord") }),
    ].join("\n"),
    noteTitle,
  );
  const allowFrom = await promptResolvedAllowFrom({
    prompter: params.prompter,
    existing: resolveDiscordAccountAllowFrom({ cfg: params.cfg, accountId }) ?? [],
    token: resolveDiscordToken(params.cfg, { accountId }).token,
    message: t("wizard.discord.allowFromPrompt"),
    placeholder: "@alice, 123456789012345678",
    label: noteTitle,
    parseInputs: splitSetupEntries,
    parseId: parseDiscordAllowFromId,
    invalidWithoutTokenNote: t("wizard.discord.allowFromInvalidWithoutToken"),
    resolveEntries: async ({ token, entries }) =>
      (
        await resolveDiscordUserAllowlist({
          token,
          entries,
        })
      ).map((entry) => ({
        input: entry.input,
        resolved: entry.resolved,
        id: entry.id ?? null,
      })),
  });
  return patchChannelConfigForAccount({
    cfg: params.cfg,
    channel,
    accountId: account.accountId,
    patch: {
      allowFrom,
      dm: {
        ...account.config.dm,
        enabled: typeof account.config.dm?.enabled === "boolean" ? account.config.dm.enabled : true,
      },
    },
  });
}

async function resolveDiscordGroupAllowlist(params: {
  cfg: OpenClawConfig;
  accountId: string;
  credentialValues: { token?: string };
  entries: string[];
}) {
  return await resolveEntriesWithOptionalToken({
    token:
      resolveDiscordToken(params.cfg, { accountId: params.accountId }).token ||
      (typeof params.credentialValues.token === "string" ? params.credentialValues.token : ""),
    entries: params.entries,
    buildWithoutToken: (input) => ({
      input,
      resolved: false,
    }),
    resolveEntries: async ({ token, entries }) =>
      await resolveDiscordChannelAllowlist({
        token,
        entries,
      }),
  });
}

export const discordSetupWizard: ChannelSetupWizard = createDiscordSetupWizardBase({
  promptAllowFrom: promptDiscordAllowFrom,
  resolveAllowFromEntries: async ({ cfg, accountId, credentialValues, entries }) =>
    await resolveDiscordAllowFromEntries({
      token:
        resolveDiscordToken(cfg, { accountId }).token ||
        (typeof credentialValues.token === "string" ? credentialValues.token : ""),
      entries,
    }),
  resolveGroupAllowlist: async ({ cfg, accountId, credentialValues, entries }) =>
    await resolveDiscordGroupAllowlist({
      cfg,
      accountId,
      credentialValues,
      entries,
    }),
});
