import { describe, it, expect, beforeEach } from "vitest";
import { InMemoryCampaignsRepository } from "../repositories/in-memory-campaigns-repository";
import { InMemoryEmailEventsRepository } from "@/modules/ses-webhooks/repositories/in-memory-email-events-repository";
import { GetCampaignByIdUseCase } from "./get-campaign-by-id-use-case";
import { AppError } from "@/core/errors/app-error";

let campaignsRepository: InMemoryCampaignsRepository;
let emailEventsRepository: InMemoryEmailEventsRepository;
let sut: GetCampaignByIdUseCase;

describe("Get Campaign By Id Use Case", () => {
  beforeEach(() => {
    campaignsRepository = new InMemoryCampaignsRepository();
    emailEventsRepository = new InMemoryEmailEventsRepository();
    sut = new GetCampaignByIdUseCase(campaignsRepository, emailEventsRepository);
  });

  it("should be able to get campaign details by id", async () => {
    const created = await campaignsRepository.create({
      title: "Test Campaign",
      subject: "Subject",
      htmlBody: "<p>HTML</p>",
      createdById: "user-1",
    });

    const { campaign, summary, opens } = await sut.execute({ id: created.id, userId: "user-1" });

    expect(campaign.id).toEqual(created.id);
    expect(summary.total).toEqual(0);
    expect(opens.total).toEqual(0);
    expect(opens.unique).toEqual(0);
    expect(opens.rate).toEqual(0);
    expect(opens.openers).toEqual([]);
    expect(opens.timeline).toEqual([]);
  });

  it("should compute open stats and rate from email events", async () => {
    const created = await campaignsRepository.create({
      title: "Test Campaign",
      subject: "Subject",
      htmlBody: "<p>HTML</p>",
      createdById: "user-1",
    });

    const campaignWithLogs = await campaignsRepository.findByIdWithLogsAndSender(created.id);
    if (campaignWithLogs) {
      campaignWithLogs.logs = [
        {
          id: "log-1",
          status: "SUCCESS",
          sentAt: new Date(),
          errorMessage: null,
          retryCount: 0,
          messageId: null,
          campaignId: created.id,
          contactId: "contact-1",
          createdAt: new Date(),
          updatedAt: new Date(),
          contact: { id: "contact-1", email: "contato@example.com", name: "Contato" },
        },
      ];
    }
    campaignsRepository.findByIdWithLogsAndSender = async () => campaignWithLogs;

    await emailEventsRepository.create({
      type: "OPEN",
      messageId: "msg-1",
      campaignId: created.id,
      contactId: "contact-1",
      payload: {},
    });

    const { summary, opens } = await sut.execute({ id: created.id, userId: "user-1" });

    expect(summary.success).toEqual(1);
    expect(opens.total).toEqual(1);
    expect(opens.unique).toEqual(1);
    expect(opens.rate).toEqual(100);
    expect(opens.openers).toHaveLength(1);
    expect(opens.openers[0].email).toEqual("contato@example.com");
  });

  it("should not allow getting another user's campaign", async () => {
    const created = await campaignsRepository.create({
      title: "Test Campaign",
      subject: "Subject",
      htmlBody: "<p>HTML</p>",
      createdById: "user-1",
    });

    await expect(sut.execute({ id: created.id, userId: "user-2" })).rejects.toBeInstanceOf(AppError);
  });
});
