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 { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js';
import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js';
const getAllIssuedDocuments = sql `
  SELECT *
  FROM accounter_schema.documents_issued;
`;
const getIssuedDocumentsByIds = sql `
  SELECT *
  FROM accounter_schema.documents_issued
  WHERE id IN $$Ids;
`;
const getIssuedDocumentsByExternalIds = sql `
  SELECT *
  FROM accounter_schema.documents_issued
  WHERE external_id IN $$externalIds;
`;
const getIssuedDocumentsByClientIds = sql `
  SELECT d.*, di.external_id, di.status, di.linked_document_ids
  FROM accounter_schema.documents_issued di
  LEFT JOIN accounter_schema.documents d
    ON di.id = d.id
  WHERE d.debtor_id IN $$clientIds OR d.creditor_id IN $$clientIds;
`;
const getIssuedDocumentsStatusByChargeIds = sql `
  SELECT
    documents.charge_id,
    COALESCE(
      bool_or(
        documents_issued.status = 'OPEN'::accounter_schema.document_status
      ),
      false
    ) AS open_docs_flag
  FROM
    accounter_schema.documents_issued
    LEFT JOIN accounter_schema.documents ON documents.id = documents_issued.id
  WHERE
    documents.charge_id in $$chargeIds
  GROUP BY
    documents.charge_id
`;
const getIssuedDocumentsByType = sql `
  SELECT d.*, di.external_id, di.status, di.linked_document_ids
  FROM accounter_schema.documents_issued di
  LEFT JOIN accounter_schema.documents d
    ON di.id = d.id
  WHERE d.type = $type
  ORDER BY d.serial_number DESC
  LIMIT $limit;
`;
const updateIssuedDocument = sql `
  UPDATE accounter_schema.documents_issued
  SET
  external_id = COALESCE(
    $externalId,
    external_id
  ),
  status = COALESCE(
    $status,
    status
  ),
  linked_document_ids = COALESCE(
    $linkedDocumentIds,
    linked_document_ids
  )
  WHERE
    id = $documentId
  RETURNING *;
`;
const updateIssuedDocumentByExternalId = sql `
  UPDATE accounter_schema.documents_issued
  SET
  id = COALESCE(
    $documentId,
    id
  ),
  status = COALESCE(
    $status,
    status
  ),
  linked_document_ids = COALESCE(
    $linkedDocumentIds,
    linked_document_ids
  )
  WHERE
    external_id = $externalId
  RETURNING *;
`;
const deleteIssuedDocument = sql `
  DELETE FROM accounter_schema.documents_issued
  WHERE id = $documentId
  RETURNING id;
`;
const insertIssuedDocuments = sql `
    INSERT INTO accounter_schema.documents_issued (
      id,
      external_id,
      status,
      linked_document_ids,
      owner_id
    )
    VALUES $$issuedDocuments(
      id,
      externalId,
      status,
      linkedDocumentIds,
      ownerId
    )
    RETURNING *;`;
let IssuedDocumentsProvider = class IssuedDocumentsProvider {
    db;
    adminContextProvider;
    constructor(db, adminContextProvider) {
        this.db = db;
        this.adminContextProvider = adminContextProvider;
    }
    allIssuedDocumentsCache = null;
    async getAllIssuedDocuments(params) {
        if (this.allIssuedDocumentsCache) {
            return this.allIssuedDocumentsCache;
        }
        this.allIssuedDocumentsCache = getAllIssuedDocuments.run(params, this.db).then(docs => {
            docs.map(doc => {
                this.getIssuedDocumentsByIdLoader.prime(doc.id, doc);
            });
            return docs;
        });
        return this.allIssuedDocumentsCache;
    }
    async batchIssuedDocumentsByIds(ids) {
        const uniqueIDs = [...new Set(ids)];
        try {
            const docs = await getIssuedDocumentsByIds.run({ Ids: uniqueIDs }, this.db);
            return ids.map(id => docs.find(doc => doc.id === id));
        }
        catch (e) {
            console.error(e);
            return ids.map(() => null);
        }
    }
    getIssuedDocumentsByIdLoader = new DataLoader((ids) => this.batchIssuedDocumentsByIds(ids));
    async batchIssuedDocumentsByExternalIds(externalIds) {
        const uniqueExternalIDs = [...new Set(externalIds)];
        try {
            const docs = await getIssuedDocumentsByExternalIds.run({ externalIds: uniqueExternalIDs }, this.db);
            return externalIds.map(id => docs.find(doc => doc.external_id === id));
        }
        catch (e) {
            console.error(e);
            return externalIds.map(() => null);
        }
    }
    getIssuedDocumentsByExternalIdLoader = new DataLoader((externalIds) => this.batchIssuedDocumentsByExternalIds(externalIds));
    async batchIssuedDocumentsByClientIds(clientIds) {
        const uniqueClientIDs = [...new Set(clientIds)];
        try {
            const docs = await getIssuedDocumentsByClientIds.run({ clientIds: uniqueClientIDs }, this.db);
            return clientIds.map(id => docs.filter(doc => {
                this.getIssuedDocumentsByIdLoader.prime(doc.id, doc);
                return doc.creditor_id === id || doc.debtor_id === id;
            }));
        }
        catch (e) {
            const message = 'Error fetching issued documents by client IDs';
            console.error(message, e);
            throw new Error(message, { cause: e });
        }
    }
    getIssuedDocumentsByClientIdLoader = new DataLoader((clientIds) => this.batchIssuedDocumentsByClientIds(clientIds), {
        cache: false,
    });
    async batchIssuedDocumentsStatusByChargeIds(chargeIds) {
        const uniqueClientIDs = [...new Set(chargeIds)];
        try {
            const statuses = await getIssuedDocumentsStatusByChargeIds.run({ chargeIds: uniqueClientIDs }, this.db);
            return chargeIds.map(id => statuses.find(status => {
                return status.charge_id === id;
            }));
        }
        catch (e) {
            const message = 'Error fetching issued documents status by charge IDs';
            console.error(message, e);
            throw new Error(message, { cause: e });
        }
    }
    getIssuedDocumentsStatusByChargeIdLoader = new DataLoader((chargeIds) => this.batchIssuedDocumentsStatusByChargeIds(chargeIds), {
        cache: false,
    });
    async getIssuedDocumentsByType(params) {
        return getIssuedDocumentsByType.run(params, this.db).then(docs => {
            docs.map(doc => {
                this.getIssuedDocumentsByIdLoader.prime(doc.id, doc);
            });
            return docs;
        });
    }
    async updateIssuedDocument(params) {
        if (params.documentId) {
            this.invalidateById(params.documentId);
        }
        return updateIssuedDocument.run(params, this.db);
    }
    async updateIssuedDocumentByExternalId(params) {
        return updateIssuedDocumentByExternalId.run(params, this.db).then(res => {
            if (res[0]?.id) {
                this.invalidateById(res[0].id);
            }
            return res;
        });
    }
    async deleteIssuedDocument(params) {
        if (params.documentId) {
            this.invalidateById(params.documentId);
        }
        return deleteIssuedDocument.run(params, this.db);
    }
    async insertIssuedDocuments(params) {
        this.allIssuedDocumentsCache = null;
        const { ownerId } = await this.adminContextProvider.getVerifiedAdminContext();
        const issuedDocumentsWithOwnerId = params.issuedDocuments.map(doc => reassureOwnerIdExists(doc, ownerId));
        return insertIssuedDocuments.run({ issuedDocuments: issuedDocumentsWithOwnerId }, this.db);
    }
    async invalidateById(id) {
        this.getIssuedDocumentsByIdLoader.clear(id);
        this.allIssuedDocumentsCache = null;
        this.getIssuedDocumentsStatusByChargeIdLoader.clearAll();
    }
    clearCache() {
        this.getIssuedDocumentsByIdLoader.clearAll();
        this.getIssuedDocumentsByExternalIdLoader.clearAll();
        this.getIssuedDocumentsByClientIdLoader.clearAll();
        this.getIssuedDocumentsStatusByChargeIdLoader.clearAll();
        this.allIssuedDocumentsCache = null;
    }
};
IssuedDocumentsProvider = __decorate([
    Injectable({
        scope: Scope.Operation,
        global: true,
    }),
    __metadata("design:paramtypes", [TenantAwareDBClient,
        AdminContextProvider])
], IssuedDocumentsProvider);
export { IssuedDocumentsProvider };
//# sourceMappingURL=issued-documents.provider.js.map