import { ChargeTypeEnum, MissingChargeInfo } from '../../../shared/enums.js';
import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js';
import { isInvoice } from '../../documents/helpers/common.helper.js';
import { validateDocumentAllocation } from '../../documents/helpers/validate-document.helper.js';
import { DocumentsProvider } from '../../documents/providers/documents.provider.js';
import { BusinessesProvider } from '../../financial-entities/providers/businesses.provider.js';
import { ChargeTagsProvider } from '../../tags/providers/charge-tags.provider.js';
import { getChargeType } from './charge-type.js';
import { getChargeBusinesses, getChargeDocumentsMeta, getChargeTaxCategoryId, getChargeTransactionsMeta, } from './common.helper.js';
export const validateCharge = async (charge, injector) => {
    const missingInfo = [];
    const [chargeType, { mainBusinessId }, taxCategoryId] = await Promise.all([
        getChargeType(charge, injector),
        getChargeBusinesses(charge.id, injector),
        getChargeTaxCategoryId(charge.id, injector),
    ]);
    const adminContext = await injector.get(AdminContextProvider).getVerifiedAdminContext();
    const isGeneralFees = taxCategoryId === adminContext.general.taxCategories.generalFeeTaxCategoryId;
    // check for consistent counterparty business
    const businessNotRequired = [ChargeTypeEnum.InternalTransfer, ChargeTypeEnum.Salary, ChargeTypeEnum.Financial].includes(chargeType) || isGeneralFees;
    const businessPromise = mainBusinessId && !businessNotRequired
        ? injector.get(BusinessesProvider).getBusinessByIdLoader.load(mainBusinessId)
        : Promise.resolve(undefined);
    const [business, { invalidTransactions, transactionsCount }, { documentsVatAmount, invoiceCount, receiptCount, invalidDocuments },] = await Promise.all([
        businessPromise,
        getChargeTransactionsMeta(charge.id, injector),
        getChargeDocumentsMeta(charge.id, injector),
    ]);
    const businessIsFine = businessNotRequired || !!business;
    if (!businessIsFine) {
        missingInfo.push(MissingChargeInfo.Counterparty);
    }
    // validate documents
    let shouldHaveDocuments = true;
    switch (chargeType) {
        case ChargeTypeEnum.Salary:
        case ChargeTypeEnum.InternalTransfer:
        case ChargeTypeEnum.Dividend:
        case ChargeTypeEnum.Conversion:
        case ChargeTypeEnum.MonthlyVat:
        case ChargeTypeEnum.CreditcardBankCharge:
        case ChargeTypeEnum.Financial:
        case ChargeTypeEnum.BusinessTrip:
        case ChargeTypeEnum.BankDeposit:
            shouldHaveDocuments = false;
    }
    if (isGeneralFees || business?.no_invoices_required === true || charge.documents_optional_flag) {
        shouldHaveDocuments = false;
    }
    let documentsAreFine;
    if (shouldHaveDocuments) {
        const documents = await injector
            .get(DocumentsProvider)
            .getDocumentsByChargeIdLoader.load(charge.id);
        let missingAllocationNumber = false;
        await Promise.all(documents.map(async (doc) => {
            if (isInvoice(doc.type)) {
                const validAllocation = await validateDocumentAllocation(doc, injector);
                if (!validAllocation) {
                    missingAllocationNumber = true;
                }
            }
        }));
        const isReceiptEnough = !!(business?.can_settle_with_receipt && receiptCount > 0);
        const dbDocumentsAreValid = !invalidDocuments;
        documentsAreFine =
            dbDocumentsAreValid && (invoiceCount > 0 || isReceiptEnough) && !missingAllocationNumber;
    }
    else {
        documentsAreFine = true;
    }
    if (!documentsAreFine) {
        missingInfo.push(MissingChargeInfo.Documents);
    }
    // validate transactions
    const hasTransaction = transactionsCount >= 1;
    const transactionsNotRequired = [ChargeTypeEnum.Financial].includes(chargeType);
    const transactionsAreFine = transactionsNotRequired || (hasTransaction && !invalidTransactions);
    if (!transactionsAreFine) {
        missingInfo.push(MissingChargeInfo.Transactions);
    }
    // validate description
    const descriptionIsFine = (charge.user_description?.trim().length ?? 0) > 0;
    if (!descriptionIsFine) {
        missingInfo.push(MissingChargeInfo.Description);
    }
    // validate tags
    const tags = await injector.get(ChargeTagsProvider).getTagsByChargeIDLoader.load(charge.id);
    const tagsAreFine = tags.length > 0;
    if (!tagsAreFine) {
        missingInfo.push(MissingChargeInfo.Tags);
    }
    // validate vat
    const isVATlessBusiness = charge.optional_vat ||
        (business &&
            (business.country !== adminContext.locality ||
                business.exempt_dealer ||
                business.optional_vat));
    const vatIsFine = !shouldHaveDocuments ||
        isGeneralFees ||
        (documentsVatAmount != null && (isVATlessBusiness || documentsVatAmount !== 0));
    if (!vatIsFine) {
        missingInfo.push(MissingChargeInfo.Vat);
    }
    // validate tax category
    const shouldHaveTaxCategory = ![ChargeTypeEnum.Salary, ChargeTypeEnum.InternalTransfer].includes(chargeType);
    const taxCategoryIsFine = !shouldHaveTaxCategory || !!taxCategoryId;
    if (!taxCategoryIsFine) {
        missingInfo.push(MissingChargeInfo.TaxCategory);
    }
    //TODO(Gil): validate balance
    //TODO(Gil): validate ledger
    const allFine = documentsAreFine &&
        businessIsFine &&
        descriptionIsFine &&
        tagsAreFine &&
        vatIsFine &&
        transactionsAreFine &&
        taxCategoryIsFine;
    return {
        isValid: allFine,
        missingInfo,
    };
};
//# sourceMappingURL=validate.helper.js.map