import { GraphQLError } from 'graphql';
import { formatFinancialAmount, optionalDateToTimelessDateString, } from '../../../shared/helpers/index.js';
import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js';
import { ChargesProvider } from '../../charges/providers/charges.provider.js';
import { ExchangeProvider } from '../../exchange-rates/providers/exchange.provider.js';
import { BusinessesProvider } from '../../financial-entities/providers/businesses.provider.js';
import { validateTransactionBasicVariables } from '../../ledger/helpers/utils.helper.js';
import { getTransactionDebitDate } from '../../transactions/helpers/debit-date.helper.js';
import { TransactionsProvider } from '../../transactions/providers/transactions.provider.js';
import { BusinessTripExpensesTransactionsMatchProvider } from '../providers/business-trips-expenses-transactions-match.provider.js';
import { BusinessTripsProvider } from '../providers/business-trips.provider.js';
export const commonBusinessTripExpenseFields = {
    id: DbTripExpense => DbTripExpense.id,
    businessTrip: (DbTripExpense, _, { injector }) => injector
        .get(BusinessTripsProvider)
        .getBusinessTripsByIdLoader.load(DbTripExpense.business_trip_id)
        .then(res => {
        if (!res) {
            throw new GraphQLError(`Business trip with id ${DbTripExpense.business_trip_id} not found`);
        }
        return res;
    }),
    date: DbTripExpense => optionalDateToTimelessDateString(DbTripExpense.date),
    valueDate: DbTripExpense => optionalDateToTimelessDateString(DbTripExpense.value_date),
    amount: async (DbTripExpense, _, { injector }) => {
        const { defaultCryptoConversionFiatCurrency } = await injector
            .get(AdminContextProvider)
            .getVerifiedAdminContext();
        if (!DbTripExpense.amount || !DbTripExpense.currency) {
            if (!DbTripExpense.transaction_ids?.length) {
                return null;
            }
            const transactionsPromise = injector
                .get(TransactionsProvider)
                .transactionByIdLoader.loadMany(DbTripExpense.transaction_ids);
            const [transactions] = await Promise.all([transactionsPromise]);
            const allTransactions = transactions.filter(transaction => transaction && !(transaction instanceof Error));
            let amount = 0;
            await Promise.all(allTransactions.map(async (transaction) => {
                if (!transaction || transaction instanceof Error) {
                    return;
                }
                const date = getTransactionDebitDate(transaction);
                const exchangeRate = await injector
                    .get(ExchangeProvider)
                    .getExchangeRates(transaction.currency, defaultCryptoConversionFiatCurrency, date);
                const transactionAmount = Number(transaction.amount) * exchangeRate;
                amount += transactionAmount;
            }));
            return formatFinancialAmount(amount, defaultCryptoConversionFiatCurrency);
        }
        if (DbTripExpense.currency === defaultCryptoConversionFiatCurrency) {
            return formatFinancialAmount(DbTripExpense.amount, DbTripExpense.currency);
        }
        // handle payed by employee cases
        if (DbTripExpense.payed_by_employee) {
            const date = DbTripExpense.value_date || DbTripExpense.date;
            if (!date) {
                return null;
            }
            const exchangeRate = await injector
                .get(ExchangeProvider)
                .getExchangeRates(DbTripExpense.currency, defaultCryptoConversionFiatCurrency, date);
            return formatFinancialAmount(Number(DbTripExpense.amount) * exchangeRate, defaultCryptoConversionFiatCurrency);
        }
        if (!DbTripExpense.transaction_ids?.length) {
            return null;
        }
        const transactionMatchesPromise = injector
            .get(BusinessTripExpensesTransactionsMatchProvider)
            .getBusinessTripsExpenseMatchesByExpenseIdLoader.load(DbTripExpense.id);
        const transactionsPromise = injector
            .get(TransactionsProvider)
            .transactionByIdLoader.loadMany(DbTripExpense.transaction_ids)
            .then(res => res.filter(transaction => {
            if (!transaction) {
                return false;
            }
            if (transaction instanceof Error) {
                throw transaction;
            }
            return transaction;
        }));
        const [transactionMatches, transactions] = await Promise.all([
            transactionMatchesPromise,
            transactionsPromise,
        ]);
        let totalAmount = 0;
        await Promise.all(transactions.map(async (transaction) => {
            const match = transactionMatches.find(match => match.transaction_id === transaction.id);
            if (!match) {
                return;
            }
            const { currency, valueDate } = validateTransactionBasicVariables(transaction);
            const exchangeRate = await injector
                .get(ExchangeProvider)
                .getExchangeRates(currency, defaultCryptoConversionFiatCurrency, valueDate);
            const amount = Number(match.amount || transaction.amount);
            totalAmount += amount * exchangeRate;
        }));
        return formatFinancialAmount(totalAmount, defaultCryptoConversionFiatCurrency);
    },
    employee: (DbTripExpense, _, { injector }) => DbTripExpense.employee_business_id
        ? injector
            .get(BusinessesProvider)
            .getBusinessByIdLoader.load(DbTripExpense.employee_business_id)
            .then(res => {
            if (!res) {
                throw new GraphQLError(`Employee with id ${DbTripExpense.employee_business_id} not found`);
            }
            return res;
        })
        : null,
    transactions: DbTripTransaction => DbTripTransaction.transaction_ids?.length ? DbTripTransaction.transaction_ids : null,
    charges: async (DbTripTransaction, _, { injector }) => {
        if (!DbTripTransaction.charge_ids?.length) {
            return null;
        }
        return injector
            .get(ChargesProvider)
            .getChargeByIdLoader.loadMany(DbTripTransaction.charge_ids)
            .then(res => res.filter(charge => charge && !(charge instanceof Error)));
    },
    payedByEmployee: dbTransaction => dbTransaction.payed_by_employee,
};
//# sourceMappingURL=common.js.map