"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrokersService = void 0;
const decimal_js_1 = __importDefault(require("decimal.js"));
const ProductBroker_model_1 = require("../models/ProductBroker.model");
const LoanBroker_model_1 = require("../models/LoanBroker.model");
const brokers_db_1 = require("../db/brokers.db");
const brokers_db_2 = require("../db/brokers.db");
const main_helper_1 = require("../helpers/main.helper");
const defaultBrokerList = [
    {
        _id: `new_${(0, main_helper_1.getUUID)()}`,
        active: true,
        BSCode: '',
        PLCode: '',
        productId: null,
        loanBrokerId: null,
        adminShare: 0,
        interestShare: 0,
        otherShare: 0,
        createdAt: null,
        updatedAt: null,
    },
];
class BrokersService {
    loanChargesService;
    constructor(loanChargesService) {
        this.loanChargesService = loanChargesService;
    }
    async normalizeObjects() {
        try {
            await LoanBroker_model_1.LoanBrokerModel.updateMany({}, { emails: [] });
        }
        catch (e) {
            console.error(e);
        }
    }
    async getAllProductBrokers() {
        return (0, brokers_db_2.getAllProductBrokers)();
    }
    async getBorrowerBrokers(borrowerId) {
        const allBorrowerBrokers = await (0, brokers_db_2.getBorrowerBrokers)(borrowerId);
        if (!allBorrowerBrokers.length) {
            return defaultBrokerList;
        }
        return allBorrowerBrokers;
    }
    async getProductBrokers(productId) {
        return await (0, brokers_db_1.getProductBrokers)(productId);
    }
    async getTotalShares(borrowerId, brokers, replaceNames = false) {
        const products = await this.loanChargesService.getLoanProducts(borrowerId);
        const productShares = products.reduce((acc, product) => {
            const sharesTypes = ['adminShare', 'interestShare', 'otherShare'];
            const shares = sharesTypes.reduce((acc, share) => ({ ...acc, [share]: 0 }), {});
            return { ...acc, [product._id.toString()]: shares };
        }, {});
        const updateShares = (broker, productId, shareFraction = 1) => {
            const sharedKeys = Object.keys(productShares[productId]);
            sharedKeys.forEach((sharedKey) => {
                const productShare = new decimal_js_1.default(broker[sharedKey]).mul(shareFraction);
                return productShares[productId][sharedKey] = new decimal_js_1.default(productShares[productId][sharedKey]).plus(productShare).toNumber();
            });
        };
        brokers.forEach((broker) => {
            updateShares(broker, broker.productId.toString());
        });
        if (replaceNames) {
            return Object.keys(productShares).reduce((acc, productId) => {
                const product = products.find((products) => products._id.toString() === productId);
                return { ...acc, [product.name]: productShares[productId] };
            }, {});
        }
        return productShares;
    }
    async getTotals(borrowerId) {
        const brokers = await ProductBroker_model_1.ProductBrokerModel.find({ borrowerId });
        const shortTotals = await this.getTotalShares(borrowerId, brokers, true);
        return Object.entries(shortTotals).map(([product, shares]) => {
            return {
                active: true,
                _id: null,
                BSCode: null,
                PLCode: null,
                productId: product,
                adminShare: shares.adminShare,
                interestShare: shares.interestShare,
                otherShare: shares.otherShare,
            };
        });
    }
    async checkTotalShares(borrowerId, brokers) {
        const productShares = await this.getTotalShares(borrowerId, brokers);
        return !Object.values(productShares).some(values => values.adminShare > 1 || values.interestShare > 1 || values.otherShare > 1);
    }
    async saveProductBrokers(borrowerId, brokers) {
        const existingBrokers = await (0, brokers_db_2.getBorrowerBrokers)(borrowerId);
        const existingBrokerIds = existingBrokers.map((broker) => broker._id.toString());
        const brokersToDelete = existingBrokerIds.filter((id) => !brokers.some((broker) => String(broker._id) === id));
        await ProductBroker_model_1.ProductBrokerModel.deleteMany({ _id: { $in: brokersToDelete } });
        const brokersToSave = brokers.map((broker) => {
            if (broker._id.toString().startsWith('new_')) {
                let { _id, ...brokerWithoutId } = broker;
                return { ...brokerWithoutId, borrowerId: borrowerId };
            }
            return { ...broker, borrowerId: borrowerId };
        });
        const getFilters = (broker) => {
            return broker.hasOwnProperty('_id') ? { _id: broker._id } : { createdAt: Math.random() };
        };
        try {
            return ProductBroker_model_1.ProductBrokerModel.bulkWrite(brokersToSave.map((broker, order) => ({
                updateOne: {
                    filter: getFilters(broker),
                    update: { $set: { ...broker, order } },
                    upsert: true,
                },
            })));
        }
        catch (e) {
            console.error(e);
        }
    }
    async getAllLoanBrokers() {
        return (0, brokers_db_2.getAllLoanBrokers)();
    }
    async saveLoanBrokers(brokers) {
        const existingBrokers = await (0, brokers_db_2.getAllLoanBrokers)();
        const existingBrokerIds = existingBrokers.map((broker) => broker._id.toString());
        const brokersToDelete = existingBrokerIds.filter((id) => !brokers.some((broker) => String(broker._id) === id));
        await LoanBroker_model_1.LoanBrokerModel.deleteMany({ _id: { $in: brokersToDelete } });
        const brokersToSave = brokers.map((broker) => {
            if (broker._id.toString().startsWith('new_')) {
                let { _id, ...brokerWithoutId } = broker;
                return brokerWithoutId;
            }
            return broker;
        });
        await Promise.all(brokersToSave.map(async (brokerToSave, order) => {
            await this.saveLoanBroker(brokerToSave, order);
        }));
    }
    async saveLoanBroker(broker, order) {
        const getFilters = (broker) => {
            return broker.hasOwnProperty('_id') ? { _id: broker._id } : { createdAt: Math.random() };
        };
        const { emails, ...update } = broker;
        const updatedBroker = await LoanBroker_model_1.LoanBrokerModel.findOneAndUpdate(getFilters(broker), { ...update, order }, { upsert: true, new: true });
        await this.saveLoanBrokerEmails(updatedBroker._id.toString(), emails);
    }
    async saveLoanBrokerEmails(loanBrokerId, emails) {
        const emailsWithoutId = emails.map((email) => {
            const { _id, ...rest } = email;
            return _id.toString().includes('new_') ? rest : email;
        });
        await LoanBroker_model_1.LoanBrokerModel.findByIdAndUpdate(loanBrokerId, { emails: emailsWithoutId });
    }
}
exports.BrokersService = BrokersService;
