/**
 * S9-002..004 money input validation regression tests.
 */
import { describe, it, expect } from 'vitest'
import {
  resolvePayoutBillLineTotal,
  PayoutBillConflictError,
} from '../../src/queries/contractors'
import {
  deriveStandaloneReceiptAmount,
  assertStandaloneReceiptAmount,
  ReceiptConflictError,
} from '../../src/queries/receipts'
import { invoiceLineSchema, creditNoteLineInputSchema } from '../../src/queries/invoices'

describe('S9-002 resolvePayoutBillLineTotal', () => {
  it('recomputes hourly line total from hours×rate', () => {
    expect(
      resolvePayoutBillLineTotal({ hours: '10.00', rate: '150.00', lineTotal: '1500.00' }),
    ).toBe('1500.00')
  })

  it('rejects inflated client lineTotal on hourly lines', () => {
    expect(() =>
      resolvePayoutBillLineTotal({ hours: '10.00', rate: '150.00', lineTotal: '999999.00' }),
    ).toThrow(PayoutBillConflictError)
  })

  it('allows fixed-fee lines within contractor agreed amount', () => {
    expect(
      resolvePayoutBillLineTotal(
        { lineTotal: '500.00' },
        { billingType: 'fixed', agreedAmount: 500, hourlyLinesTotal: 0 },
      ),
    ).toBe('500.00')
  })

  it('passes through uncapped fixed-fee lines when contractor has no agreed amount', () => {
    expect(
      resolvePayoutBillLineTotal(
        { lineTotal: '999999.00' },
        { billingType: 'fixed', agreedAmount: null, hourlyLinesTotal: 0 },
      ),
    ).toBe('999999.00')
  })

  it('rejects inflated fixed-fee lines (S9-i2-001)', () => {
    expect(() =>
      resolvePayoutBillLineTotal(
        { lineTotal: '999999.00' },
        { billingType: 'fixed', agreedAmount: 500, hourlyLinesTotal: 0 },
      ),
    ).toThrow(PayoutBillConflictError)
  })

  it('rejects partial hours/rate pair', () => {
    expect(() =>
      resolvePayoutBillLineTotal({ hours: '5.00', lineTotal: '500.00' }),
    ).toThrow(PayoutBillConflictError)
  })
})

describe('S9-003 standalone receipt amount validation', () => {
  const invoice = { total: '1000.00', amountPaid: '0' }

  it('derives amount from outstanding balance when no payment links', () => {
    expect(
      deriveStandaloneReceiptAmount(invoice, [{ amount: '1000.00' }], new Map()),
    ).toBe(1000)
  })

  it('rejects receipt when invoice has no outstanding balance', () => {
    expect(() =>
      deriveStandaloneReceiptAmount(
        { total: '1000.00', amountPaid: '1000.00' },
        [{ amount: '1.00' }],
        new Map(),
      ),
    ).toThrow(ReceiptConflictError)
  })

  it('uses linked payment amounts when invoicePaymentId is set', () => {
    const payments = new Map([['pay-1', '250.00']])
    expect(
      deriveStandaloneReceiptAmount(
        invoice,
        [{ amount: '250.00', invoicePaymentId: 'pay-1' }],
        payments,
      ),
    ).toBe(250)
  })

  it('rejects client amount mismatch', () => {
    expect(() =>
      assertStandaloneReceiptAmount('1.00', 1000, [{ amount: '1.00' }]),
    ).toThrow(ReceiptConflictError)
  })

  it('rejects payment lines sum mismatch', () => {
    expect(() =>
      assertStandaloneReceiptAmount('1000.00', 1000, [{ amount: '1.00' }]),
    ).toThrow(ReceiptConflictError)
  })
})

describe('S9-004 invoice line unitPrice validation', () => {
  it('rejects negative unitPrice on standard invoice lines', () => {
    const result = invoiceLineSchema.safeParse({
      description: 'Bad line',
      quantity: 1,
      unitPrice: -5000,
      position: 0,
    })
    expect(result.success).toBe(false)
  })

  it('accepts non-negative unitPrice on standard invoice lines', () => {
    const result = invoiceLineSchema.safeParse({
      description: 'Good line',
      quantity: 1,
      unitPrice: 100,
      position: 0,
    })
    expect(result.success).toBe(true)
  })

  it('preserves credit-note negative quantity flow', () => {
    const result = creditNoteLineInputSchema.safeParse({
      description: 'Credit',
      quantity: -1,
      unitPrice: 3500,
    })
    expect(result.success).toBe(true)
  })
})
