import { describe, it, expect } from 'vitest';
import { formatUSD, formatUSDWhole, formatCentsUSD, validateNonNegativeMoney } from './money';

describe('validateNonNegativeMoney', () => {
  it('allows blank and zero (non-negative, not strictly positive)', () => {
    expect(validateNonNegativeMoney('')).toBe('');
    expect(validateNonNegativeMoney(null)).toBe('');
    expect(validateNonNegativeMoney(undefined)).toBe('');
    expect(validateNonNegativeMoney('0')).toBe('');
    expect(validateNonNegativeMoney('12.50')).toBe('');
  });

  it('rejects negatives and non-numeric with a labelled message', () => {
    expect(validateNonNegativeMoney('-1', 'Amount')).toBe('Amount must be a non-negative number');
    expect(validateNonNegativeMoney('abc', 'Balance')).toBe('Balance must be a non-negative number');
    expect(validateNonNegativeMoney('-0.01', 'Min payment')).toBe('Min payment must be a non-negative number');
  });
});

describe('formatUSD (dollars in)', () => {
  it('formats to two decimals with grouping', () => {
    expect(formatUSD(1234.5)).toBe('$1,234.50');
    expect(formatUSD(0)).toBe('$0.00');
    expect(formatUSD(8.99)).toBe('$8.99');
  });

  it('formats negatives', () => {
    expect(formatUSD(-12.34)).toBe('-$12.34');
  });

  it('normalizes negative zero to "$0.00" (not "-$0.00")', () => {
    expect(formatUSD(-0)).toBe('$0.00');
    expect(formatUSD(Math.round(-0.2))).toBe('$0.00'); // Math.round(-0.2) === -0
  });

  it('coerces blank / non-numeric to $0.00 (never NaN)', () => {
    expect(formatUSD(null)).toBe('$0.00');
    expect(formatUSD(undefined)).toBe('$0.00');
    expect(formatUSD('')).toBe('$0.00');
    expect(formatUSD('not a number')).toBe('$0.00');
  });

  it('accepts numeric strings', () => {
    expect(formatUSD('1234.5')).toBe('$1,234.50');
  });

  it('whole:true drops the cents', () => {
    expect(formatUSD(1234.56, { whole: true })).toBe('$1,235');
    expect(formatUSDWhole(1234.4)).toBe('$1,234');
  });

  it('dash:true renders blank input as an em dash, but 0 as $0.00', () => {
    expect(formatUSD(null, { dash: true })).toBe('—');
    expect(formatUSD(undefined, { dash: true })).toBe('—');
    expect(formatUSD('', { dash: true })).toBe('—');
    expect(formatUSD(0, { dash: true })).toBe('$0.00');
  });
});

describe('formatCentsUSD (integer cents in)', () => {
  it('converts cents to dollars', () => {
    expect(formatCentsUSD(1234)).toBe('$12.34');
    expect(formatCentsUSD(0)).toBe('$0.00');
    expect(formatCentsUSD(99)).toBe('$0.99');
  });

  it('unsigned negatives get a leading minus only', () => {
    expect(formatCentsUSD(-1234)).toBe('-$12.34');
  });

  it('signed:true adds +/- for income vs expense', () => {
    expect(formatCentsUSD(1234, { signed: true })).toBe('+$12.34');
    expect(formatCentsUSD(-1234, { signed: true })).toBe('-$12.34');
    expect(formatCentsUSD(0, { signed: true })).toBe('+$0.00');
  });

  it('dash:true renders blank input as an em dash', () => {
    expect(formatCentsUSD(null, { dash: true })).toBe('—');
    expect(formatCentsUSD(undefined, { dash: true })).toBe('—');
    expect(formatCentsUSD(0, { dash: true })).toBe('$0.00');
  });

  it('coerces non-numeric to $0.00 (never NaN)', () => {
    expect(formatCentsUSD('abc')).toBe('$0.00');
    expect(formatCentsUSD(null)).toBe('$0.00');
  });
});
