import { describe, expect, it } from 'vitest';
import { PricingService } from '../application/pricing-service.js';
import { InvalidPriceError, PriceNotFoundError } from '../domain/errors.js';
import type { PricingRepository } from '../domain/ports.js';
import type { SetVariantPriceCommand, VariantPrice } from '../domain/price.js';

const PRICE: VariantPrice = {
  variantId: 'variant-1',
  netUnitAmountCents: 1000,
  offerCents: null,
  costCents: null,
  vatRate: 'general',
  currency: 'EUR',
  createdAt: new Date('2026-01-01T00:00:00Z'),
  updatedAt: new Date('2026-01-01T00:00:00Z'),
};

function repository(overrides: Partial<PricingRepository> = {}): PricingRepository {
  return {
    findByVariantId: async () => PRICE,
    setVariantPrice: async (_input: SetVariantPriceCommand) => PRICE,
    seedVariantPrice: async () => undefined,
    ...overrides,
  };
}

describe('PricingService', () => {
  it('calculates general VAT totals from server-side price (AC1)', async () => {
    const service = new PricingService(repository());

    await expect(service.calculate({ variantId: 'variant-1', quantity: 2 })).resolves.toEqual({
      variantId: 'variant-1',
      quantity: 2,
      currency: 'EUR',
      vatRate: 'general',
      vatBasisPoints: 2100,
      netUnitAmountCents: 1000,
      netSubtotalCents: 2000,
      vatAmountCents: 420,
      totalCents: 2420,
    });
  });

  it('calculates reduced VAT totals', async () => {
    const service = new PricingService(
      repository({ findByVariantId: async () => ({ ...PRICE, vatRate: 'reduced' }) }),
    );

    await expect(service.calculate({ variantId: 'variant-1', quantity: 3 })).resolves.toMatchObject(
      {
        vatRate: 'reduced',
        vatBasisPoints: 1000,
        netSubtotalCents: 3000,
        vatAmountCents: 300,
        totalCents: 3300,
      },
    );
  });

  it('rejects invalid quantities and amounts', async () => {
    const service = new PricingService(repository());

    await expect(service.calculate({ variantId: 'variant-1', quantity: 0 })).rejects.toBeInstanceOf(
      InvalidPriceError,
    );
    await expect(
      service.setVariantPrice({
        variantId: 'variant-1',
        netUnitAmountCents: -1,
        vatRate: 'general',
      }),
    ).rejects.toBeInstanceOf(InvalidPriceError);
  });

  it('fails calculation when the variant has no server-side price', async () => {
    const service = new PricingService(repository({ findByVariantId: async () => undefined }));

    await expect(service.calculate({ variantId: 'variant-1', quantity: 1 })).rejects.toBeInstanceOf(
      PriceNotFoundError,
    );
  });
});
