import { EMPTY_UUID } from '../../../../../shared/constants.js';
import { AdminContextProvider } from '../../../../admin-context/providers/admin-context.provider.js';
import { FinancialEntitiesProvider } from '../../../../financial-entities/providers/financial-entities.provider.js';
import { decorateLedgerRecords, getProfitLossReportAmounts, } from '../../../../reports/helpers/profit-and-loss.helper.js';
import { calculateCumulativeRnDExpenses, calculateTaxAmounts, } from '../../../../reports/helpers/tax.helper.js';
import { storeInitialGeneratedRecords } from '../../../helpers/ledgrer-storage.helper.js';
import { generateMiscExpensesLedger } from '../../../helpers/misc-expenses-ledger.helper.js';
import { ledgerProtoToRecordsConverter } from '../../../helpers/utils.helper.js';
import { LedgerProvider } from '../../../providers/ledger.provider.js';
export const generateLedgerRecordsForTaxExpenses = async (charge, { insertLedgerRecordsIfNotExists }, { injector }) => {
    try {
        const { defaultLocalCurrency, authorities: { taxBusinessId, taxExpensesTaxCategoryId }, } = await injector.get(AdminContextProvider).getVerifiedAdminContext();
        if (!charge.user_description) {
            return {
                __typename: 'CommonError',
                message: `Tax expenses charge must include user description with designated year`,
            };
        }
        // get revaluation date - search for "yyyy-mm-dd" in description
        const dateRegex = /\b(\d{4})\b/;
        const matches = charge.user_description.match(dateRegex);
        if (!matches?.length) {
            return {
                __typename: 'CommonError',
                message: `Tax expenses charge description must include full year`,
            };
        }
        const stringYear = matches[0];
        const year = Number(stringYear);
        if (Number.isNaN(year) || year < 2000 || year > new Date().getFullYear()) {
            return {
                __typename: 'CommonError',
                message: `Tax expenses charge description must include valid year (2000 - current year)`,
            };
        }
        const from = new Date(year - 2, 0, 1, 0, 0, 1);
        const to = new Date(year + 1, 0, 0);
        const ledgerRecords = await injector
            .get(LedgerProvider)
            .getLedgerRecordsByDates({ fromDate: from, toDate: to });
        const financialEntities = await injector
            .get(FinancialEntitiesProvider)
            .getAllFinancialEntities();
        const financialEntitiesDict = new Map(financialEntities.map(entity => [entity.id, entity]));
        const decoratedLedgerByYear = new Map();
        for (let year = from.getFullYear(); year <= to.getFullYear(); year++) {
            if (from.getFullYear() > to.getFullYear()) {
                break;
            }
            decoratedLedgerByYear.set(year, []);
        }
        ledgerRecords.map(record => {
            const year = record.invoice_date.getFullYear();
            const [decoratedRecord] = decorateLedgerRecords([record], financialEntitiesDict);
            decoratedLedgerByYear.get(year)?.push(decoratedRecord);
        });
        const profitLossByYear = new Map();
        function getProfitLossReportAmountsByYear(year) {
            let amounts = profitLossByYear.get(year);
            if (!amounts) {
                const decoratedLedgerRecords = decoratedLedgerByYear.get(year) ?? [];
                amounts = getProfitLossReportAmounts(decoratedLedgerRecords);
                profitLossByYear.set(year, amounts);
            }
            return amounts;
        }
        const cumulativeResearchAndDevelopmentExpensesAmount = calculateCumulativeRnDExpenses(year, decoratedLedgerByYear, profitLossByYear);
        const taxableCumulativeResearchAndDevelopmentExpensesAmount = cumulativeResearchAndDevelopmentExpensesAmount / 3;
        const { researchAndDevelopmentExpenses, profitBeforeTax } = getProfitLossReportAmountsByYear(year);
        const { annualTaxExpenseAmount } = await calculateTaxAmounts(injector, year, decoratedLedgerByYear.get(year) ?? [], researchAndDevelopmentExpenses.amount * -1, taxableCumulativeResearchAndDevelopmentExpensesAmount, profitBeforeTax.amount);
        const ledgerEntry = {
            id: EMPTY_UUID,
            invoiceDate: new Date(year, 11, 31),
            valueDate: new Date(year, 11, 31),
            currency: defaultLocalCurrency,
            isCreditorCounterparty: true,
            creditAccountID1: taxBusinessId,
            debitAccountID1: taxExpensesTaxCategoryId,
            localCurrencyCreditAmount1: Math.abs(annualTaxExpenseAmount),
            localCurrencyDebitAmount1: Math.abs(annualTaxExpenseAmount),
            description: `Tax expenses for ${year}`,
            ownerId: charge.owner_id,
            chargeId: charge.id,
            currencyRate: 1,
        };
        const ledgerEntries = [ledgerEntry];
        // generate ledger from misc expenses
        await generateMiscExpensesLedger(charge, injector).then(entries => {
            entries.map(entry => {
                entry.ownerId = charge.owner_id;
                ledgerEntries.push(entry);
            });
        });
        if (insertLedgerRecordsIfNotExists) {
            await storeInitialGeneratedRecords(charge.id, ledgerEntries, injector);
        }
        return {
            records: ledgerProtoToRecordsConverter(ledgerEntries),
            charge,
            balance: {
                isBalanced: true,
                unbalancedEntities: [],
                balanceSum: 0,
                financialEntities: [],
            },
            errors: [],
        };
    }
    catch (e) {
        return {
            __typename: 'CommonError',
            message: `Failed to generate ledger records for charge ID="${charge.id}"\n${e}`,
        };
    }
};
//# sourceMappingURL=tax-expenses-ledger-generation.resolver.js.map