import { DECREASED_VAT_RATIO } from '../../../shared/constants.js';
import { dateToTimelessDateString, formatCurrency } from '../../../shared/helpers/index.js';
import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js';
import { validateDocumentAllocation, validateDocumentVat, } from '../../documents/helpers/validate-document.helper.js';
import { ExchangeProvider } from '../../exchange-rates/providers/exchange.provider.js';
import { FinancialAccountsProvider } from '../../financial-accounts/providers/financial-accounts.provider.js';
import { VatProvider } from '../../vat/providers/vat.provider.js';
import { getFinancialAccountTaxCategoryId, LedgerError, validateTransactionBasicVariables, } from './utils.helper.js';
export async function ledgerEntryFromDocument(injector, document, charge, ownerId, taxCategoryId) {
    if (!document.date) {
        throw new LedgerError(`Document serial "${document.serial_number}" is missing the date`);
    }
    if (!document.debtor_id) {
        throw new LedgerError(`Document serial "${document.serial_number}" is missing the debtor`);
    }
    if (!document.creditor_id) {
        throw new LedgerError(`Document serial "${document.serial_number}" is missing the creditor`);
    }
    if (!document.total_amount) {
        throw new LedgerError(`Document serial "${document.serial_number}" is missing amount`);
    }
    if (!document.currency_code) {
        throw new LedgerError(`Document serial "${document.serial_number}" is missing currency code`);
    }
    const { defaultLocalCurrency, authorities: { inputVatTaxCategoryId, outputVatTaxCategoryId, propertyOutputVatTaxCategoryId }, } = await injector.get(AdminContextProvider).getVerifiedAdminContext();
    let totalAmount = Math.abs(document.total_amount);
    const isCreditorCounterparty = document.debtor_id === ownerId;
    const counterpartyId = isCreditorCounterparty ? document.creditor_id : document.debtor_id;
    const debitAccountID1 = isCreditorCounterparty ? taxCategoryId : counterpartyId;
    const creditAccountID1 = isCreditorCounterparty ? counterpartyId : taxCategoryId;
    const currency = formatCurrency(document.currency_code);
    let foreignTotalAmount = null;
    let amountWithoutVat = totalAmount;
    let foreignAmountWithoutVat = null;
    let vatAmount = document.vat_amount == null ? null : Math.abs(document.vat_amount);
    let foreignVatAmount = null;
    let vatTaxCategory = null;
    if (vatAmount != null && charge.is_property) {
        vatAmount = vatAmount * DECREASED_VAT_RATIO; // Adjust VAT for property charges
    }
    const isCreditInvoice = document.type === 'CREDIT_INVOICE';
    if (vatAmount) {
        amountWithoutVat = amountWithoutVat - vatAmount;
        const adjustedOutputVatTaxCategoryId = charge.is_property
            ? propertyOutputVatTaxCategoryId
            : outputVatTaxCategoryId;
        vatTaxCategory =
            isCreditorCounterparty === isCreditInvoice
                ? inputVatTaxCategoryId
                : adjustedOutputVatTaxCategoryId;
        const vatValue = await injector
            .get(VatProvider)
            .getVatValueByDateLoader.load(dateToTimelessDateString(document.date));
        if (!vatValue) {
            throw new LedgerError(`VAT value is missing for document ID=${document.id}`);
        }
        validateDocumentVat(document, vatValue, message => {
            throw new LedgerError(message);
        });
        await validateDocumentAllocation(document, injector).then(valid => {
            if (!valid) {
                throw new LedgerError(`Allocation number missing for document [${document.serial_number}]`);
            }
        });
    }
    // handle non-local currencies
    if (document.currency_code !== defaultLocalCurrency) {
        let exchangeRate;
        if (document.exchange_rate_override) {
            exchangeRate = Number(document.exchange_rate_override);
        }
        else {
            exchangeRate = await injector
                .get(ExchangeProvider)
                .getExchangeRates(currency, defaultLocalCurrency, document.date);
        }
        // Set foreign amounts
        foreignTotalAmount = totalAmount;
        foreignAmountWithoutVat = amountWithoutVat;
        // calculate amounts in ILS
        totalAmount = exchangeRate * totalAmount;
        amountWithoutVat = exchangeRate * amountWithoutVat;
        if (vatAmount && vatAmount > 0) {
            foreignVatAmount = vatAmount;
            vatAmount = exchangeRate * vatAmount;
        }
    }
    let creditAccountID2 = null;
    let debitAccountID2 = null;
    let creditAmount1;
    let localCurrencyCreditAmount1;
    let debitAmount1;
    let localCurrencyDebitAmount1;
    let creditAmount2 = null;
    let localCurrencyCreditAmount2 = null;
    let debitAmount2 = null;
    let localCurrencyDebitAmount2 = null;
    if (isCreditorCounterparty) {
        localCurrencyCreditAmount1 = totalAmount;
        creditAmount1 = foreignTotalAmount;
        localCurrencyDebitAmount1 = amountWithoutVat;
        debitAmount1 = foreignAmountWithoutVat;
        if (vatAmount && vatAmount > 0) {
            // add vat to debtor2
            debitAmount2 = foreignVatAmount;
            localCurrencyDebitAmount2 = vatAmount;
            debitAccountID2 = vatTaxCategory;
        }
    }
    else {
        localCurrencyDebitAmount1 = totalAmount;
        debitAmount1 = foreignTotalAmount;
        localCurrencyCreditAmount1 = amountWithoutVat;
        creditAmount1 = foreignAmountWithoutVat;
        if (vatAmount && vatAmount > 0) {
            // add vat to creditor2
            creditAmount2 = foreignVatAmount;
            localCurrencyCreditAmount2 = vatAmount;
            creditAccountID2 = vatTaxCategory;
        }
    }
    const ledgerEntry = {
        id: document.id,
        invoiceDate: document.date,
        valueDate: document.date,
        currency,
        creditAccountID1,
        creditAmount1: creditAmount1 ?? undefined,
        localCurrencyCreditAmount1,
        debitAccountID1,
        debitAmount1: debitAmount1 ?? undefined,
        localCurrencyDebitAmount1,
        creditAccountID2: creditAccountID2 ?? undefined,
        creditAmount2: creditAmount2 ?? undefined,
        localCurrencyCreditAmount2: localCurrencyCreditAmount2 ?? undefined,
        debitAccountID2: debitAccountID2 ?? undefined,
        debitAmount2: debitAmount2 ?? undefined,
        localCurrencyDebitAmount2: localCurrencyDebitAmount2 ?? undefined,
        description: undefined,
        reference: document.serial_number ?? undefined,
        isCreditorCounterparty,
        isCreditInvoice,
        ownerId,
        chargeId: charge.id,
    };
    return ledgerEntry;
}
function getCreditCardAccountByTransactionReferenceAndDescription(sourceReference, sourceDescription) {
    if (sourceReference === '8547') {
        return '6fed9073-f571-402e-9da0-ac0669f658d2'; // 9200
    }
    if (sourceReference === '13795') {
        if (sourceDescription?.includes('2260')) {
            return '0e86514c-9ddb-4c82-b731-6107f7293b1f'; //2260
        }
        if (sourceDescription?.includes('4333')) {
            return '782070ce-ec7e-4be0-ab69-46c89528bf04'; //4333
        }
    }
    if (sourceReference === '22200' && sourceDescription?.includes('מסטרקארד')) {
        return '782070ce-ec7e-4be0-ab69-46c89528bf04'; //4333
    }
    if (sourceReference === '11200' && sourceDescription?.includes('כ.א.ל')) {
        return '6fed9073-f571-402e-9da0-ac0669f658d2'; // 9200
    }
    return null;
}
export async function ledgerEntryFromMainTransaction(transaction, injector, chargeId, ownerId, businessId, gotRelevantDocuments = false) {
    const { currency, valueDate, transactionBusinessId } = validateTransactionBasicVariables(transaction);
    let mainAccountId = transactionBusinessId;
    const { defaultLocalCurrency, financialAccounts: { internalWalletsIds }, } = await injector.get(AdminContextProvider).getVerifiedAdminContext();
    if (!gotRelevantDocuments &&
        transaction.source_reference &&
        businessId &&
        internalWalletsIds.includes(businessId)) {
        const account = await injector
            .get(FinancialAccountsProvider)
            .getFinancialAccountByAccountNumberLoader.load(transaction.source_reference);
        let accountId = account?.id ?? null;
        accountId ??= getCreditCardAccountByTransactionReferenceAndDescription(transaction.source_reference, transaction.source_description);
        if (!accountId) {
            throw new LedgerError(`Transaction reference "${transaction.source_reference}" is missing account`);
        }
        mainAccountId = await getFinancialAccountTaxCategoryId(injector, {
            ...transaction,
            account_id: accountId,
        });
    }
    let amount = Number(transaction.amount);
    let foreignAmount = undefined;
    if (currency !== defaultLocalCurrency) {
        // get exchange rate for currency
        const exchangeRate = await injector
            .get(ExchangeProvider)
            .getExchangeRates(currency, defaultLocalCurrency, valueDate);
        foreignAmount = amount;
        // calculate amounts in ILS
        amount = exchangeRate * amount;
    }
    const accountTaxCategoryId = await getFinancialAccountTaxCategoryId(injector, transaction);
    const isCreditorCounterparty = amount > 0;
    const ledgerEntry = {
        id: transaction.id,
        invoiceDate: transaction.event_date,
        valueDate,
        currency,
        creditAccountID1: isCreditorCounterparty ? mainAccountId : accountTaxCategoryId,
        creditAmount1: foreignAmount ? Math.abs(foreignAmount) : undefined,
        localCurrencyCreditAmount1: Math.abs(amount),
        debitAccountID1: isCreditorCounterparty ? accountTaxCategoryId : mainAccountId,
        debitAmount1: foreignAmount ? Math.abs(foreignAmount) : undefined,
        localCurrencyDebitAmount1: Math.abs(amount),
        description: transaction.source_description ?? undefined,
        reference: transaction.origin_key,
        isCreditorCounterparty,
        ownerId,
        currencyRate: transaction.currency_rate ? Number(transaction.currency_rate) : undefined,
        chargeId,
    };
    return ledgerEntry;
}
export async function ledgerEntryFromBalanceCancellation(balanceCancellation, ledgerBalance, financialAccountLedgerEntries, chargeId, ownerId, injector) {
    const { defaultLocalCurrency, general: { taxCategories: { balanceCancellationTaxCategoryId }, }, } = await injector.get(AdminContextProvider).getVerifiedAdminContext();
    const entityBalance = ledgerBalance.get(balanceCancellation.business_id);
    if (!entityBalance) {
        throw new LedgerError(`Balance cancellation for business ${balanceCancellation.business_id} redundant - already balanced`);
    }
    const { amount, entityId } = entityBalance;
    const financialAccountEntry = financialAccountLedgerEntries.find(entry => [
        entry.creditAccountID1,
        entry.creditAccountID2,
        entry.debitAccountID1,
        entry.debitAccountID2,
    ].includes(balanceCancellation.business_id));
    if (!financialAccountEntry) {
        throw new LedgerError(`Balance cancellation for business ${balanceCancellation.business_id} failed - no financial account entry found`);
    }
    let foreignAmount = undefined;
    if (financialAccountEntry.currency !== defaultLocalCurrency &&
        financialAccountEntry.currencyRate) {
        foreignAmount = financialAccountEntry.currencyRate * amount;
    }
    const isCreditorCounterparty = amount > 0;
    const ledgerEntry = {
        id: balanceCancellation.charge_id,
        invoiceDate: financialAccountEntry.invoiceDate,
        valueDate: financialAccountEntry.valueDate,
        currency: financialAccountEntry.currency,
        creditAccountID1: isCreditorCounterparty ? balanceCancellationTaxCategoryId : entityId,
        creditAmount1: foreignAmount ? Math.abs(foreignAmount) : undefined,
        localCurrencyCreditAmount1: Math.abs(amount),
        debitAccountID1: isCreditorCounterparty ? entityId : balanceCancellationTaxCategoryId,
        debitAmount1: foreignAmount ? Math.abs(foreignAmount) : undefined,
        localCurrencyDebitAmount1: Math.abs(amount),
        description: balanceCancellation.description ?? undefined,
        reference: financialAccountEntry.reference,
        isCreditorCounterparty,
        ownerId,
        currencyRate: financialAccountEntry.currencyRate,
        chargeId,
    };
    return ledgerEntry;
}
export function isRefundCharge(description) {
    if (!description) {
        return false;
    }
    const normalizedDescription = description.toLocaleLowerCase();
    return (normalizedDescription.includes('refund') || normalizedDescription.includes('reimbursement'));
}
export function getExchangeDates(financialAccountLedgerEntries) {
    const timeValue = Math.max(...financialAccountLedgerEntries.map(entry => entry.valueDate.getTime()));
    const date = new Date(timeValue);
    return date;
}
//# sourceMappingURL=common-charge-ledger.helper.js.map