import { __decorate, __metadata } from "tslib";
import DataLoader from 'dataloader';
import { Injectable, Scope } from 'graphql-modules';
import { sql } from '@pgtyped/runtime';
import { reassureOwnerIdExists } from '../../../shared/helpers/index.js';
import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js';
import { AuthContextProvider } from '../../auth/providers/auth-context.provider.js';
import { BusinessesProvider } from '../../financial-entities/providers/businesses.provider.js';
const getAllOpenContracts = sql `
    SELECT *
    FROM accounter_schema.clients_contracts
    WHERE is_active IS TRUE;`;
const getContractsByIds = sql `
    SELECT *
    FROM accounter_schema.clients_contracts
    WHERE id In $$ids;`;
const getContractsByAdminBusinessIds = sql `
    SELECT *
    FROM accounter_schema.clients_contracts
    WHERE owner_id IN $$adminBusinessIds;`;
const getContractsByClientIds = sql `
    SELECT *
    FROM accounter_schema.clients_contracts
    WHERE client_id IN $$clientIds;`;
const deleteContract = sql `
    DELETE FROM accounter_schema.clients_contracts
    WHERE id = $id;`;
const updateContract = sql `
      UPDATE accounter_schema.clients_contracts
      SET
      client_id = COALESCE(
        $clientId,
        client_id
      ),
      purchase_orders = COALESCE(
        $purchaseOrders,
        purchase_orders
      ),
      start_date = COALESCE(
        $startDate,
        start_date
      ),
      end_date = COALESCE(
        $endDate,
        end_date
      ),
      remarks = COALESCE(
        $remarks,
        remarks
      ),
      document_type = COALESCE(
        $documentType,
        document_type
      ),
      amount = COALESCE(
        $amount,
        amount
      ),
      currency = COALESCE(
        $currency,
        currency
      ),
      billing_cycle = COALESCE(
        $billingCycle,
        billing_cycle
      ),
      product = COALESCE(
        $product,
        product
      ),
      plan = COALESCE(
        $plan,
        plan
      ),
      is_active = COALESCE(
        $isActive,
        is_active
      ),
      ms_cloud = COALESCE(
        $msCloud,
        ms_cloud
      ),
      operations_count = COALESCE(
        $operationsLimit,
        operations_count
      )
      WHERE
        id = $contractId
      RETURNING *;
    `;
const insertContract = sql `
        INSERT INTO accounter_schema.clients_contracts (
          client_id,
          purchase_orders,
          start_date,
          end_date,
          remarks,
          document_type,
          amount,
          currency,
          billing_cycle,
          product,
          plan,
          is_active,
          ms_cloud,
          operations_count,
          owner_id
        )
        VALUES ($clientId,
          $purchaseOrders,
          $startDate,
          $endDate,
          $remarks,
          $documentType,
          $amount,
          $currency,
          $billingCycle,
          $product,
          $plan,
          $isActive,
          $msCloud,
          $operationsLimit,
          $ownerId)
        RETURNING *;`;
let ContractsProvider = class ContractsProvider {
    db;
    businessesProvider;
    authContextProvider;
    businessIdCache = null;
    constructor(db, businessesProvider, authContextProvider) {
        this.db = db;
        this.businessesProvider = businessesProvider;
        this.authContextProvider = authContextProvider;
    }
    async getBusinessId() {
        if (this.businessIdCache !== null) {
            return this.businessIdCache;
        }
        const authContext = await this.authContextProvider.getAuthContext();
        this.businessIdCache = authContext?.tenant.businessId ?? null;
        return this.businessIdCache;
    }
    allOpenContractsCache = null;
    getAllOpenContracts() {
        if (this.allOpenContractsCache) {
            return this.allOpenContractsCache;
        }
        this.allOpenContractsCache = getAllOpenContracts.run(undefined, this.db).then(contracts => {
            if (contracts) {
                contracts.map(contract => {
                    this.getContractsByIdLoader.prime(contract.id, contract);
                });
            }
            return contracts;
        });
        return this.allOpenContractsCache;
    }
    async contractsByIds(ids) {
        const contracts = await getContractsByIds.run({ ids }, this.db);
        return ids.map(id => contracts.find(contract => contract.id === id));
    }
    getContractsByIdLoader = new DataLoader((ids) => this.contractsByIds(ids));
    async contractsByAdminBusinessIds(adminBusinessIds) {
        const contracts = await getContractsByAdminBusinessIds.run({ adminBusinessIds }, this.db);
        contracts.map(contract => {
            this.getContractsByIdLoader.prime(contract.id, contract);
        });
        return adminBusinessIds.map(adminBusinessId => contracts.filter(contract => contract.owner_id === adminBusinessId));
    }
    getContractsByAdminBusinessIdLoader = new DataLoader((adminBusinessIds) => this.contractsByAdminBusinessIds(adminBusinessIds));
    async contractsByClients(clientIds) {
        const contracts = await getContractsByClientIds.run({ clientIds }, this.db);
        contracts.map(contract => {
            this.getContractsByIdLoader.prime(contract.id, contract);
        });
        return clientIds.map(clientId => contracts.filter(contract => contract.client_id === clientId));
    }
    getContractsByClientIdLoader = new DataLoader((ids) => this.contractsByClients(ids));
    async createContract(params) {
        const businessId = await this.getBusinessId();
        if (!businessId) {
            throw new Error('Business ID is required for creating a contract');
        }
        const [newContract] = await insertContract.run(reassureOwnerIdExists(params, businessId), this.db);
        this.getContractsByIdLoader.prime(newContract.id, newContract);
        // Invalidate list caches
        this.getContractsByClientIdLoader.clear(newContract.client_id);
        const business = await this.businessesProvider.getBusinessByIdLoader.load(newContract.client_id);
        if (business?.owner_id) {
            this.getContractsByAdminBusinessIdLoader.clear(business.owner_id);
        }
        return newContract;
    }
    async updateContract(params) {
        const [updatedContract] = await updateContract.run(params, this.db);
        if (params.contractId) {
            await this.invalidateCacheForContract(params.contractId);
        }
        else {
            this.clearCache();
        }
        this.getContractsByIdLoader.prime(updatedContract.id, updatedContract);
        return updatedContract;
    }
    async deleteContract(contractId) {
        await deleteContract.run({ id: contractId }, this.db);
        await this.invalidateCacheForContract(contractId);
        return true;
    }
    async invalidateCacheForContract(contractId) {
        const contract = await this.getContractsByIdLoader.load(contractId);
        if (contract) {
            this.getContractsByClientIdLoader.clear(contract.client_id);
            const business = await this.businessesProvider.getBusinessByIdLoader.load(contract.client_id);
            if (business?.owner_id) {
                this.getContractsByAdminBusinessIdLoader.clear(business.owner_id);
            }
        }
        this.allOpenContractsCache = null;
    }
    clearCache() {
        this.getContractsByAdminBusinessIdLoader.clearAll();
        this.getContractsByClientIdLoader.clearAll();
        this.getContractsByIdLoader.clearAll();
        this.allOpenContractsCache = null;
    }
};
ContractsProvider = __decorate([
    Injectable({
        scope: Scope.Operation,
        global: true,
    }),
    __metadata("design:paramtypes", [TenantAwareDBClient,
        BusinessesProvider,
        AuthContextProvider])
], ContractsProvider);
export { ContractsProvider };
//# sourceMappingURL=contracts.provider.js.map