"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ManualEntryService = exports.emptySummary = void 0;
const mongoose_1 = __importDefault(require("mongoose"));
const decimal_js_1 = __importDefault(require("decimal.js"));
const numbers_helper_1 = require("../helpers/numbers.helper");
const inventory_manual_entry_db_1 = require("../db/inventory-manual-entry.db");
const InventoryManualEntry_model_1 = require("../models/InventoryManualEntry.model");
const inventory_availability_db_1 = require("../db/inventory-availability.db");
const BBCDate_model_1 = require("../models/BBCDate.model");
const bbcDates_db_1 = require("../db/bbcDates.db");
const collaterals_enum_1 = require("../enums/collaterals.enum");
const ReceivableAvailabilityManualSummary_model_1 = require("../models/ReceivableAvailabilityManualSummary.model");
exports.emptySummary = {
    invoiceAmount: 0,
    creditNotes: 0,
    excludedCustomerDeduction: 0,
    grossAR: 0,
    permittedOver: 0,
    preliminaryEligibleBalance: 0,
    creditNotesNegative: 0,
    deduction: 0,
    partiallyPaidDeduction: 0,
    contraDeduction: 0,
    crossAgeDeduction: 0,
    waivedDeduction: 0,
    balanceAfterCrossAge: 0,
    finalResult: 0,
    insuredComponent: 0,
    uninsuredComponent: 0,
    insuredAvailability: 0,
    uninsuredAvailability: 0,
    ARReserves: 0,
    ARAvailability: 0,
};
const emptyMultipliers = {
    insuredAvailability: 0,
    uninsuredAvailability: 0,
};
const recalculateAvailabilitySummary = (summary, multiplier, update = null) => {
    const updatedIndexes = (!update || multiplier) ? [] : Object.keys(update);
    summary.summary.grossAR = new decimal_js_1.default(summary.summary.invoiceAmount)
        .plus(summary.summary.excludedCustomerDeduction)
        .plus(summary.summary.creditNotes)
        .toNumber();
    summary.summary.preliminaryEligibleBalance = new decimal_js_1.default(summary.summary.grossAR).plus(summary.summary.permittedOver).toNumber();
    summary.summary.balanceAfterCrossAge = new decimal_js_1.default(summary.summary.preliminaryEligibleBalance)
        .plus(summary.summary.deduction)
        .plus(summary.summary.partiallyPaidDeduction)
        .plus(summary.summary.contraDeduction)
        .plus(summary.summary.crossAgeDeduction)
        .plus(summary.summary.creditNotesNegative)
        .toNumber();
    summary.summary.finalResult = new decimal_js_1.default(summary.summary.balanceAfterCrossAge).plus(summary.summary.waivedDeduction).toNumber();
    if (updatedIndexes.includes('insuredComponent')) {
        summary.summary.uninsuredComponent = new decimal_js_1.default(summary.summary.finalResult).sub(summary.summary.insuredComponent).toNumber();
    }
    else if (updatedIndexes.includes('uninsuredComponent')) {
        summary.summary.insuredComponent = new decimal_js_1.default(summary.summary.finalResult).sub(summary.summary.uninsuredComponent).toNumber();
    }
    else {
        summary.summary.uninsuredComponent = new decimal_js_1.default(summary.summary.finalResult).sub(summary.summary.insuredComponent).toNumber();
    }
    summary.summary.insuredAvailability = new decimal_js_1.default(summary.summary.insuredComponent)
        .mul(summary.multipliers.insuredAvailability || 0)
        .div(100)
        .toNumber();
    summary.summary.uninsuredAvailability = new decimal_js_1.default(summary.summary.uninsuredComponent)
        .mul(summary.multipliers.uninsuredAvailability || 0)
        .div(100)
        .toNumber();
    summary.summary.ARAvailability = new decimal_js_1.default(summary.summary.insuredAvailability)
        .plus(summary.summary.uninsuredAvailability)
        .sub(summary.summary.ARReserves)
        .toNumber();
    return summary;
};
class ManualEntryService {
    getInventoryAvailabilityService;
    constructor(getInventoryAvailabilityService) {
        this.getInventoryAvailabilityService = getInventoryAvailabilityService;
    }
    async getPreviousInventoryEntries(bbcDateId) {
        const currentBBC = await BBCDate_model_1.BBCDateModel.findById(bbcDateId);
        if (currentBBC) {
            const allBBCs = await (0, bbcDates_db_1.getBBCDatesByType)(currentBBC.borrowerId.toString(), [collaterals_enum_1.ECollaterals.INVENTORY]);
            const previousBBCs = allBBCs.filter((bbc) => bbc.bbcDate < currentBBC.bbcDate);
            if (previousBBCs.length > 0) {
                const lastBBC = previousBBCs[0];
                const previousEntries = await (0, inventory_manual_entry_db_1.getInventoryManualEntryData)(lastBBC._id.toString());
                return previousEntries.items;
            }
            else {
                return [];
            }
        }
        return [];
    }
    async getInventoryManualEntry(bbcDateId) {
        const manualEntryData = await (0, inventory_manual_entry_db_1.getInventoryManualEntryData)(bbcDateId);
        if (!manualEntryData.items.length) {
            const previousEntries = await this.getPreviousInventoryEntries(bbcDateId);
            const mappedItems = previousEntries.map((e) => {
                const { _id, ...rest } = e;
                return rest;
            });
            const newEntries = await InventoryManualEntry_model_1.InventoryManualEntryModel.findOneAndUpdate({ bbcDateId: bbcDateId }, { items: mappedItems }, {
                upsert: true,
                new: true,
            }).lean();
            manualEntryData.items = newEntries.items;
        }
        return manualEntryData;
    }
    async updateInventoryManualEntry(manualEntry) {
        const foundEntry = await InventoryManualEntry_model_1.InventoryManualEntryModel.findOne({ bbcDateId: manualEntry.bbcDateId }).lean();
        manualEntry.items = manualEntry.items.map((item) => {
            item.availability = (0, numbers_helper_1.roundToXDigits)((0, numbers_helper_1.roundToXDigits)(item.totalValue - item.ineligible) * item.advanceRate / 100);
            return item;
        });
        if (!foundEntry) {
            const mappedItems = manualEntry.items.map((item) => {
                const { _id, ...rest } = item;
                return rest;
            });
            const newEntry = await InventoryManualEntry_model_1.InventoryManualEntryModel.create({
                bbcDateId: new mongoose_1.default.Types.ObjectId(manualEntry.bbcDateId),
                items: mappedItems,
            });
            await newEntry.save();
            return;
        }
        const mappedItems = manualEntry.items.map((item) => {
            if (String(item._id).includes('new_')) {
                const { _id, ...rest } = item;
                return rest;
            }
            return item;
        });
        await InventoryManualEntry_model_1.InventoryManualEntryModel.findOneAndUpdate({ bbcDateId: manualEntry.bbcDateId }, { items: mappedItems }).lean();
        const inventoryAvailability = await (0, inventory_availability_db_1.getInventoryAvailabilityByBBCDateId)(manualEntry.bbcDateId);
        if (inventoryAvailability && inventoryAvailability.useManualInputs) {
            const inventoryAvailabilityService = this.getInventoryAvailabilityService();
            await inventoryAvailabilityService.toggleManualInventoryAvailability(manualEntry.bbcDateId, true);
        }
    }
    async getReceivableManualSummary(bbcDateId) {
        const manualSummary = await ReceivableAvailabilityManualSummary_model_1.ReceivableAvailabilityManualSummary.findOne({ bbcDateId });
        if (!manualSummary) {
            return { summary: exports.emptySummary, multipliers: emptyMultipliers };
        }
        return {
            summary: manualSummary.summary ? manualSummary.summary : exports.emptySummary,
            multipliers: manualSummary.multipliers ? manualSummary.multipliers : emptyMultipliers,
        };
    }
    async updateReceivableManualSummary(manualSummary, update, multiplier) {
        const negativeKeys = ['permittedOver', 'deduction', 'partiallyPaidDeduction', 'contraDeduction', 'crossAgeDeduction', 'creditNotesNegative'];
        Object.entries(update).forEach(([index, value]) => {
            value = negativeKeys.includes(index) ? new decimal_js_1.default(value).abs().neg().toNumber() : new decimal_js_1.default(value).abs().toNumber();
            if (multiplier) {
                manualSummary.multipliers[index] = value;
            }
            else {
                manualSummary.summary[index] = value;
            }
        });
        return recalculateAvailabilitySummary(manualSummary, multiplier, multiplier ? null : update);
    }
    async saveReceivableManualSummary(bbcDateId, summary) {
        const normalizedSummary = recalculateAvailabilitySummary(summary, false);
        const existingSummary = await ReceivableAvailabilityManualSummary_model_1.ReceivableAvailabilityManualSummary.findOne({ bbcDateId });
        if (existingSummary) {
            existingSummary.summary = normalizedSummary.summary;
            existingSummary.multipliers = summary.multipliers;
            await existingSummary.save();
        }
        else {
            await ReceivableAvailabilityManualSummary_model_1.ReceivableAvailabilityManualSummary.create({ bbcDateId, summary: normalizedSummary.summary, multipliers: summary.multipliers });
        }
    }
}
exports.ManualEntryService = ManualEntryService;
