import { describe, it, expect } from 'vitest';
import { BillingViewModel, PaymentMethodViewModel, InvoiceViewModel, BillingStatsViewModel } from './BillingViewModel';

describe('BillingViewModel', () => {
  it('maps arrays of payment methods, invoices and stats into view models', () => {
    const data = {
      paymentMethods: [
        { id: 'pm-1', type: 'card', last4: '4242', brand: 'Visa', isDefault: true, expiryMonth: 12, expiryYear: 2030 },
      ],
      invoices: [
        {
          id: 'inv-1',
          invoiceNumber: 'INV-1',
          date: '2024-01-01',
          dueDate: '2024-02-01',
          amount: 100,
          vatAmount: 19,
          totalAmount: 119,
          status: 'pending',
          description: 'Sponsorship',
          sponsorshipType: 'league',
          pdfUrl: 'https://example.com/invoice.pdf',
        },
      ],
      stats: {
        totalSpent: 1000,
        pendingAmount: 200,
        nextPaymentDate: '2024-03-01',
        nextPaymentAmount: 50,
        activeSponsorships: 3,
        averageMonthlySpend: 250,
      },
    } as any;

    const vm = new BillingViewModel(data);

    expect(vm.paymentMethods).toHaveLength(1);
    expect(vm.paymentMethods[0]).toBeInstanceOf(PaymentMethodViewModel);
    expect(vm.invoices).toHaveLength(1);
    expect(vm.invoices[0]).toBeInstanceOf(InvoiceViewModel);
    expect(vm.stats).toBeInstanceOf(BillingStatsViewModel);
  });
});

describe('PaymentMethodViewModel', () => {
  it('builds displayLabel based on type and bankName/brand', () => {
    const card = new PaymentMethodViewModel({
      id: 'pm-1',
      type: 'card',
      last4: '4242',
      brand: 'Visa',
      isDefault: true,
    });

    const sepa = new PaymentMethodViewModel({
      id: 'pm-2',
      type: 'sepa',
      last4: '1337',
      bankName: 'Test Bank',
      isDefault: false,
    });

    expect(card.displayLabel).toBe('Visa •••• 4242');
    expect(sepa.displayLabel).toBe('Test Bank •••• 1337');
  });

  it('returns expiryDisplay when month and year are provided', () => {
    const withExpiry = new PaymentMethodViewModel({
      id: 'pm-1',
      type: 'card',
      last4: '4242',
      brand: 'Visa',
      isDefault: true,
      expiryMonth: 3,
      expiryYear: 2030,
    });

    const withoutExpiry = new PaymentMethodViewModel({
      id: 'pm-2',
      type: 'card',
      last4: '9999',
      brand: 'Mastercard',
      isDefault: false,
    });

    expect(withExpiry.expiryDisplay).toBe('03/2030');
    expect(withoutExpiry.expiryDisplay).toBeNull();
  });
});

describe('InvoiceViewModel', () => {
  it('formats monetary amounts and dates', () => {
    const dto = {
      id: 'inv-1',
      invoiceNumber: 'INV-1',
      date: '2024-01-15',
      dueDate: '2024-02-01',
      amount: 100,
      vatAmount: 19,
      totalAmount: 119,
      status: 'paid',
      description: 'Sponsorship',
      sponsorshipType: 'league',
      pdfUrl: 'https://example.com/invoice.pdf',
    } as any;

    const vm = new InvoiceViewModel(dto);

    expect(vm.formattedTotalAmount).toBe(`€${(119).toLocaleString('de-DE', { minimumFractionDigits: 2 })}`);
    expect(vm.formattedVatAmount).toBe(`€${(19).toLocaleString('de-DE', { minimumFractionDigits: 2 })}`);
    expect(typeof vm.formattedDate).toBe('string');
  });

  it('detects overdue when status is overdue or pending past due date', () => {
    const now = new Date();
    const pastDate = new Date(now.getTime() - 24 * 60 * 60 * 1000).toISOString();
    const futureDate = new Date(now.getTime() + 24 * 60 * 60 * 1000).toISOString();

    const overdue = new InvoiceViewModel({
      id: 'inv-1',
      invoiceNumber: 'INV-1',
      date: pastDate,
      dueDate: pastDate,
      amount: 0,
      vatAmount: 0,
      totalAmount: 0,
      status: 'overdue',
      description: '',
      sponsorshipType: 'league',
      pdfUrl: '',
    } as any);

    const pendingPastDue = new InvoiceViewModel({
      id: 'inv-2',
      invoiceNumber: 'INV-2',
      date: pastDate,
      dueDate: pastDate,
      amount: 0,
      vatAmount: 0,
      totalAmount: 0,
      status: 'pending',
      description: '',
      sponsorshipType: 'league',
      pdfUrl: '',
    } as any);

    const pendingFuture = new InvoiceViewModel({
      id: 'inv-3',
      invoiceNumber: 'INV-3',
      date: pastDate,
      dueDate: futureDate,
      amount: 0,
      vatAmount: 0,
      totalAmount: 0,
      status: 'pending',
      description: '',
      sponsorshipType: 'league',
      pdfUrl: '',
    } as any);

    expect(overdue.isOverdue).toBe(true);
    expect(pendingPastDue.isOverdue).toBe(true);
    expect(pendingFuture.isOverdue).toBe(false);
  });
});

describe('BillingStatsViewModel', () => {
  it('formats monetary fields and next payment date', () => {
    const dto = {
      totalSpent: 1234,
      pendingAmount: 56.78,
      nextPaymentDate: '2024-03-01',
      nextPaymentAmount: 42,
      activeSponsorships: 2,
      averageMonthlySpend: 321,
    } as any;

    const vm = new BillingStatsViewModel(dto);

    expect(vm.formattedTotalSpent).toBe(`€${(1234).toLocaleString('de-DE')}`);
    expect(vm.formattedPendingAmount).toBe(`€${(56.78).toLocaleString('de-DE', { minimumFractionDigits: 2 })}`);
    expect(vm.formattedNextPaymentAmount).toBe(`€${(42).toLocaleString('de-DE', { minimumFractionDigits: 2 })}`);
    expect(vm.formattedAverageMonthlySpend).toBe(`€${(321).toLocaleString('de-DE')}`);
    expect(typeof vm.formattedNextPaymentDate).toBe('string');
  });
});
