import { describe, expect, it } from 'vitest';
import { PaymentsService } from '../application/payments-service.js';
import type { PaymentRepository } from '../domain/ports.js';
import type { PaymentEvent, PaymentTransaction } from '../domain/payment.js';
import type { OrderServicePort, OrderState, OrderView } from '../../orders/index.js';

const TRANSACTION: PaymentTransaction = {
  id: 'pt-1',
  provider: 'stripe',
  providerEventId: 'evt-1',
  providerPaymentId: 'pi-1',
  orderId: 'order-1',
  amountCents: 1210,
  currency: 'EUR',
  status: 'succeeded',
  createdAt: new Date(),
};

function _repo(overrides: Partial<PaymentRepository> = {}): PaymentRepository {
  return {
    findByProviderEvent: async () => undefined,
    recordEvent: async () => TRANSACTION,
    listByOrderId: async () => [TRANSACTION],
    ...overrides,
  };
}

describe('PaymentsService', () => {
  it('returns processed on first event and duplicate on replay (AC3)', async () => {
    const orderService: OrderServicePort = {
      create: async () => {
        throw new Error('not used');
      },
      listOrders: async () => [],
      transition: async (_id, state) =>
        ({
          id: 'order-1',
          userId: 'user-1',
          state: state as OrderState,
          currency: 'EUR',
          idempotencyKey: null,
          subtotalCents: 1210,
          discountCents: 0,
          taxCents: 210,
          totalCents: 1210,
          createdAt: new Date(),
          updatedAt: new Date(),
          items: [],
        }) satisfies OrderView,
      getOrder: async () => undefined,
      getOrderAdmin: async () => undefined,
      transitionAdmin: async () => {
        throw new Error('not used');
      },
    };
    let recorded = 0;
    let seen = 0;
    const events = { emit: async () => undefined };
    const repository: PaymentRepository = {
      findByProviderEvent: async () => {
        seen += 1;
        if (seen > 1) return TRANSACTION;
        return undefined;
      },
      recordEvent: async () => {
        recorded += 1;
        if (recorded > 1) return undefined;
        return TRANSACTION;
      },
      listByOrderId: async () => [TRANSACTION],
    };
    const service = new PaymentsService({
      repository,
      orders: orderService,
      events,
      provider: 'stripe',
    });
    const event: PaymentEvent = {
      providerEventId: 'evt-1',
      providerPaymentId: 'pi-1',
      orderId: 'order-1',
      amountCents: 1210,
      currency: 'EUR',
      status: 'succeeded',
      type: 'PaymentSucceeded',
      raw: {},
    };
    const first = await service.handleWebhook(event);
    expect(first.kind).toBe('processed');
    const second = await service.handleWebhook(event);
    expect(second.kind).toBe('duplicate');
    expect(recorded).toBe(1);
  });
});
