import { __decorate, __metadata } from "tslib";
import DataLoader from 'dataloader';
import { GraphQLError } from 'graphql';
import { Injectable, Scope } from 'graphql-modules';
import { sql } from '@pgtyped/runtime';
import { reassureOwnerIdExists } from '../../../shared/helpers/index.js';
import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js';
import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js';
import { TransactionsProvider } from '../../transactions/providers/transactions.provider.js';
import { BusinessTripAccommodationsExpensesProvider } from './business-trips-expenses-accommodations.provider.js';
import { BusinessTripCarRentalExpensesProvider } from './business-trips-expenses-car-rental.provider.js';
import { BusinessTripFlightsExpensesProvider } from './business-trips-expenses-flights.provider.js';
import { BusinessTripOtherExpensesProvider } from './business-trips-expenses-other.provider.js';
import { BusinessTripTravelAndSubsistenceExpensesProvider } from './business-trips-expenses-travel-and-subsistence.provider.js';
import { BusinessTripsProvider } from './business-trips.provider.js';
const getBusinessTripsExpensesByBusinessTripIds = sql `
  SELECT *
  FROM accounter_schema.extended_business_trip_transactions
  WHERE business_trip_id IN $$businessTripIds;`;
const getBusinessTripsExpensesByIds = sql `
  SELECT *
  FROM accounter_schema.extended_business_trip_transactions
  WHERE id IN $$expenseIds;`;
const updateBusinessTripExpense = sql `
  UPDATE accounter_schema.business_trips_transactions
  SET
  business_trip_id = COALESCE(
    $businessTripId,
    business_trip_id
  ),
  category = COALESCE(
    $category,
    category
  )
  WHERE
    id = $businessTripExpenseId
  RETURNING *;
`;
const insertBusinessTripExpense = sql `
  INSERT INTO accounter_schema.business_trips_transactions (business_trip_id, category, owner_id)
  VALUES($businessTripId, $category, $ownerId)
  RETURNING *;`;
