import { describe, expect, it } from 'vitest';
import { aggregateDocuments, } from '../providers/document-aggregator.js';
describe('Document Aggregator', () => {
    const USER_ID = 'user-123';
    // Helper to create test documents
    const createDocument = (overrides = {}) => ({
        id: 'doc-' + Math.random().toString(36).substr(2, 9),
        charge_id: 'charge-123',
        creditor_id: USER_ID, // Default: user is creditor
        debtor_id: 'business-1', // Default: business is debtor
        currency_code: 'USD',
        date: new Date('2024-01-15'),
        total_amount: 100,
        type: 'INVOICE',
        serial_number: null,
        image_url: null,
        file_url: null,
        ...overrides,
    });
    describe('Single Document', () => {
        it('should return single document with normalized amount', () => {
            const document = createDocument({
                total_amount: 150.5,
                currency_code: 'USD',
                creditor_id: USER_ID,
                debtor_id: 'business-1',
                type: 'INVOICE',
                date: new Date('2024-01-15'),
                serial_number: 'INV-001',
            });
            const result = aggregateDocuments([document], USER_ID);
            expect(result.amount).toBe(150.5); // Positive: business is debtor
            expect(result.currency).toBe('USD');
            expect(result.businessId).toBe('business-1');
            expect(result.date).toEqual(new Date('2024-01-15'));
            expect(result.type).toBe('INVOICE');
            expect(result.description).toBe('INV-001');
        });
        it('should normalize amount when business is creditor', () => {
            const document = createDocument({
                total_amount: 200,
                creditor_id: 'business-1', // Business is creditor
                debtor_id: USER_ID, // User is debtor
                type: 'INVOICE',
            });
            const result = aggregateDocuments([document], USER_ID);
            expect(result.amount).toBe(-200); // Negative: business is creditor
            expect(result.businessId).toBe('business-1');
        });
        it('should handle credit invoice normalization', () => {
            const document = createDocument({
                total_amount: 100,
                creditor_id: 'business-1', // Business is creditor
                debtor_id: USER_ID, // User is debtor
                type: 'CREDIT_INVOICE',
            });
            const result = aggregateDocuments([document], USER_ID);
            expect(result.amount).toBe(100); // Positive: double negation (-1 * -1)
            expect(result.type).toBe('CREDIT_INVOICE');
        });
        it('should use file_url as description when serial_number is null', () => {
            const document = createDocument({
                serial_number: null,
                file_url: 'https://example.com/files/invoice_2024.pdf',
            });
            const result = aggregateDocuments([document], USER_ID);
            expect(result.description).toBe('invoice_2024.pdf');
        });
        it('should use image_url as description when both serial_number and file_url are null', () => {
            const document = createDocument({
                serial_number: null,
                file_url: null,
                image_url: 'https://example.com/images/scan_001.jpg',
            });
            const result = aggregateDocuments([document], USER_ID);
            expect(result.description).toBe('scan_001.jpg');
        });
        it('should use document ID as fallback description', () => {
            const document = createDocument({
                id: 'doc-abc123def456',
                serial_number: null,
                file_url: null,
                image_url: null,
            });
            const result = aggregateDocuments([document], USER_ID);
            expect(result.description).toBe('Doc-doc-abc1');
        });
    });
    describe('Multiple Invoices', () => {
        it('should sum normalized amounts correctly', () => {
            const documents = [
                createDocument({ total_amount: 100, type: 'INVOICE' }), // +100
                createDocument({ total_amount: 200, type: 'INVOICE' }), // +200
                createDocument({ total_amount: 50, type: 'INVOICE' }), // +50
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(350);
            expect(result.type).toBe('INVOICE');
        });
        it('should handle mixed regular and credit invoices', () => {
            const documents = [
                createDocument({
                    total_amount: 500,
                    type: 'INVOICE',
                    creditor_id: USER_ID,
                    debtor_id: 'business-1',
                }), // +500
                createDocument({
                    total_amount: 100,
                    type: 'CREDIT_INVOICE',
                    creditor_id: USER_ID,
                    debtor_id: 'business-1',
                }), // -100
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(400); // 500 - 100
        });
        it('should handle invoices where business is creditor', () => {
            const documents = [
                createDocument({
                    total_amount: 200,
                    creditor_id: 'business-1',
                    debtor_id: USER_ID,
                }), // -200
                createDocument({
                    total_amount: 100,
                    creditor_id: 'business-1',
                    debtor_id: USER_ID,
                }), // -100
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(-300);
        });
    });
    describe('Multiple Receipts', () => {
        it('should sum receipt amounts correctly', () => {
            const documents = [
                createDocument({ total_amount: 50, type: 'RECEIPT' }),
                createDocument({ total_amount: 75, type: 'RECEIPT' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(125);
            expect(result.type).toBe('RECEIPT');
        });
        it('should handle invoice-receipts', () => {
            const documents = [
                createDocument({ total_amount: 100, type: 'INVOICE_RECEIPT' }),
                createDocument({ total_amount: 150, type: 'INVOICE_RECEIPT' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(250);
            expect(result.type).toBe('INVOICE_RECEIPT');
        });
    });
    describe('Type Priority Filtering', () => {
        it('should use only receipts when both invoices and receipts exist', () => {
            const documents = [
                createDocument({ total_amount: 100, type: 'RECEIPT', serial_number: 'REC-001' }),
                createDocument({ total_amount: 200, type: 'INVOICE', serial_number: 'INV-001' }),
                createDocument({ total_amount: 50, type: 'RECEIPT', serial_number: 'REC-002' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(150);
            expect(result.type).toBe('RECEIPT');
            expect(result.description).toContain('REC-001');
            expect(result.description).toContain('REC-002');
            expect(result.description).not.toContain('INV-001'); // Invoices excluded
        });
        it('should use only receipts when both credit invoices and receipts exist', () => {
            const documents = [
                createDocument({ total_amount: 100, type: 'RECEIPT' }),
                createDocument({ total_amount: 200, type: 'CREDIT_INVOICE' }),
                createDocument({ total_amount: 50, type: 'RECEIPT' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            // Credit invoices with user as creditor (business debtor): negate
            expect(result.amount).toBe(150); // 100 + 50
            expect(result.type).toBe('RECEIPT');
        });
        it('should use only receipts/invoice-receipts when mixed with invoices and credit-invoices', () => {
            const documents = [
                createDocument({ total_amount: 100, type: 'INVOICE' }), // Should be excluded
                createDocument({ total_amount: 200, type: 'INVOICE_RECEIPT' }),
                createDocument({ total_amount: 10, type: 'RECEIPT' }),
                createDocument({ total_amount: 50, type: 'CREDIT_INVOICE' }), // Should be excluded
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(210); // 200 + 10 (receipt and invoice-receipt)
        });
        it('should use receipts when no invoices exist', () => {
            const documents = [
                createDocument({ total_amount: 100, type: 'RECEIPT' }),
                createDocument({ total_amount: 50, type: 'INVOICE_RECEIPT' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(150);
            expect(result.type).toBe('RECEIPT');
        });
    });
    describe('Currency Validation', () => {
        it('should throw error with multiple currencies', () => {
            const documents = [
                createDocument({ currency_code: 'USD' }),
                createDocument({ currency_code: 'EUR' }),
            ];
            expect(() => aggregateDocuments(documents, USER_ID)).toThrow('Cannot aggregate documents: multiple currencies found (USD, EUR)');
        });
        it('should throw error with three different currencies', () => {
            const documents = [
                createDocument({ currency_code: 'USD' }),
                createDocument({ currency_code: 'EUR' }),
                createDocument({ currency_code: 'GBP' }),
            ];
            expect(() => aggregateDocuments(documents, USER_ID)).toThrow(/multiple currencies found/);
        });
        it('should not throw when all have same currency', () => {
            const documents = [
                createDocument({ currency_code: 'ILS' }),
                createDocument({ currency_code: 'ILS' }),
                createDocument({ currency_code: 'ILS' }),
            ];
            expect(() => aggregateDocuments(documents, USER_ID)).not.toThrow();
        });
        it('should throw error when all currencies are null', () => {
            const documents = [
                createDocument({ currency_code: null }),
                createDocument({ currency_code: null }),
            ];
            expect(() => aggregateDocuments(documents, USER_ID)).toThrow('Cannot aggregate documents: all documents have null currency_code');
        });
        it('should ignore currency of filtered-out invoices', () => {
            const documents = [
                createDocument({ currency_code: 'USD', type: 'INVOICE' }), // Different currency but will be filtered
                createDocument({ currency_code: 'EUR', type: 'RECEIPT' }),
                createDocument({ currency_code: 'EUR', type: 'RECEIPT' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.currency).toBe('EUR');
        });
    });
    describe('Business ID Validation', () => {
        it('should throw error with multiple different business IDs', () => {
            const documents = [
                createDocument({ debtor_id: 'business-1', creditor_id: USER_ID }),
                createDocument({ debtor_id: 'business-2', creditor_id: USER_ID }),
            ];
            expect(() => aggregateDocuments(documents, USER_ID)).toThrow('Cannot aggregate documents: multiple business IDs found (business-1, business-2)');
        });
        it('should return null when all business IDs are null', () => {
            const documents = [
                createDocument({ debtor_id: null, creditor_id: USER_ID }),
                createDocument({ debtor_id: null, creditor_id: USER_ID }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.businessId).toBeNull();
        });
        it('should return single non-null business ID', () => {
            const documents = [
                createDocument({ debtor_id: 'business-1', creditor_id: USER_ID }),
                createDocument({ debtor_id: null, creditor_id: USER_ID }),
                createDocument({ debtor_id: null, creditor_id: USER_ID }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.businessId).toBe('business-1');
        });
        it('should not throw when all have same business ID', () => {
            const documents = [
                createDocument({ debtor_id: 'business-1', creditor_id: USER_ID }),
                createDocument({ debtor_id: 'business-1', creditor_id: USER_ID }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.businessId).toBe('business-1');
        });
    });
    describe('Date Selection', () => {
        it('should select latest date', () => {
            const documents = [
                createDocument({ date: new Date('2024-01-10') }),
                createDocument({ date: new Date('2024-03-15') }), // Latest
                createDocument({ date: new Date('2024-02-20') }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.date).toEqual(new Date('2024-03-15'));
        });
        it('should handle dates spanning years', () => {
            const documents = [
                createDocument({ date: new Date('2023-12-31') }),
                createDocument({ date: new Date('2024-02-01') }), // Latest
                createDocument({ date: new Date('2024-01-15') }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.date).toEqual(new Date('2024-02-01'));
        });
        it('should handle same date for all documents', () => {
            const documents = [
                createDocument({ date: new Date('2024-01-15') }),
                createDocument({ date: new Date('2024-01-15') }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.date).toEqual(new Date('2024-01-15'));
        });
        it('should throw error when all dates are null', () => {
            const documents = [
                createDocument({ date: null }),
                createDocument({ date: null }),
            ];
            expect(() => aggregateDocuments(documents, USER_ID)).toThrow('Cannot aggregate documents: all documents have null date');
        });
        it('should handle mix of null and valid dates', () => {
            const documents = [
                createDocument({ date: null }),
                createDocument({ date: new Date('2024-01-15') }),
                createDocument({ date: new Date('2024-02-20') }), // Latest
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.date).toEqual(new Date('2024-02-20'));
        });
    });
    describe('Description Concatenation', () => {
        it('should concatenate serial numbers with line breaks', () => {
            const documents = [
                createDocument({ serial_number: 'INV-001' }),
                createDocument({ serial_number: 'INV-002' }),
                createDocument({ serial_number: 'INV-003' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.description).toBe('INV-001\nINV-002\nINV-003');
        });
        it('should prefer serial_number over file URLs', () => {
            const documents = [
                createDocument({ serial_number: 'INV-001', file_url: 'file1.pdf' }),
                createDocument({ serial_number: null, file_url: 'file2.pdf' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.description).toBe('INV-001\nfile2.pdf');
        });
        it('should use image URLs when no serial or file URL', () => {
            const documents = [
                createDocument({ serial_number: null, file_url: null, image_url: 'img1.jpg' }),
                createDocument({ serial_number: null, file_url: null, image_url: 'img2.jpg' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.description).toBe('img1.jpg\nimg2.jpg');
        });
        it('should fallback to document ID when no other identifiers', () => {
            const documents = [
                createDocument({
                    id: 'doc-abc123',
                    serial_number: null,
                    file_url: null,
                    image_url: null,
                }),
                createDocument({ id: 'doc-def456', serial_number: 'INV-001' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.description).toContain('Doc-doc-abc1');
            expect(result.description).toContain('INV-001');
        });
        it('should handle empty descriptions gracefully', () => {
            const documents = [
                createDocument({ serial_number: '  ', file_url: null, image_url: null, id: 'doc-123' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.description).toBe('Doc-doc-123');
        });
    });
    describe('Business Extraction Error Propagation', () => {
        it('should propagate error when both creditor and debtor are user', () => {
            const documents = [
                createDocument({
                    creditor_id: USER_ID,
                    debtor_id: USER_ID, // Invalid: both are user
                }),
            ];
            expect(() => aggregateDocuments(documents, USER_ID)).toThrow(/both creditor_id and debtor_id equal to user ID/);
        });
        it('should propagate error when neither creditor nor debtor is user', () => {
            const documents = [
                createDocument({
                    creditor_id: 'business-1',
                    debtor_id: 'business-2', // Invalid: neither is user
                }),
            ];
            expect(() => aggregateDocuments(documents, USER_ID)).toThrow(/neither creditor_id nor debtor_id equal to user ID/);
        });
        it('should propagate error when both IDs are null', () => {
            const documents = [
                createDocument({
                    creditor_id: null,
                    debtor_id: null, // Invalid: both null
                }),
            ];
            expect(() => aggregateDocuments(documents, USER_ID)).toThrow(/both creditor_id and debtor_id as null/);
        });
    });
    describe('Input Validation', () => {
        it('should throw error for empty array', () => {
            expect(() => aggregateDocuments([], USER_ID)).toThrow('Cannot aggregate documents: array is empty');
        });
        it('should throw error for null input', () => {
            expect(() => aggregateDocuments(null, USER_ID)).toThrow('Cannot aggregate documents: array is empty');
        });
        it('should throw error for undefined input', () => {
            expect(() => aggregateDocuments(undefined, USER_ID)).toThrow('Cannot aggregate documents: array is empty');
        });
    });
    describe('Complex Scenarios', () => {
        it('should handle real-world mixed document scenario', () => {
            const documents = [
                createDocument({
                    total_amount: 1000,
                    type: 'INVOICE', // Will be filtered out
                    creditor_id: USER_ID,
                    debtor_id: 'business-abc',
                    date: new Date('2024-01-15'),
                    serial_number: 'INV-2024-001',
                    currency_code: 'USD',
                }),
                createDocument({
                    total_amount: 500,
                    type: 'RECEIPT',
                    creditor_id: USER_ID,
                    debtor_id: 'business-abc',
                    date: new Date('2024-01-20'),
                    serial_number: 'REC-2024-001',
                    currency_code: 'EUR', // Different currency but will be filtered
                }),
                createDocument({
                    total_amount: 200,
                    type: 'CREDIT_INVOICE', // Will be filtered out
                    creditor_id: USER_ID,
                    debtor_id: 'business-abc',
                    date: new Date('2024-01-25'),
                    serial_number: 'CRD-2024-001',
                    currency_code: 'USD',
                }),
                createDocument({
                    total_amount: 100,
                    type: 'INVOICE_RECEIPT',
                    creditor_id: USER_ID,
                    debtor_id: 'business-abc',
                    date: new Date('2024-01-23'), // Latest
                    serial_number: 'REC-2024-002',
                    currency_code: 'EUR', // Different currency but will be filtered
                }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(600); // 500 + 100
            expect(result.currency).toBe('EUR');
            expect(result.businessId).toBe('business-abc');
            expect(result.date).toEqual(new Date('2024-01-23')); // Latest among receipts
            expect(result.type).toBe('RECEIPT'); // First receipt type
            expect(result.description).not.toContain('INV-2024-001'); // Invoice excluded
            expect(result.description).not.toContain('CRD-2024-001'); // Credit-Invoice excluded
            expect(result.description).toContain('REC-2024-001');
            expect(result.description).toContain('REC-2024-002');
        });
        it('should handle documents with null business IDs', () => {
            const documents = [
                createDocument({
                    total_amount: 100,
                    creditor_id: USER_ID,
                    debtor_id: null, // No business
                }),
                createDocument({
                    total_amount: 200,
                    creditor_id: USER_ID,
                    debtor_id: null, // No business
                }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(300);
            expect(result.businessId).toBeNull();
        });
        it('should handle cryptocurrency documents', () => {
            const documents = [
                createDocument({ total_amount: 0.5, currency_code: 'ETH' }),
                createDocument({ total_amount: 0.3, currency_code: 'ETH' }),
            ];
            const result = aggregateDocuments(documents, USER_ID);
            expect(result.amount).toBe(0.8);
            expect(result.currency).toBe('ETH');
        });
    });
});
//# sourceMappingURL=document-aggregator.test.js.map