import type { AgentToolResult } from "@mariozechner/pi-agent-core";

import type { ClawdbotConfig } from "../../config/config.js";
import { resolveSlackAccount } from "../../slack/accounts.js";
import {
  deleteSlackMessage,
  editSlackMessage,
  getSlackMemberInfo,
  listSlackEmojis,
  listSlackPins,
  listSlackReactions,
  pinSlackMessage,
  reactSlackMessage,
  readSlackMessages,
  removeOwnSlackReactions,
  removeSlackReaction,
  sendSlackMessage,
  unpinSlackMessage,
} from "../../slack/actions.js";
import {
  createActionGate,
  jsonResult,
  readReactionParams,
  readStringParam,
} from "./common.js";

const messagingActions = new Set([
  "sendMessage",
  "editMessage",
  "deleteMessage",
  "readMessages",
]);

const reactionsActions = new Set(["react", "reactions"]);
const pinActions = new Set(["pinMessage", "unpinMessage", "listPins"]);

export async function handleSlackAction(
  params: Record<string, unknown>,
  cfg: ClawdbotConfig,
): Promise<AgentToolResult<unknown>> {
  const action = readStringParam(params, "action", { required: true });
  const accountId = readStringParam(params, "accountId");
  const accountOpts = accountId ? { accountId } : undefined;
  const account = resolveSlackAccount({ cfg, accountId });
  const actionConfig = account.actions ?? cfg.slack?.actions;
  const isActionEnabled = createActionGate(actionConfig);

  if (reactionsActions.has(action)) {
    if (!isActionEnabled("reactions")) {
      throw new Error("Slack reactions are disabled.");
    }
    const channelId = readStringParam(params, "channelId", { required: true });
    const messageId = readStringParam(params, "messageId", { required: true });
    if (action === "react") {
      const { emoji, remove, isEmpty } = readReactionParams(params, {
        removeErrorMessage: "Emoji is required to remove a Slack reaction.",
      });
      if (remove) {
        if (accountOpts) {
          await removeSlackReaction(channelId, messageId, emoji, accountOpts);
        } else {
          await removeSlackReaction(channelId, messageId, emoji);
        }
        return jsonResult({ ok: true, removed: emoji });
      }
      if (isEmpty) {
        const removed = accountOpts
          ? await removeOwnSlackReactions(channelId, messageId, accountOpts)
          : await removeOwnSlackReactions(channelId, messageId);
        return jsonResult({ ok: true, removed });
      }
      if (accountOpts) {
        await reactSlackMessage(channelId, messageId, emoji, accountOpts);
      } else {
        await reactSlackMessage(channelId, messageId, emoji);
      }
      return jsonResult({ ok: true, added: emoji });
    }
    const reactions = accountOpts
      ? await listSlackReactions(channelId, messageId, accountOpts)
      : await listSlackReactions(channelId, messageId);
    return jsonResult({ ok: true, reactions });
  }

  if (messagingActions.has(action)) {
    if (!isActionEnabled("messages")) {
      throw new Error("Slack messages are disabled.");
    }
    switch (action) {
      case "sendMessage": {
        const to = readStringParam(params, "to", { required: true });
        const content = readStringParam(params, "content", { required: true });
        const mediaUrl = readStringParam(params, "mediaUrl");
        const result = await sendSlackMessage(to, content, {
          accountId: accountId ?? undefined,
          mediaUrl: mediaUrl ?? undefined,
        });
        return jsonResult({ ok: true, result });
      }
      case "editMessage": {
        const channelId = readStringParam(params, "channelId", {
          required: true,
        });
        const messageId = readStringParam(params, "messageId", {
          required: true,
        });
        const content = readStringParam(params, "content", {
          required: true,
        });
        if (accountOpts) {
          await editSlackMessage(channelId, messageId, content, accountOpts);
        } else {
          await editSlackMessage(channelId, messageId, content);
        }
        return jsonResult({ ok: true });
      }
      case "deleteMessage": {
        const channelId = readStringParam(params, "channelId", {
          required: true,
        });
        const messageId = readStringParam(params, "messageId", {
          required: true,
        });
        if (accountOpts) {
          await deleteSlackMessage(channelId, messageId, accountOpts);
        } else {
          await deleteSlackMessage(channelId, messageId);
        }
        return jsonResult({ ok: true });
      }
      case "readMessages": {
        const channelId = readStringParam(params, "channelId", {
          required: true,
        });
        const limitRaw = params.limit;
        const limit =
          typeof limitRaw === "number" && Number.isFinite(limitRaw)
            ? limitRaw
            : undefined;
        const before = readStringParam(params, "before");
        const after = readStringParam(params, "after");
        const result = await readSlackMessages(channelId, {
          accountId: accountId ?? undefined,
          limit,
          before: before ?? undefined,
          after: after ?? undefined,
        });
        return jsonResult({ ok: true, ...result });
      }
      default:
        break;
    }
  }

  if (pinActions.has(action)) {
    if (!isActionEnabled("pins")) {
      throw new Error("Slack pins are disabled.");
    }
    const channelId = readStringParam(params, "channelId", { required: true });
    if (action === "pinMessage") {
      const messageId = readStringParam(params, "messageId", {
        required: true,
      });
      if (accountOpts) {
        await pinSlackMessage(channelId, messageId, accountOpts);
      } else {
        await pinSlackMessage(channelId, messageId);
      }
      return jsonResult({ ok: true });
    }
    if (action === "unpinMessage") {
      const messageId = readStringParam(params, "messageId", {
        required: true,
      });
      if (accountOpts) {
        await unpinSlackMessage(channelId, messageId, accountOpts);
      } else {
        await unpinSlackMessage(channelId, messageId);
      }
      return jsonResult({ ok: true });
    }
    const pins = accountOpts
      ? await listSlackPins(channelId, accountOpts)
      : await listSlackPins(channelId);
    return jsonResult({ ok: true, pins });
  }

  if (action === "memberInfo") {
    if (!isActionEnabled("memberInfo")) {
      throw new Error("Slack member info is disabled.");
    }
    const userId = readStringParam(params, "userId", { required: true });
    const info = accountOpts
      ? await getSlackMemberInfo(userId, accountOpts)
      : await getSlackMemberInfo(userId);
    return jsonResult({ ok: true, info });
  }

  if (action === "emojiList") {
    if (!isActionEnabled("emojiList")) {
      throw new Error("Slack emoji list is disabled.");
    }
    const emojis = accountOpts
      ? await listSlackEmojis(accountOpts)
      : await listSlackEmojis();
    return jsonResult({ ok: true, emojis });
  }

  throw new Error(`Unknown action: ${action}`);
}
