import type { AgentToolResult } from "@mariozechner/pi-agent-core";
import {
  readNumberParam,
  readStringArrayParam,
  readStringParam,
} from "../../../../agents/tools/common.js";
import { handleDiscordAction } from "../../../../agents/tools/discord-actions.js";
import type { ChannelMessageActionContext } from "../../types.js";
import { tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin.js";
import { resolveDiscordChannelId } from "../../../../discord/targets.js";

const providerId = "discord";

function readParentIdParam(params: Record<string, unknown>): string | null | undefined {
  if (params.clearParent === true) return null;
  if (params.parentId === null) return null;
  return readStringParam(params, "parentId");
}

export async function handleDiscordMessageAction(
  ctx: Pick<ChannelMessageActionContext, "action" | "params" | "cfg" | "accountId">,
): Promise<AgentToolResult<unknown>> {
  const { action, params, cfg } = ctx;
  const accountId = ctx.accountId ?? readStringParam(params, "accountId");

  const resolveChannelId = () =>
    resolveDiscordChannelId(
      readStringParam(params, "channelId") ?? readStringParam(params, "to", { required: true }),
    );

  if (action === "send") {
    const to = readStringParam(params, "to", { required: true });
    const content = readStringParam(params, "message", {
      required: true,
      allowEmpty: true,
    });
    const mediaUrl = readStringParam(params, "media", { trim: false });
    const replyTo = readStringParam(params, "replyTo");
    const embeds = Array.isArray(params.embeds) ? params.embeds : undefined;
    return await handleDiscordAction(
      {
        action: "sendMessage",
        accountId: accountId ?? undefined,
        to,
        content,
        mediaUrl: mediaUrl ?? undefined,
        replyTo: replyTo ?? undefined,
        embeds,
      },
      cfg,
    );
  }

  if (action === "poll") {
    const to = readStringParam(params, "to", { required: true });
    const question = readStringParam(params, "pollQuestion", {
      required: true,
    });
    const answers = readStringArrayParam(params, "pollOption", { required: true }) ?? [];
    const allowMultiselect = typeof params.pollMulti === "boolean" ? params.pollMulti : undefined;
    const durationHours = readNumberParam(params, "pollDurationHours", {
      integer: true,
    });
    return await handleDiscordAction(
      {
        action: "poll",
        accountId: accountId ?? undefined,
        to,
        question,
        answers,
        allowMultiselect,
        durationHours: durationHours ?? undefined,
        content: readStringParam(params, "message"),
      },
      cfg,
    );
  }

  if (action === "react") {
    const messageId = readStringParam(params, "messageId", { required: true });
    const emoji = readStringParam(params, "emoji", { allowEmpty: true });
    const remove = typeof params.remove === "boolean" ? params.remove : undefined;
    return await handleDiscordAction(
      {
        action: "react",
        accountId: accountId ?? undefined,
        channelId: resolveChannelId(),
        messageId,
        emoji,
        remove,
      },
      cfg,
    );
  }

  if (action === "reactions") {
    const messageId = readStringParam(params, "messageId", { required: true });
    const limit = readNumberParam(params, "limit", { integer: true });
    return await handleDiscordAction(
      {
        action: "reactions",
        accountId: accountId ?? undefined,
        channelId: resolveChannelId(),
        messageId,
        limit,
      },
      cfg,
    );
  }

  if (action === "read") {
    const limit = readNumberParam(params, "limit", { integer: true });
    return await handleDiscordAction(
      {
        action: "readMessages",
        accountId: accountId ?? undefined,
        channelId: resolveChannelId(),
        limit,
        before: readStringParam(params, "before"),
        after: readStringParam(params, "after"),
        around: readStringParam(params, "around"),
      },
      cfg,
    );
  }

  if (action === "edit") {
    const messageId = readStringParam(params, "messageId", { required: true });
    const content = readStringParam(params, "message", { required: true });
    return await handleDiscordAction(
      {
        action: "editMessage",
        accountId: accountId ?? undefined,
        channelId: resolveChannelId(),
        messageId,
        content,
      },
      cfg,
    );
  }

  if (action === "delete") {
    const messageId = readStringParam(params, "messageId", { required: true });
    return await handleDiscordAction(
      {
        action: "deleteMessage",
        accountId: accountId ?? undefined,
        channelId: resolveChannelId(),
        messageId,
      },
      cfg,
    );
  }

  if (action === "pin" || action === "unpin" || action === "list-pins") {
    const messageId =
      action === "list-pins" ? undefined : readStringParam(params, "messageId", { required: true });
    return await handleDiscordAction(
      {
        action: action === "pin" ? "pinMessage" : action === "unpin" ? "unpinMessage" : "listPins",
        accountId: accountId ?? undefined,
        channelId: resolveChannelId(),
        messageId,
      },
      cfg,
    );
  }

  if (action === "permissions") {
    return await handleDiscordAction(
      {
        action: "permissions",
        accountId: accountId ?? undefined,
        channelId: resolveChannelId(),
      },
      cfg,
    );
  }

  if (action === "thread-create") {
    const name = readStringParam(params, "threadName", { required: true });
    const messageId = readStringParam(params, "messageId");
    const content = readStringParam(params, "message");
    const autoArchiveMinutes = readNumberParam(params, "autoArchiveMin", {
      integer: true,
    });
    return await handleDiscordAction(
      {
        action: "threadCreate",
        accountId: accountId ?? undefined,
        channelId: resolveChannelId(),
        name,
        messageId,
        content,
        autoArchiveMinutes,
      },
      cfg,
    );
  }

  if (action === "sticker") {
    const stickerIds =
      readStringArrayParam(params, "stickerId", {
        required: true,
        label: "sticker-id",
      }) ?? [];
    return await handleDiscordAction(
      {
        action: "sticker",
        accountId: accountId ?? undefined,
        to: readStringParam(params, "to", { required: true }),
        stickerIds,
        content: readStringParam(params, "message"),
      },
      cfg,
    );
  }

  const adminResult = await tryHandleDiscordMessageActionGuildAdmin({
    ctx,
    resolveChannelId,
    readParentIdParam,
  });
  if (adminResult !== undefined) return adminResult;

  throw new Error(`Action ${String(action)} is not supported for provider ${providerId}.`);
}
