import { describe, expect, it } from 'vitest';
import { isBalanced, parseAmount, validateDates, validateEntityBalance, validateForeignCurrency, validateLedgerRecords, validateNoOrphanedAmounts, validatePositiveAmounts, validateRecordInternalBalance, } from './ledger-validators.js';
const mockContext = {
    useCaseId: 'test-case',
    defaultCurrency: 'ILS',
    tolerance: 0.005,
};
function createMockRecord(overrides = {}) {
    return {
        id: 'rec-1',
        charge_id: 'charge-1',
        owner_id: 'owner-1',
        debit_entity1: null,
        debit_local_amount1: null,
        debit_foreign_amount1: null,
        debit_entity2: null,
        debit_local_amount2: null,
        debit_foreign_amount2: null,
        credit_entity1: null,
        credit_local_amount1: null,
        credit_foreign_amount1: null,
        credit_entity2: null,
        credit_local_amount2: null,
        credit_foreign_amount2: null,
        currency: 'ILS',
        invoice_date: new Date('2024-01-01'),
        value_date: new Date('2024-01-01'),
        description: null,
        reference1: null,
        locked: false,
        ...overrides,
    };
}
describe('parseAmount', () => {
    it('should parse valid number strings', () => {
        expect(parseAmount('100.50')).toBe(100.5);
        expect(parseAmount('0')).toBe(0);
    });
    it('should handle null and undefined', () => {
        expect(parseAmount(null)).toBe(0);
        expect(parseAmount(undefined)).toBe(0);
    });
    it('should handle invalid strings', () => {
        expect(parseAmount('invalid')).toBe(0);
        expect(parseAmount('')).toBe(0);
    });
});
describe('isBalanced', () => {
    it('should return true for equal values', () => {
        expect(isBalanced(100, 100)).toBe(true);
    });
    it('should return true for values within tolerance', () => {
        expect(isBalanced(100, 100.005, 0.005)).toBe(true);
    });
    it('should return false for values outside tolerance', () => {
        expect(isBalanced(100, 102, 0.005)).toBe(false);
    });
});
describe('validateRecordInternalBalance', () => {
    it('should pass for balanced record', () => {
        const record = createMockRecord({
            debit_entity1: 'entity-1',
            debit_local_amount1: '100.00',
            credit_entity1: 'entity-2',
            credit_local_amount1: '100.00',
        });
        const errors = validateRecordInternalBalance([record], mockContext);
        expect(errors).toHaveLength(0);
    });
    it('should fail for unbalanced record', () => {
        const record = createMockRecord({
            debit_local_amount1: '100.00',
            credit_local_amount1: '99.00',
        });
        const errors = validateRecordInternalBalance([record], mockContext);
        expect(errors).toHaveLength(1);
        expect(errors[0]).toContain('internal imbalance');
        expect(errors[0]).toContain('debit=100.00');
        expect(errors[0]).toContain('credit=99.00');
    });
    it('should detect empty records', () => {
        const record = createMockRecord({
        // All amounts null/zero
        });
        const errors = validateRecordInternalBalance([record], mockContext);
        expect(errors.length).toBeGreaterThan(0);
        expect(errors[0]).toContain('empty record');
    });
});
describe('validateEntityBalance', () => {
    it('should pass when all entities balance to zero', () => {
        const records = [
            createMockRecord({
                debit_entity1: 'entity-1',
                debit_local_amount1: '100.00',
                credit_entity1: 'entity-2',
                credit_local_amount1: '100.00',
            }),
            createMockRecord({
                id: 'rec-2',
                debit_entity1: 'entity-2',
                debit_local_amount1: '100.00',
                credit_entity1: 'entity-1',
                credit_local_amount1: '100.00',
            }),
        ];
        const errors = validateEntityBalance(records, mockContext);
        expect(errors).toHaveLength(0);
    });
    it('should fail when entity has unbalanced position', () => {
        const record = createMockRecord({
            debit_entity1: 'entity-1',
            debit_local_amount1: '100.00',
            credit_entity1: 'entity-2',
            credit_local_amount1: '100.00',
        });
        const errors = validateEntityBalance([record], mockContext);
        expect(errors.length).toBeGreaterThan(0);
        expect(errors[0]).toContain('unbalanced');
        expect(errors[0]).toContain('entity-1');
    });
});
describe('validateNoOrphanedAmounts', () => {
    it('should fail when amount exists without entity', () => {
        const record = createMockRecord({
            debit_entity1: null,
            debit_local_amount1: '100.00',
        });
        const errors = validateNoOrphanedAmounts([record], mockContext);
        expect(errors.length).toBeGreaterThan(0);
        expect(errors[0]).toContain('orphaned amount');
    });
    it('should pass when amounts have entities', () => {
        const record = createMockRecord({
            debit_entity1: 'entity-1',
            debit_local_amount1: '100.00',
            credit_entity1: 'entity-2',
            credit_local_amount1: '100.00',
        });
        const errors = validateNoOrphanedAmounts([record], mockContext);
        expect(errors).toHaveLength(0);
    });
});
describe('validatePositiveAmounts', () => {
    it('should fail for negative amounts', () => {
        const record = createMockRecord({
            debit_local_amount1: '-100.00',
        });
        const errors = validatePositiveAmounts([record], mockContext);
        expect(errors.length).toBeGreaterThan(0);
        expect(errors[0]).toContain('negative amount');
    });
    it('should pass for positive amounts', () => {
        const record = createMockRecord({
            debit_local_amount1: '100.00',
            credit_local_amount1: '100.00',
        });
        const errors = validatePositiveAmounts([record], mockContext);
        expect(errors).toHaveLength(0);
    });
});
describe('validateForeignCurrency', () => {
    it('should require foreign amounts for non-ILS currency', () => {
        const record = createMockRecord({
            currency: 'USD',
            debit_local_amount1: '350.00',
            debit_foreign_amount1: null,
        });
        const errors = validateForeignCurrency([record], mockContext);
        expect(errors.length).toBeGreaterThan(0);
        expect(errors[0]).toContain('no foreign amounts');
    });
    it('should reject foreign amounts for ILS currency', () => {
        const record = createMockRecord({
            currency: 'ILS',
            debit_local_amount1: '100.00',
            debit_foreign_amount1: '100.00',
        });
        const errors = validateForeignCurrency([record], mockContext);
        expect(errors.length).toBeGreaterThan(0);
        expect(errors[0]).toContain('has foreign amounts');
    });
    it('should detect suspicious exchange rates', () => {
        const record = createMockRecord({
            currency: 'USD',
            debit_local_amount1: '1000.00',
            debit_foreign_amount1: '10.00', // Rate = 100
        });
        const errors = validateForeignCurrency([record], mockContext);
        expect(errors.length).toBeGreaterThan(0);
        expect(errors[0]).toContain('suspicious exchange rate');
    });
});
describe('validateDates', () => {
    it('should fail for missing dates', () => {
        const record = createMockRecord({
            invoice_date: null,
        });
        const errors = validateDates([record], mockContext);
        expect(errors.length).toBeGreaterThan(0);
        expect(errors[0]).toContain('missing invoice_date');
    });
    it('should fail for dates out of range', () => {
        const record = createMockRecord({
            invoice_date: new Date('1999-01-01'),
        });
        const errors = validateDates([record], mockContext);
        expect(errors.length).toBeGreaterThan(0);
        expect(errors[0]).toContain('out of range');
    });
});
describe('validateLedgerRecords', () => {
    it('should pass when all validations succeed', () => {
        // Create two records that balance entities:
        // Record 1: entity-1 debits 100, entity-2 credits 100
        // Record 2: entity-1 credits 100, entity-2 debits 100
        // This ensures each entity has equal debits and credits
        const record1 = createMockRecord({
            debit_entity1: 'entity-1',
            debit_local_amount1: '100.00',
            credit_entity1: 'entity-2',
            credit_local_amount1: '100.00',
        });
        const record2 = createMockRecord({
            debit_entity1: 'entity-2',
            debit_local_amount1: '100.00',
            credit_entity1: 'entity-1',
            credit_local_amount1: '100.00',
        });
        const errors = validateLedgerRecords([record1, record2], 2, mockContext);
        expect(errors).toHaveLength(0);
    });
    it('should collect errors from multiple validators', () => {
        const record = createMockRecord({
            debit_local_amount1: '100.00',
            credit_local_amount1: '99.00', // Imbalance
            debit_entity1: null, // Orphaned amount
            invoice_date: null, // Missing date
        });
        const errors = validateLedgerRecords([record], 1, mockContext);
        expect(errors.length).toBeGreaterThan(1); // Multiple errors
        expect(errors.some(e => e.includes('imbalance'))).toBe(true);
        expect(errors.some(e => e.includes('orphaned'))).toBe(true);
        expect(errors.some(e => e.includes('missing invoice_date'))).toBe(true);
    });
});
//# sourceMappingURL=ledger-validators.test.js.map