import { GraphQLError } from 'graphql';
import { errorSimplifier } from '../../../shared/errors.js';
import { formatFinancialAmount } from '../../../shared/helpers/index.js';
import { TransactionsProvider } from '../../transactions/providers/transactions.provider.js';
import { BankDepositChargesProvider } from '../providers/bank-deposit-charges.provider.js';
import { BankDepositsProvider } from '../providers/bank-deposits.provider.js';
export const bankDepositChargesResolvers = {
    Query: {
        depositByCharge: async (_, { chargeId }, { injector }) => {
            try {
                return await injector
                    .get(BankDepositChargesProvider)
                    .getBankDepositByChargeIdLoader.load(chargeId);
            }
            catch (e) {
                throw errorSimplifier('Error fetching deposit by charge', e);
            }
        },
        relevantDepositsForCharge: async (_, { chargeId }, { injector }) => {
            try {
                const transactions = await injector
                    .get(TransactionsProvider)
                    .transactionsByChargeIDLoader.load(chargeId);
                if (transactions.length === 0) {
                    return { id: chargeId, deposits: [], error: null };
                }
                const currencies = new Set(transactions.map(t => t.currency).filter(Boolean));
                const accountIds = new Set(transactions.map(t => t.account_id).filter(Boolean));
                if (currencies.size > 1) {
                    return {
                        id: chargeId,
                        deposits: [],
                        error: `Charge has transactions in multiple currencies (${[...currencies].join(', ')})`,
                    };
                }
                if (accountIds.size > 1) {
                    return {
                        id: chargeId,
                        deposits: [],
                        error: 'Charge has transactions from multiple accounts',
                    };
                }
                const chargeCurrency = currencies.size === 1 ? [...currencies][0] : null;
                const chargeAccountId = accountIds.size === 1 ? [...accountIds][0] : null;
                const allOpen = await injector.get(BankDepositsProvider).getAllOpenBankDeposits();
                const relevant = allOpen.filter(deposit => {
                    const currencyMatch = deposit.currency == null ||
                        chargeCurrency == null ||
                        deposit.currency === chargeCurrency;
                    const accountMatch = deposit.account_id == null ||
                        chargeAccountId == null ||
                        deposit.account_id === chargeAccountId;
                    return currencyMatch && accountMatch;
                });
                return { id: chargeId, deposits: relevant, error: null };
            }
            catch (e) {
                throw errorSimplifier('Error fetching relevant deposits for charge', e);
            }
        },
    },
    Mutation: {
        assignChargeToDeposit: async (_, { chargeId, depositId }, { injector }) => {
            try {
                await injector.get(BankDepositChargesProvider).assignChargeToDeposit(chargeId, depositId);
                return injector
                    .get(BankDepositChargesProvider)
                    .getBankDepositByChargeIdLoader.load(chargeId)
                    .then(deposit => {
                    if (!deposit) {
                        throw new GraphQLError('Deposit not found for charge after assignment');
                    }
                    return deposit;
                });
            }
            catch (e) {
                throw errorSimplifier('Error assigning transaction to deposit', e);
            }
        },
        createDepositFromCharge: async (_, { chargeId, name }, { injector }) => {
            try {
                const transactions = await injector
                    .get(TransactionsProvider)
                    .transactionsByChargeIDLoader.load(chargeId);
                if (transactions.length === 0) {
                    throw new GraphQLError('Deposit creation from charge requires charges that have at least one transaction');
                }
                const currencies = new Set();
                const accountIds = new Set();
                let openDate = null;
                transactions.map(t => {
                    currencies.add(t.currency);
                    if (t.account_id) {
                        accountIds.add(t.account_id);
                    }
                    // Derive open_date from the earliest debit_date, falling back to event_date
                    const transactionDate = t.debit_date ?? t.event_date;
                    if (transactionDate && (!openDate || transactionDate < openDate)) {
                        openDate = transactionDate;
                    }
                });
                // Validate single currency and single account across all transactions
                if (currencies.size > 1) {
                    throw new GraphQLError(`Cannot create deposit: charge has transactions in multiple currencies (${[...currencies].join(', ')})`);
                }
                if (accountIds.size > 1) {
                    throw new GraphQLError(`Cannot create deposit: charge has transactions from multiple accounts`);
                }
                const currency = [...currencies][0];
                const accountId = [...accountIds][0] ?? null;
                const deposit = await injector.get(BankDepositsProvider).insertBankDeposit({
                    name,
                    currency,
                    accountId,
                    openDate,
                    closeDate: null,
                });
                if (!deposit) {
                    throw new GraphQLError('Failed to create bank deposit');
                }
                await injector
                    .get(BankDepositChargesProvider)
                    .upsertBankDepositCharge({ chargeId, depositId: deposit.id });
                injector.get(BankDepositChargesProvider).getBankDepositByChargeIdLoader.clear(chargeId);
                return deposit;
            }
            catch (e) {
                throw errorSimplifier('Error creating deposit from charge', e);
            }
        },
    },
    BankDeposit: {
        metadata: async (deposit, _, { injector }) => {
            try {
                return await injector
                    .get(BankDepositChargesProvider)
                    .getBankDepositMetadataLoader.load(deposit.id);
            }
            catch (e) {
                throw errorSimplifier(`Error fetching metadata for deposit ${deposit.name}`, e);
            }
        },
    },
    BankDepositMetadata: {
        id: metadata => metadata.id,
        currentBalance: metadata => formatFinancialAmount(metadata.currentBalance),
        totalInterest: metadata => formatFinancialAmount(metadata.totalInterest),
        totalDeposit: metadata => formatFinancialAmount(metadata.totalDeposit),
        potentialCloseDate: metadata => Math.abs(metadata.currentBalance) >= 0.005 ? metadata.potentialCloseDate : null,
        transactions: metadata => metadata.transactionIds,
    },
};
//# sourceMappingURL=bank-deposit-charges.resolver.js.map