import { describe, expect, it } from 'vitest';
import { NotificationsService } from '../application/notifications-service.js';
import type { EmailProvider, NotificationsRepository } from '../domain/ports.js';
import type { EmailMessage } from '../domain/notification.js';

function repo(overrides: Partial<NotificationsRepository> = {}): NotificationsRepository {
  return {
    findByEventId: async () => undefined,
    record: async () => ({ created: true }),
    ...overrides,
  };
}

function provider(sent: EmailMessage[]): EmailProvider {
  return {
    send: async (message) => {
      sent.push(message);
    },
  };
}

describe('NotificationsService', () => {
  it('sends the email on first event and duplicate on replay (AC1/AC2)', async () => {
    const sent: EmailMessage[] = [];
    const repository: NotificationsRepository = {
      findByEventId: async () => undefined,
      record: async () => ({ created: true }),
    };
    const service = new NotificationsService(repository, provider(sent));
    const message: EmailMessage = {
      eventId: 'evt-1',
      template: 'order_confirmation',
      recipient: 'a@example.com',
      subject: 'subject',
      body: 'body',
    };
    const first = await service.dispatch(message);
    expect(first).toBe('sent');
    // Now simulate replay: findByEventId returns a record.
    const replayService = new NotificationsService(
      {
        findByEventId: async () => ({
          template: message.template,
          recipient: message.recipient,
          status: 'sent',
        }),
        record: async () => ({ created: true }),
      },
      provider(sent),
    );
    const second = await replayService.dispatch(message);
    expect(second).toBe('duplicate');
    expect(sent).toHaveLength(1);
  });

  it('returns duplicate when repository record returns created=false', async () => {
    const sent: EmailMessage[] = [];
    const service = new NotificationsService(
      repo({ record: async () => ({ created: false }) }),
      provider(sent),
    );
    const outcome = await service.dispatch({
      eventId: 'evt-2',
      template: 'payment_failed',
      recipient: 'b@example.com',
      subject: 's',
      body: 'b',
    });
    expect(outcome).toBe('duplicate');
    expect(sent).toHaveLength(0);
  });
});
