"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvestorSummaryService = void 0;
const mongoose_1 = __importDefault(require("mongoose"));
const decimal_js_1 = __importDefault(require("decimal.js"));
const dayjs_1 = __importDefault(require("dayjs"));
const date_helper_1 = require("../../helpers/date.helper");
const Borrower_model_1 = require("../../models/Borrower.model");
const LoanTransaction_model_1 = require("../../models/LoanTransaction.model");
const loan_types_enum_1 = require("../../enums/loan-types.enum");
const getFirstTransactionDate = async (productId, transactionType) => {
    const firstDocs = await LoanTransaction_model_1.LoanTransaction
        .find({ productId: new mongoose_1.default.Types.ObjectId(productId), transactionType: transactionType })
        .sort('date')
        .limit(1)
        .lean();
    if (!firstDocs.length) {
        return new Date();
    }
    return firstDocs[0].date;
};
const getCollectionBetweenDates = async (productId, start, end, transactionType) => {
    const collections = await LoanTransaction_model_1.LoanTransaction.aggregate([{
            $match: {
                date: { $gte: start, $lte: end },
                productId: new mongoose_1.default.Types.ObjectId(productId),
                transactionType: transactionType,
            },
        }]);
    return collections.reduce((sum, collection) => new decimal_js_1.default(collection.amount).abs().add(sum).toNumber(), 0);
};
const emptySummary = {
    ARAdvanceRate: 0,
    ARGross: 0,
    ARNet: 0,
    ARReserves: 0,
    NAISC: '',
    bootCollateral: 0,
    borrowerName: '',
    collateralAdjustments: 0,
    commitment: 0,
    equipmentCollateral: 0,
    intellectualProperty: 0,
    inventoryAdvanceRate: 0,
    inventoryGrossValue: 0,
    inventoryNet: 0,
    inventoryReserves: 0,
    loanBalanceRevolver: 0,
    loanTermBalance: 0,
    maturityDate: undefined,
    netRevolverAvailability: 0,
    netTermAvailability: 0,
    otherReserves: 0,
    participantBalance: 0,
    productCode: '',
    productType: '',
    realEstate: 0,
    startDate: undefined,
    termLoanReserves: 0,
    totalCollateral: 0,
};
class InvestorSummaryService {
    loanChargesService;
    getReportsService;
    constructor(loanChargesService, getReportsService) {
        this.loanChargesService = loanChargesService;
        this.getReportsService = getReportsService;
    }
    async getInvestorSummaryData(borrowerIds, start, end) {
        const data = [];
        const reportsService = this.getReportsService();
        const borrowerSummaries = await reportsService.generateBankPortfolioSummary(borrowerIds, end);
        await Promise.all(borrowerIds.map(async (borrowerId) => {
            const borrower = await Borrower_model_1.BorrowerModel.findById(borrowerId).lean();
            const borrowerProducts = await this.loanChargesService.getLoanProducts(borrowerId);
            await Promise.all(borrowerProducts.filter((product) => product.masterLoanProductId == null).map(async (product) => {
                const productId = product._id.toString();
                const isRevolver = product.type === loan_types_enum_1.ELoanTypes.REVOLVER;
                const { balance: balanceEnd } = await this.loanChargesService.getLoanProductBalance(productId, end);
                const collectionsBetweenStartEnd = await getCollectionBetweenDates(productId, start, end, LoanTransaction_model_1.ELoanTransactionTypes.COLLECTION);
                const disbursementsBetweenStartEnd = await getCollectionBetweenDates(productId, start, end, LoanTransaction_model_1.ELoanTransactionTypes.DISBURSEMENT);
                const collectionsBeginning = await getFirstTransactionDate(productId, LoanTransaction_model_1.ELoanTransactionTypes.COLLECTION);
                const disbursementBeginning = await getFirstTransactionDate(productId, LoanTransaction_model_1.ELoanTransactionTypes.COLLECTION);
                const collectionsBetweenBeginningEnd = await getCollectionBetweenDates(productId, collectionsBeginning, end, LoanTransaction_model_1.ELoanTransactionTypes.COLLECTION);
                const disbursementsBetweenBeginningEnd = await getCollectionBetweenDates(productId, disbursementBeginning, end, LoanTransaction_model_1.ELoanTransactionTypes.DISBURSEMENT);
                const participationBalanceEnd = await this.loanChargesService.getParticipationBalance(product.code, end);
                const companyExposure = new decimal_js_1.default(balanceEnd).sub(participationBalanceEnd).toNumber();
                const productSummary = borrowerSummaries.find((summary) => summary.productCode === product.code) || emptySummary;
                const netRevolverAvailability = productSummary.netRevolverAvailability;
                const ARNet = productSummary.ARNet;
                const inventoryNet = productSummary.inventoryNet;
                const otherCollateral = new decimal_js_1.default(productSummary.equipmentCollateral).add(productSummary.intellectualProperty).add(productSummary.realEstate).add(productSummary.bootCollateral).toNumber();
                const otherReserves = isRevolver ? productSummary.otherReserves : 0;
                const collateralAdjustments = isRevolver ? await reportsService.getCollateralAdjustmentsForLastSignedBBC(borrowerId, end) : 0;
                const otherReservesAndAdjustments = new decimal_js_1.default(otherReserves).add(collateralAdjustments).toNumber();
                const totalRevolver = new decimal_js_1.default(productSummary.totalCollateral).add(productSummary.equipmentCollateral).add(productSummary.intellectualProperty).toNumber();
                const netAvailable = new decimal_js_1.default(inventoryNet).add(ARNet).add(otherCollateral).add(otherReservesAndAdjustments).minus(balanceEnd).toNumber();
                const newRow = {
                    clientName: borrower.name,
                    productName: product.name,
                    maturityDate: (0, dayjs_1.default)(product.maturityDate).format(date_helper_1.defaultDateFormat),
                    commitmentAmount: product.commitment,
                    balanceEnd,
                    participationBalanceEnd,
                    companyExposure,
                    netAvailable,
                    collectionsBetweenStartEnd,
                    disbursementsBetweenStartEnd,
                    netRevolverAvailability,
                    ARNet,
                    inventoryNet,
                    otherCollateral,
                    otherReservesAndAdjustments,
                    totalRevolver,
                    collectionsBetweenBeginningEnd,
                    disbursementsBetweenBeginningEnd,
                };
                data.push(newRow);
            }));
        }));
        return data
            .sort((a, b) => {
            const borrowerComparison = a.clientName.localeCompare(b.clientName);
            if (borrowerComparison !== 0) {
                return borrowerComparison;
            }
            else {
                return a.productName.localeCompare(b.productName);
            }
        });
    }
    ;
}
exports.InvestorSummaryService = InvestorSummaryService;
