import { describe, expect, it, vi } from "vitest";

import type { ClawdbotConfig } from "../../config/config.js";
import {
  deliverOutboundPayloads,
  normalizeOutboundPayloads,
} from "./deliver.js";

describe("deliverOutboundPayloads", () => {
  it("chunks telegram markdown and passes config token", async () => {
    const sendTelegram = vi
      .fn()
      .mockResolvedValue({ messageId: "m1", chatId: "c1" });
    const cfg: ClawdbotConfig = {
      telegram: { botToken: "tok-1", textChunkLimit: 2 },
    };
    const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN;
    process.env.TELEGRAM_BOT_TOKEN = "";
    try {
      const results = await deliverOutboundPayloads({
        cfg,
        provider: "telegram",
        to: "123",
        payloads: [{ text: "abcd" }],
        deps: { sendTelegram },
      });

      expect(sendTelegram).toHaveBeenCalledTimes(2);
      for (const call of sendTelegram.mock.calls) {
        expect(call[2]).toEqual(
          expect.objectContaining({ token: "tok-1", verbose: false }),
        );
      }
      expect(results).toHaveLength(2);
      expect(results[0]).toMatchObject({ provider: "telegram", chatId: "c1" });
    } finally {
      if (prevTelegramToken === undefined) {
        delete process.env.TELEGRAM_BOT_TOKEN;
      } else {
        process.env.TELEGRAM_BOT_TOKEN = prevTelegramToken;
      }
    }
  });

  it("uses signal media maxBytes from config", async () => {
    const sendSignal = vi
      .fn()
      .mockResolvedValue({ messageId: "s1", timestamp: 123 });
    const cfg: ClawdbotConfig = { signal: { mediaMaxMb: 2 } };

    const results = await deliverOutboundPayloads({
      cfg,
      provider: "signal",
      to: "+1555",
      payloads: [{ text: "hi", mediaUrl: "https://x.test/a.jpg" }],
      deps: { sendSignal },
    });

    expect(sendSignal).toHaveBeenCalledWith(
      "+1555",
      "hi",
      expect.objectContaining({
        mediaUrl: "https://x.test/a.jpg",
        maxBytes: 2 * 1024 * 1024,
      }),
    );
    expect(results[0]).toMatchObject({ provider: "signal", messageId: "s1" });
  });

  it("chunks WhatsApp text and returns all results", async () => {
    const sendWhatsApp = vi
      .fn()
      .mockResolvedValueOnce({ messageId: "w1", toJid: "jid" })
      .mockResolvedValueOnce({ messageId: "w2", toJid: "jid" });
    const cfg: ClawdbotConfig = {
      whatsapp: { textChunkLimit: 2 },
    };

    const results = await deliverOutboundPayloads({
      cfg,
      provider: "whatsapp",
      to: "+1555",
      payloads: [{ text: "abcd" }],
      deps: { sendWhatsApp },
    });

    expect(sendWhatsApp).toHaveBeenCalledTimes(2);
    expect(results.map((r) => r.messageId)).toEqual(["w1", "w2"]);
  });

  it("uses iMessage media maxBytes from agent fallback", async () => {
    const sendIMessage = vi.fn().mockResolvedValue({ messageId: "i1" });
    const cfg: ClawdbotConfig = { agent: { mediaMaxMb: 3 } };

    await deliverOutboundPayloads({
      cfg,
      provider: "imessage",
      to: "chat_id:42",
      payloads: [{ text: "hello" }],
      deps: { sendIMessage },
    });

    expect(sendIMessage).toHaveBeenCalledWith(
      "chat_id:42",
      "hello",
      expect.objectContaining({ maxBytes: 3 * 1024 * 1024 }),
    );
  });

  it("normalizes payloads and drops empty entries", () => {
    const normalized = normalizeOutboundPayloads([
      { text: "hi" },
      { mediaUrl: "https://x.test/a.jpg" },
      { text: " ", mediaUrls: [] },
    ]);
    expect(normalized).toEqual([
      { text: "hi", mediaUrls: [] },
      { text: "", mediaUrls: ["https://x.test/a.jpg"] },
      { text: " ", mediaUrls: [] },
    ]);
  });

  it("continues on errors when bestEffort is enabled", async () => {
    const sendWhatsApp = vi
      .fn()
      .mockRejectedValueOnce(new Error("fail"))
      .mockResolvedValueOnce({ messageId: "w2", toJid: "jid" });
    const onError = vi.fn();
    const cfg: ClawdbotConfig = {};

    const results = await deliverOutboundPayloads({
      cfg,
      provider: "whatsapp",
      to: "+1555",
      payloads: [{ text: "a" }, { text: "b" }],
      deps: { sendWhatsApp },
      bestEffort: true,
      onError,
    });

    expect(sendWhatsApp).toHaveBeenCalledTimes(2);
    expect(onError).toHaveBeenCalledTimes(1);
    expect(results).toEqual([
      { provider: "whatsapp", messageId: "w2", toJid: "jid" },
    ]);
  });
});
