import { GraphQLError } from 'graphql';
import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js';
import { BusinessTripsProvider } from '../../business-trips/providers/business-trips.provider.js';
import { businessTripSummary } from '../../business-trips/resolvers/business-trip-summary.resolver.js';
import { CorporateTaxesProvider } from '../../corporate-taxes/providers/corporate-taxes.provider.js';
import { TaxCategoriesProvider } from '../../financial-entities/providers/tax-categories.provider.js';
import { amountByFinancialEntityIdAndSortCodeValidations, recordsByFinancialEntityIdAndSortCodeValidations, } from './misc.helper.js';
import { getProfitLossReportAmounts } from './profit-and-loss.helper.js';
export async function calculateTaxAmounts(injector, year, decoratedLedgerRecords, yearlyResearchAndDevelopmentExpensesAmount, threeYearsResearchAndDevelopmentExpensesForTax, profitBeforeTaxAmount) {
    const { general: { taxCategories: { fineTaxCategoryId, untaxableGiftsTaxCategoryId, salaryExcessExpensesTaxCategoryId, }, }, } = await injector.get(AdminContextProvider).getVerifiedAdminContext();
    const taxRateVariablesPromise = injector
        .get(CorporateTaxesProvider)
        .getCorporateTaxesByDateLoader.load(`${year}-01-01`);
    const businessTripsPromise = injector
        .get(BusinessTripsProvider)
        .getBusinessTripsByDates({
        fromDate: `${year}-01-01`,
        toDate: `${year}-12-31`,
    })
        .then(async (businessTrips) => await Promise.all(businessTrips.map(trip => businessTripSummary(injector, trip))));
    const [taxRateVariables, businessTrips] = await Promise.all([
        taxRateVariablesPromise,
        businessTripsPromise,
    ]);
    if (!taxRateVariables) {
        throw new GraphQLError('No tax rate for year');
    }
    const excludedTaxCategories = await injector
        .get(TaxCategoriesProvider)
        .getAllTaxCategories()
        .then(res => res.filter(tc => !!tc.tax_excluded).map(tc => tc.id));
    const untaxableGiftsFilter = {
        rule: taxCategoryId => taxCategoryId === untaxableGiftsTaxCategoryId,
        negate: true,
    };
    const finesFilter = {
        rule: taxCategoryId => taxCategoryId === fineTaxCategoryId,
        negate: true,
    };
    const reservesFilter = {
        rule: (financialEntityId, sortCode) => sortCode === 931 && !excludedTaxCategories.includes(financialEntityId),
        negate: true,
    };
    const nontaxableLinkageFilter = {
        rule: (financialEntityId, sortCode) => sortCode === 990 && excludedTaxCategories.includes(financialEntityId),
        negate: true,
    };
    // Special tax rate for special taxable income
    const specialTaxableIncomeFilter = {
        rule: (_, sortCode) => sortCode === 991,
        negate: false,
    };
    const [untaxableGifts, fines, reserves, nontaxableLinkage, specialTaxableIncome] = recordsByFinancialEntityIdAndSortCodeValidations(decoratedLedgerRecords, [
        untaxableGiftsFilter,
        finesFilter,
        reservesFilter,
        nontaxableLinkageFilter,
        specialTaxableIncomeFilter,
    ]);
    let businessTripsExcessExpensesAmount = 0;
    businessTrips.map(summary => {
        const amount = summary.rows.find(row => row.type === 'TOTAL')?.excessExpenditure?.raw ?? 0;
        businessTripsExcessExpensesAmount += amount;
    });
    const businessTripsExcludedFilter = {
        rule: (financialEntityId, sortCode) => {
            return sortCode === 945 && excludedTaxCategories.includes(financialEntityId);
        },
        negate: true,
    };
    const salaryExcessExpensesFilter = {
        rule: financialEntityId => financialEntityId === salaryExcessExpensesTaxCategoryId,
        negate: true,
    };
    const yearlyRndExcludedRndFilter = {
        rule: (financialEntityId, sortCode) => {
            return sortCode === 922 && excludedTaxCategories.includes(financialEntityId);
        },
        negate: true,
    };
    const [businessTripsExcludedAmount, salaryExcessExpensesAmount, yearlyRndExcludedRnd] = amountByFinancialEntityIdAndSortCodeValidations(decoratedLedgerRecords, [
        businessTripsExcludedFilter,
        salaryExcessExpensesFilter,
        yearlyRndExcludedRndFilter,
    ]);
    businessTripsExcessExpensesAmount += businessTripsExcludedAmount;
    const researchAndDevelopmentExpensesForTax = threeYearsResearchAndDevelopmentExpensesForTax + yearlyRndExcludedRnd;
    const taxableIncomeAmount = profitBeforeTaxAmount +
        yearlyResearchAndDevelopmentExpensesAmount +
        fines.amount +
        untaxableGifts.amount +
        businessTripsExcessExpensesAmount +
        salaryExcessExpensesAmount +
        reserves.amount +
        nontaxableLinkage.amount +
        researchAndDevelopmentExpensesForTax -
        specialTaxableIncome.amount;
    const taxRate = Number(taxRateVariables.tax_rate) / 100;
    const specialTaxRate = Number(taxRateVariables.original_tax_rate) / 100;
    const annualTaxExpenseAmount = taxableIncomeAmount * taxRate + specialTaxableIncome.amount * specialTaxRate;
    return {
        researchAndDevelopmentExpensesForTax,
        fines,
        untaxableGifts,
        businessTripsExcessExpensesAmount,
        salaryExcessExpensesAmount,
        reserves,
        nontaxableLinkage,
        taxableIncomeAmount,
        taxRate,
        specialTaxableIncome,
        specialTaxRate,
        annualTaxExpenseAmount,
    };
}
export function calculateCumulativeRnDExpenses(year, decoratedLedgerByYear, profitLossByYear = new Map()) {
    let cumulativeResearchAndDevelopmentExpensesAmount = 0;
    for (const rndYear of [year - 2, year - 1, year]) {
        let profitLossHelperReportAmounts = profitLossByYear.get(rndYear);
        if (!profitLossHelperReportAmounts) {
            const rndDecoratedLedgerRecords = decoratedLedgerByYear.get(rndYear) ?? [];
            profitLossHelperReportAmounts = getProfitLossReportAmounts(rndDecoratedLedgerRecords);
            profitLossByYear.set(rndYear, profitLossHelperReportAmounts);
        }
        cumulativeResearchAndDevelopmentExpensesAmount +=
            profitLossHelperReportAmounts.researchAndDevelopmentExpenses.amount;
    }
    return cumulativeResearchAndDevelopmentExpensesAmount;
}
//# sourceMappingURL=tax.helper.js.map