const deleteBusinessTripExpense = sql `
  DELETE FROM accounter_schema.business_trips_transactions
  WHERE id = $businessTripExpenseId
  RETURNING id;
`;
let BusinessTripExpensesProvider = class BusinessTripExpensesProvider {
    db;
    adminContextProvider;
    businessTripsProvider;
    flightExpensesProvider;
    accommodationsExpensesProvider;
    travelAndSubsistenceExpensesProvider;
    otherExpensesProvider;
    carRentalExpensesProvider;
    transactionsProvider;
    constructor(db, adminContextProvider, businessTripsProvider, flightExpensesProvider, accommodationsExpensesProvider, travelAndSubsistenceExpensesProvider, otherExpensesProvider, carRentalExpensesProvider, transactionsProvider) {
        this.db = db;
        this.adminContextProvider = adminContextProvider;
        this.businessTripsProvider = businessTripsProvider;
        this.flightExpensesProvider = flightExpensesProvider;
        this.accommodationsExpensesProvider = accommodationsExpensesProvider;
        this.travelAndSubsistenceExpensesProvider = travelAndSubsistenceExpensesProvider;
        this.otherExpensesProvider = otherExpensesProvider;
        this.carRentalExpensesProvider = carRentalExpensesProvider;
        this.transactionsProvider = transactionsProvider;
    }
    async batchBusinessTripsExpensesByBusinessTripIds(businessTripIds) {
        const businessTrips = await getBusinessTripsExpensesByBusinessTripIds.run({
            businessTripIds,
        }, this.db);
        return businessTripIds.map(id => businessTrips.filter(record => record.business_trip_id === id));
    }
    getBusinessTripsExpensesByBusinessTripIdLoader = new DataLoader((ids) => this.batchBusinessTripsExpensesByBusinessTripIds(ids));
    async batchBusinessTripsExpenseMatchesByIds(expenseIds) {
        const businessTripsExpenses = await getBusinessTripsExpensesByIds.run({
            expenseIds,
        }, this.db);
        return expenseIds.map(id => businessTripsExpenses.find(record => record.id === id));
    }
    getBusinessTripsExpensesByIdLoader = new DataLoader((ids) => this.batchBusinessTripsExpenseMatchesByIds(ids));
    updateBusinessTripExpense(params) {
        return updateBusinessTripExpense.run(params, this.db);
    }
    async insertBusinessTripExpense(params) {
        if (params.businessTripId) {
            this.invalidateByBusinessTripId(params.businessTripId);
        }
        const { ownerId } = await this.adminContextProvider.getVerifiedAdminContext();
        return insertBusinessTripExpense.run(reassureOwnerIdExists(params, ownerId), this.db);
    }
    async getBusinessTripExtendedExpensesByChargeId(chargeId) {
        const businessTrip = await this.businessTripsProvider.getBusinessTripsByChargeIdLoader.load(chargeId);
        if (!businessTrip) {
            throw new GraphQLError(`Business trip not found for charge id ${chargeId}`);
        }
        const [allExpenses, flightExpenses, accommodationsExpenses, travelAndSubsistenceExpenses, otherExpenses, carRentalExpenses,] = await Promise.all([
            this.getBusinessTripsExpensesByBusinessTripIdLoader.load(businessTrip.id),
            this.flightExpensesProvider.getBusinessTripsFlightsExpensesByBusinessTripIdLoader.load(businessTrip.id),
            this.accommodationsExpensesProvider.getBusinessTripsAccommodationsExpensesByBusinessTripIdLoader.load(businessTrip.id),
            this.travelAndSubsistenceExpensesProvider.getBusinessTripsTravelAndSubsistenceExpensesByBusinessTripIdLoader.load(businessTrip.id),
            this.otherExpensesProvider.getBusinessTripsOtherExpensesByBusinessTripIdLoader.load(businessTrip.id),
            this.carRentalExpensesProvider.getBusinessTripsCarRentalExpensesByBusinessTripIdLoader.load(businessTrip.id),
        ]);
        const extendedIds = new Set([
            ...flightExpenses,
            ...accommodationsExpenses,
            ...travelAndSubsistenceExpenses,
            ...otherExpenses,
            ...carRentalExpenses,
        ].map(t => t.id));
        return {
            nonExtendedExpenses: allExpenses?.filter(t => !extendedIds.has(t.id)),
            flightExpenses,
            accommodationsExpenses,
            travelAndSubsistenceExpenses,
            otherExpenses,
            carRentalExpenses,
        };
    }
    async getBusinessTripExtendedExpensesByBusinessTripId(businessTripId) {
        const [allExpenses, flightExpenses, accommodationsExpenses, travelAndSubsistenceExpenses, otherExpenses, carRentalExpenses,] = await Promise.all([
            this.getBusinessTripsExpensesByBusinessTripIdLoader.load(businessTripId),
            this.flightExpensesProvider.getBusinessTripsFlightsExpensesByBusinessTripIdLoader.load(businessTripId),
            this.accommodationsExpensesProvider.getBusinessTripsAccommodationsExpensesByBusinessTripIdLoader.load(businessTripId),
            this.travelAndSubsistenceExpensesProvider.getBusinessTripsTravelAndSubsistenceExpensesByBusinessTripIdLoader.load(businessTripId),
            this.otherExpensesProvider.getBusinessTripsOtherExpensesByBusinessTripIdLoader.load(businessTripId),
            this.carRentalExpensesProvider.getBusinessTripsCarRentalExpensesByBusinessTripIdLoader.load(businessTripId),
        ]);
        const extendedIds = new Set([
            ...flightExpenses,
            ...accommodationsExpenses,
            ...travelAndSubsistenceExpenses,
            ...otherExpenses,
            ...carRentalExpenses,
        ].map(t => t.id));
        return {
            nonExtendedExpenses: allExpenses?.filter(t => !extendedIds.has(t.id)),
            flightExpenses,
            accommodationsExpenses,
            travelAndSubsistenceExpenses,
            otherExpenses,
            carRentalExpenses,
        };
    }
    async getTransactionsByBusinessTripId(businessTripId) {
        const chargeIds = await this.businessTripsProvider.getChargeIdsByBusinessTripIdLoader.load(businessTripId);
        return this.transactionsProvider.transactionsByChargeIDLoader
            .loadMany(chargeIds)
            .then(res => res.filter(r => !(r instanceof Error)).flat());
    }
    deleteBusinessTripExpense(params) {
        if (params.businessTripExpenseId) {
            this.invalidateById(params.businessTripExpenseId);
        }
        return deleteBusinessTripExpense.run(params, this.db);
    }
    invalidateExpenseExtensionsById(expenseId) {
        this.flightExpensesProvider.invalidateById(expenseId);
        this.accommodationsExpensesProvider.invalidateById(expenseId);
        this.travelAndSubsistenceExpensesProvider.invalidateById(expenseId);
        this.otherExpensesProvider.invalidateById(expenseId);
        this.carRentalExpensesProvider.invalidateById(expenseId);
    }
    invalidateExpenseExtensionsByBusinessTripId(businessTripId) {
        this.flightExpensesProvider.invalidateByBusinessTripId(businessTripId);
        this.accommodationsExpensesProvider.invalidateByBusinessTripId(businessTripId);
        this.travelAndSubsistenceExpensesProvider.invalidateByBusinessTripId(businessTripId);
        this.otherExpensesProvider.invalidateByBusinessTripId(businessTripId);
        this.carRentalExpensesProvider.invalidateByBusinessTripId(businessTripId);
    }
    async invalidateById(expenseId) {
        const expense = await this.getBusinessTripsExpensesByIdLoader.load(expenseId);
        if (expense?.business_trip_id) {
            this.getBusinessTripsExpensesByBusinessTripIdLoader.clear(expense.business_trip_id);
            this.invalidateExpenseExtensionsByBusinessTripId(expense.business_trip_id);
        }
        this.getBusinessTripsExpensesByIdLoader.clear(expenseId);
        this.invalidateExpenseExtensionsById(expenseId);
    }
    async invalidateByBusinessTripId(businessTripId) {
        const expenses = await this.getBusinessTripsExpensesByBusinessTripIdLoader.load(businessTripId);
        for (const expense of expenses ?? []) {
            if (expense.id) {
                this.getBusinessTripsExpensesByIdLoader.clear(expense.id);
                this.invalidateExpenseExtensionsById(expense.id);
            }
        }
        this.getBusinessTripsExpensesByBusinessTripIdLoader.clear(businessTripId);
        this.invalidateExpenseExtensionsByBusinessTripId(businessTripId);
    }
    clearCache() {
        this.getBusinessTripsExpensesByBusinessTripIdLoader.clearAll();
        this.getBusinessTripsExpensesByIdLoader.clearAll();
    }
};
BusinessTripExpensesProvider = __decorate([
    Injectable({
        scope: Scope.Operation,
        global: true,
    }),
    __metadata("design:paramtypes", [TenantAwareDBClient,
        AdminContextProvider,
        BusinessTripsProvider,
        BusinessTripFlightsExpensesProvider,
        BusinessTripAccommodationsExpensesProvider,
        BusinessTripTravelAndSubsistenceExpensesProvider,
        BusinessTripOtherExpensesProvider,
        BusinessTripCarRentalExpensesProvider,
        TransactionsProvider])
], BusinessTripExpensesProvider);
export { BusinessTripExpensesProvider };
//# sourceMappingURL=business-trips-expenses.provider.js.map