import { describe, it, expect, beforeEach } from "vitest";
import { BootstrapSesInfraUseCase, SesInfraBootstrapper } from "./bootstrap-ses-infra-use-case";

class InMemorySesInfraBootstrapper implements SesInfraBootstrapper {
  public configurationSets: string[] = [];
  public topics = new Map<string, string>();
  public permissionsGranted: string[] = [];
  public subscriptions: Array<{ topicArn: string; endpoint: string }> = [];
  public eventDestinations: Array<{ configurationSetName: string; topicArn: string }> = [];

  async ensureConfigurationSet(name: string): Promise<void> {
    if (!this.configurationSets.includes(name)) this.configurationSets.push(name);
  }

  async ensureSnsTopic(name: string): Promise<string> {
    if (!this.topics.has(name)) this.topics.set(name, `arn:aws:sns:us-east-1:123:${name}`);
    return this.topics.get(name)!;
  }

  async ensureTopicPublishPermission(topicArn: string): Promise<void> {
    this.permissionsGranted.push(topicArn);
  }

  async ensureHttpsSubscription(topicArn: string, endpoint: string): Promise<void> {
    this.subscriptions.push({ topicArn, endpoint });
  }

  async ensureEventDestination(configurationSetName: string, topicArn: string): Promise<void> {
    this.eventDestinations.push({ configurationSetName, topicArn });
  }
}

let infra: InMemorySesInfraBootstrapper;
let sut: BootstrapSesInfraUseCase;

describe("Bootstrap SES Infra Use Case", () => {
  beforeEach(() => {
    infra = new InMemorySesInfraBootstrapper();
    sut = new BootstrapSesInfraUseCase(infra);
  });

  it("should provision the configuration set, topic, permission, subscription and event destination", async () => {
    const result = await sut.execute({
      configurationSetName: "newsletter-platform-default",
      snsTopicName: "newsletter-platform-ses-events",
      webhookEndpoint: "https://app.example.com/api/webhooks/ses",
    });

    expect(infra.configurationSets).toContain("newsletter-platform-default");
    expect(result.topicArn).toEqual(infra.topics.get("newsletter-platform-ses-events"));
    expect(infra.permissionsGranted).toContain(result.topicArn);
    expect(infra.subscriptions).toEqual([
      { topicArn: result.topicArn, endpoint: "https://app.example.com/api/webhooks/ses" },
    ]);
    expect(infra.eventDestinations).toEqual([
      { configurationSetName: "newsletter-platform-default", topicArn: result.topicArn },
    ]);
  });

  it("should be idempotent across repeated runs", async () => {
    const request = {
      configurationSetName: "newsletter-platform-default",
      snsTopicName: "newsletter-platform-ses-events",
      webhookEndpoint: "https://app.example.com/api/webhooks/ses",
    };

    await sut.execute(request);
    await sut.execute(request);

    expect(infra.configurationSets).toEqual(["newsletter-platform-default"]);
    expect(infra.topics.size).toEqual(1);
  });
});
