import { describe, it, expect, vi, beforeEach } from "vitest";
import { sendAlerts, type Destination } from "./destinations.js";

function makeApi(opts: { wa?: ReturnType<typeof vi.fn>; tg?: ReturnType<typeof vi.fn>; dc?: ReturnType<typeof vi.fn> } = {}) {
  return {
    logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
    runtime: {
      channel: {
        whatsapp: { sendMessageWhatsApp: opts.wa ?? vi.fn().mockResolvedValue({}) },
        telegram: { sendMessageTelegram: opts.tg ?? vi.fn().mockResolvedValue({}) },
        discord: { sendMessageDiscord: opts.dc ?? vi.fn().mockResolvedValue({}) },
      },
    },
  };
}

const wa: Destination = { channel: "whatsapp", accountId: "default", to: "+51999" };
const tg: Destination = { channel: "telegram", accountId: "default", to: "8416955510" };
const dc: Destination = { channel: "discord", accountId: "default", to: "channel-id-42" };

describe("sendAlerts", () => {
  beforeEach(() => vi.clearAllMocks());

  it("sends to a WhatsApp destination", async () => {
    const api = makeApi() as any;
    const result = await sendAlerts(api, [wa], "hello");
    expect(api.runtime.channel.whatsapp.sendMessageWhatsApp).toHaveBeenCalledWith("+51999", "hello", expect.any(Object));
    expect(result.successCount).toBe(1);
  });

  it("sends to a Telegram destination", async () => {
    const api = makeApi() as any;
    await sendAlerts(api, [tg], "hello");
    expect(api.runtime.channel.telegram.sendMessageTelegram).toHaveBeenCalledWith("8416955510", "hello", expect.any(Object));
  });

  it("sends to a Discord destination", async () => {
    const api = makeApi() as any;
    await sendAlerts(api, [dc], "hello");
    expect(api.runtime.channel.discord.sendMessageDiscord).toHaveBeenCalledWith("channel-id-42", "hello", expect.any(Object));
  });

  it("fans out to multiple destinations in parallel", async () => {
    const api = makeApi() as any;
    const result = await sendAlerts(api, [wa, tg], "hi");
    expect(result.successCount).toBe(2);
    expect(result.total).toBe(2);
  });

  it("one fails, another succeeds, successCount=1", async () => {
    const api = makeApi({
      wa: vi.fn().mockRejectedValue(new Error("WA offline")),
      tg: vi.fn().mockResolvedValue({}),
    }) as any;
    const result = await sendAlerts(api, [wa, tg], "hi");
    expect(result.successCount).toBe(1);
    expect(result.total).toBe(2);
  });

  it("all fail → successCount=0, does not throw", async () => {
    const api = makeApi({
      wa: vi.fn().mockRejectedValue(new Error("x")),
      tg: vi.fn().mockRejectedValue(new Error("y")),
    }) as any;
    const result = await sendAlerts(api, [wa, tg], "hi");
    expect(result.successCount).toBe(0);
  });

  it("unknown channel logs warn and counts as failure", async () => {
    const api = makeApi() as any;
    const result = await sendAlerts(api, [{ channel: "carrier-pigeon", to: "wing-42" } as Destination], "hi");
    expect(api.logger.warn).toHaveBeenCalled();
    expect(result.successCount).toBe(0);
  });
});
