import { DocumentType } from '../../../shared/enums.js';
import { formatFinancialAmount } from '../../../shared/helpers/index.js';
import { isInvoice, isReceipt } from '../../documents/helpers/common.helper.js';
import { basicDocumentValidation } from '../../documents/helpers/validate-document.helper.js';
import { DocumentsProvider } from '../../documents/providers/documents.provider.js';
import { TaxCategoriesProvider } from '../../financial-entities/providers/tax-categories.provider.js';
import { getLedgerMeta } from '../../ledger/helpers/common.helper.js';
import { LedgerProvider } from '../../ledger/providers/ledger.provider.js';
import { MiscExpensesProvider } from '../../misc-expenses/providers/misc-expenses.provider.js';
import { getTransactionsMeta } from '../../transactions/helpers/common.helper.js';
import { TransactionsProvider } from '../../transactions/providers/transactions.provider.js';
import { ChargesProvider } from '../providers/charges.provider.js';
export async function calculateTotalAmount(chargeId, injector, defaultLocalCurrency) {
    try {
        const [charge, { transactionsAmount, transactionsCurrency }, { documentsCurrency, documentsAmount },] = await Promise.all([
            injector.get(ChargesProvider).getChargeByIdLoader.load(chargeId),
            getChargeTransactionsMeta(chargeId, injector),
            getChargeDocumentsMeta(chargeId, injector),
        ]);
        if (!charge) {
            throw new Error(`Charge ID="${chargeId}" not found`);
        }
        if (charge.type === 'PAYROLL' && transactionsAmount) {
            return formatFinancialAmount(transactionsAmount, defaultLocalCurrency);
        }
        if (documentsAmount && documentsCurrency) {
            return formatFinancialAmount(documentsAmount, documentsCurrency);
        }
        if (transactionsAmount && transactionsCurrency) {
            return formatFinancialAmount(transactionsAmount, transactionsCurrency);
        }
        return null;
    }
    catch (error) {
        console.error('Error calculating total amount for charge:', error);
        throw new Error('Failed to calculate total amount for charge', { cause: error });
    }
}
export async function getChargeBusinesses(chargeId, injector) {
    const [charge, transactions, documents, ledgerRecords, miscExpenses] = await Promise.all([
        injector.get(ChargesProvider).getChargeByIdLoader.load(chargeId),
        injector.get(TransactionsProvider).transactionsByChargeIDLoader.load(chargeId),
        injector.get(DocumentsProvider).getDocumentsByChargeIdLoader.load(chargeId),
        injector.get(LedgerProvider).getLedgerRecordsByChargesIdLoader.load(chargeId),
        injector.get(MiscExpensesProvider).getExpensesByChargeIdLoader.load(chargeId),
    ]);
    if (!charge) {
        throw new Error(`Charge ID="${chargeId}" not found`);
    }
    const allBusinessIdsSet = new Set();
    const mainBusinessIdsSet = new Set();
    transactions.map(t => {
        if (t.business_id) {
            allBusinessIdsSet.add(t.business_id);
            if (!t.is_fee) {
                mainBusinessIdsSet.add(t.business_id);
            }
        }
    });
    documents.map(d => {
        [d.creditor_id, d.debtor_id].map(id => {
            if (id && id !== charge.owner_id) {
                allBusinessIdsSet.add(id);
                mainBusinessIdsSet.add(id);
            }
        });
    });
    ledgerRecords.map(lr => {
        [lr.credit_entity1, lr.credit_entity2, lr.debit_entity1, lr.debit_entity2].map(id => {
            if (id && id !== charge.owner_id) {
                allBusinessIdsSet.add(id);
            }
        });
    });
    miscExpenses.map(me => {
        [me.creditor_id, me.debtor_id].map(id => {
            if (id && id !== charge.owner_id) {
                allBusinessIdsSet.add(id);
            }
        });
    });
    const allBusinessIds = Array.from(allBusinessIdsSet);
    const mainBusinessIds = Array.from(mainBusinessIdsSet);
    let mainBusinessId = null;
    if (mainBusinessIds.length === 1) {
        mainBusinessId = mainBusinessIds[0];
    }
    return {
        allBusinessIds,
        mainBusinessId,
    };
}
export async function getChargeDocumentsMeta(chargeId, injector) {
    const [charge, documents] = await Promise.all([
        injector.get(ChargesProvider).getChargeByIdLoader.load(chargeId),
        injector.get(DocumentsProvider).getDocumentsByChargeIdLoader.load(chargeId),
    ]);
    if (!charge) {
        throw new Error(`Charge ID="${chargeId}" not found`);
    }
    let invalidDocuments = false;
    let receiptAmount = 0;
    let receiptVatAmount = null;
    let receiptCount = 0;
    let invoiceAmount = 0;
    let invoiceVatAmount = null;
    let invoiceCount = 0;
    let proformaAmount = null;
    const currenciesSet = new Set();
    const proformaCurrencySet = new Set();
    let documentsMinAccountancyDate = null;
    let documentsMinAnyDate = null;
    let documentsMaxAccountancyDate = null;
    let documentsMaxDate = null;
    documents.map(d => {
        const amount = d.total_amount ?? 0;
        let factor = 1;
        if (d.debtor_id === charge.owner_id) {
            factor *= -1;
        }
        if (d.date) {
            documentsMinAnyDate ??= d.date;
            if (documentsMinAnyDate > d.date) {
                documentsMinAnyDate = d.date;
            }
            documentsMaxDate ??= d.date;
            if (documentsMaxDate < d.date) {
                documentsMaxDate = d.date;
            }
        }
        if (isInvoice(d.type)) {
            invoiceCount++;
            invoiceAmount += amount * factor;
            if (d.vat_amount != null) {
                invoiceVatAmount ??= 0;
                invoiceVatAmount += (d.vat_amount ?? 0) * factor;
            }
            if (d.date) {
                documentsMinAccountancyDate ??= d.date;
                if (documentsMinAccountancyDate > d.date) {
                    documentsMinAccountancyDate = d.date;
                }
                documentsMaxAccountancyDate ??= d.date;
                if (documentsMaxAccountancyDate < d.date) {
                    documentsMaxAccountancyDate = d.date;
                }
            }
            if (d.currency_code) {
                currenciesSet.add(d.currency_code);
            }
        }
        if (isReceipt(d.type)) {
            receiptCount++;
            receiptAmount += amount * factor;
            if (d.vat_amount != null) {
                receiptVatAmount ??= 0;
                receiptVatAmount += (d.vat_amount ?? 0) * factor;
            }
            if (d.date) {
                documentsMinAccountancyDate ??= d.date;
                if (documentsMinAccountancyDate > d.date) {
                    documentsMinAccountancyDate = d.date;
                }
                documentsMaxAccountancyDate ??= d.date;
                if (documentsMaxAccountancyDate < d.date) {
                    documentsMaxAccountancyDate = d.date;
                }
            }
            if (d.currency_code) {
                currenciesSet.add(d.currency_code);
            }
        }
        if (d.type === DocumentType.Proforma) {
            proformaAmount ??= 0;
            proformaAmount += amount * factor;
            if (d.currency_code) {
                proformaCurrencySet.add(d.currency_code);
            }
        }
        if (!basicDocumentValidation(d)) {
            invalidDocuments = true;
        }
    });
    const currencies = currenciesSet.size > 0 ? Array.from(currenciesSet) : Array.from(proformaCurrencySet);
    const documentsAmount = invoiceCount > 0 ? invoiceAmount : receiptCount > 0 ? receiptAmount : proformaAmount;
    return {
        receiptAmount,
        receiptCount,
        invoiceAmount,
        invoiceCount,
        documentsAmount,
        documentsVatAmount: invoiceVatAmount == null ? receiptVatAmount : invoiceVatAmount,
        documentsCount: documents.length,
        documentsCurrency: currencies.length === 1 ? currencies[0] : null,
        invalidDocuments,
        documentsMinDate: documentsMinAccountancyDate ?? documentsMinAnyDate,
        documentsMaxDate: documentsMaxAccountancyDate ?? documentsMaxDate,
    };
}
export async function getChargeTransactionsMeta(chargeId, injector) {
    const transactions = await injector
        .get(TransactionsProvider)
        .transactionsByChargeIDLoader.load(chargeId);
    return getTransactionsMeta(transactions);
}
export async function getChargeLedgerMeta(chargeId, injector) {
    const ledgerRecords = await injector
        .get(LedgerProvider)
        .getLedgerRecordsByChargesIdLoader.load(chargeId);
    return getLedgerMeta(ledgerRecords);
}
export async function getChargeTaxCategoryId(chargeId, injector) {
    const charge = await injector.get(ChargesProvider).getChargeByIdLoader.load(chargeId);
    if (!charge) {
        throw new Error(`Charge ID="${chargeId}" not found`);
    }
    if (charge.tax_category_id) {
        return charge.tax_category_id;
    }
    const { mainBusinessId } = await getChargeBusinesses(chargeId, injector);
    if (!mainBusinessId) {
        return null;
    }
    const taxCategory = await injector
        .get(TaxCategoriesProvider)
        .taxCategoryByBusinessIDsLoader.load(mainBusinessId);
    return taxCategory?.id ?? null;
}
//# sourceMappingURL=common.helper.js.map