"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getARTurn = exports.getARTurnFull = void 0;
const decimal_js_1 = __importDefault(require("decimal.js"));
const dayjs_1 = __importDefault(require("dayjs"));
const BBCDate_model_1 = require("../../models/BBCDate.model");
const bbcSheets_db_1 = require("../../db/bbcSheets.db");
const collaterals_enum_1 = require("../../enums/collaterals.enum");
const receivables_db_1 = require("../../db/receivables.db");
const collaterals_db_1 = require("../../db/collaterals.db");
const excel_helper_1 = require("../../helpers/excel.helper");
const ReceivableItem_model_1 = require("../../models/ReceivableItem.model");
const getARTurnFull = async (params) => {
    const data = await (0, exports.getARTurn)(params);
    const header = getARTurnHeader();
    return (0, excel_helper_1.addHeaderToData)(header, data);
};
exports.getARTurnFull = getARTurnFull;
const getInvoices = async (bbcSheetIds) => {
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                $and: [
                    { 'bbcSheetId': { $in: bbcSheetIds } },
                ],
            },
        },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
    ]);
};
const getARTurn = async (params) => {
    const { borrowerId, bbcDateId, extraParams } = params;
    const { daysFilter } = extraParams;
    const currentBbcDate = await BBCDate_model_1.BBCDateModel.findById(bbcDateId).lean();
    if (!currentBbcDate) {
        return [];
    }
    const rangeStart = (0, dayjs_1.default)(new Date(currentBbcDate.bbcDate)).subtract(daysFilter, 'day').toDate();
    const rangeEnd = new Date(currentBbcDate.bbcDate);
    const allInventoryBbcDates = await (0, bbcSheets_db_1.getUniqueDatesForPeriod)(borrowerId.toString(), collaterals_enum_1.ECollaterals.RECEIVABLE, new Date(rangeStart), new Date(rangeEnd));
    const sheetIds = allInventoryBbcDates.reduce((acc, bbc) => [...acc, ...bbc.ids], []);
    const uniqInvoices = (await (0, receivables_db_1.getUniqInvoices)(sheetIds)).pop();
    if (!uniqInvoices) {
        return [];
    }
    const bbcIds = allInventoryBbcDates.map((bbc) => bbc._id.toString());
    const allInvoicesNew = await (0, collaterals_db_1.getCollateralDocsByBBC)(bbcIds, collaterals_enum_1.ECollaterals.RECEIVABLE);
    const mappedUniqInvoices = uniqInvoices.uniqueValues.map((value) => {
        const [customerTitle, invoiceNumber] = value.split(receivables_db_1.CUSTOMER_NUMBER_SEPARATOR);
        return { customerTitle, invoiceNumber };
    });
    const lastInvoiceNew = allInvoicesNew[allInvoicesNew.length - 1];
    if (!lastInvoiceNew) {
        return [];
    }
    const workedInvoice = [];
    mappedUniqInvoices.forEach((uniqInvoice) => {
        const foundInvoice = lastInvoiceNew.items
            .find((invoice) => invoice.customerTitle === uniqInvoice.customerTitle && invoice.invoiceNumber === uniqInvoice.invoiceNumber);
        if (!foundInvoice) {
            workedInvoice.push(uniqInvoice);
        }
    });
    workedInvoice.sort((invoice1, invoice2) => invoice1.invoiceNumber - invoice2.invoiceNumber);
    const lastInvoices = [];
    const allInvoices = await getInvoices(sheetIds);
    workedInvoice.forEach((invoice) => {
        const testFirstInvoices = allInvoices
            .filter((i) => i.customerTitle === invoice.customerTitle && i.invoiceNumber === invoice.invoiceNumber)
            .sort((invoice1, invoice2) => new Date(invoice1.bbcDate).valueOf() - new Date(invoice2.bbcDate).valueOf());
        const firstInvoice = testFirstInvoices.length > 0 ? testFirstInvoices[0] : null;
        const lastInvoice = testFirstInvoices.length > 0 ? testFirstInvoices[testFirstInvoices.length - 1] : null;
        const lastIndex = allInventoryBbcDates.findIndex((i) => i._id.toString() === lastInvoice.bbc._id.toString());
        const dateRemoved = new Date(allInventoryBbcDates[lastIndex + 1].bbcDate);
        const numberOfDays = (0, dayjs_1.default)(dateRemoved).diff((0, dayjs_1.default)(new Date(firstInvoice.invoiceDate)), 'day');
        lastInvoices.push({
            invoiceNumber: firstInvoice.invoiceNumber,
            dateIssued: firstInvoice.invoiceDate,
            dateRemoved,
            numberOfDays,
            valueRemoved: firstInvoice.invoiceAmount,
            customer: firstInvoice.customerTitle,
            totalValue: numberOfDays * firstInvoice.invoiceAmount,
        });
    });
    const groupedInvoices = lastInvoices.reduce((acc, invoice) => {
        acc[invoice.customer] = acc[invoice.customer] || [];
        acc[invoice.customer].push(invoice);
        return acc;
    }, {});
    return Object.entries(groupedInvoices).reduce((acc, [customer, invoices]) => {
        const invoiceTotalDays = invoices.reduce((totalAverage, invoice) => new decimal_js_1.default(totalAverage).add(invoice.numberOfDays).toNumber(), 0);
        const averageNumberDays = new decimal_js_1.default(invoiceTotalDays).div(invoices.length).toDP(2).toNumber();
        const invoiceTotalValue = invoices.reduce((totalAverage, invoice) => new decimal_js_1.default(totalAverage).add(invoice.totalValue).toNumber(), 0);
        const invoiceTotalRemoved = invoices.reduce((totalAverage, invoice) => new decimal_js_1.default(totalAverage).add(invoice.valueRemoved).toNumber(), 0);
        const weightedAveragedDays = invoiceTotalRemoved === 0
            ? 0
            : new decimal_js_1.default(invoiceTotalValue).div(invoiceTotalRemoved).toDP(2).toNumber();
        const data = {
            customer,
            averageNumberDays,
            weightedAveragedDays,
        };
        return [...acc, data];
    }, []);
};
exports.getARTurn = getARTurn;
const getARTurnHeader = () => {
    return {
        customer: 'Customer',
        averageNumberDays: 'Average Number of Days to clear invoice',
        weightedAveragedDays: 'Weighted Averaged Days (by Value)',
    };
};
