"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.compareInvoices = exports.getAverageOver = exports.getDuplicates = exports.getReceivableItemsCustomerAndValue = exports.setReceivableManualInputsToggle = exports.getUniqInvoices = exports.getFirstLastBBCInvoiceWithNumberOccurrence = exports.getPartialPaidTable = exports.getAverageOverInvoiceSize = exports.getAverageInvoiceSize = exports.getAllCustomers = exports.aggregateBbcExposuresGrouped = exports.aggregateBbcExposures = exports.aggregateAllValuesForBbc = exports.aggregateSKUDateAgingPlot = exports.getReceivablesAndTheirQtyByBorrowerId = exports.getReceivableItemsSKUAndValue = exports.getLastDigitFromAllValues = exports.CUSTOMER_NUMBER_SEPARATOR = void 0;
const dayjs_1 = __importDefault(require("dayjs"));
const mongoose_1 = __importDefault(require("mongoose"));
const lodash_1 = __importDefault(require("lodash"));
const ReceivableItem_model_1 = require("../models/ReceivableItem.model");
const collaterals_db_1 = require("./collaterals.db");
const collaterals_enum_1 = require("../enums/collaterals.enum");
const Receivable_model_1 = require("../models/Receivable.model");
const ReceivableAvailability_model_1 = require("../models/ReceivableAvailability.model");
const bbcSheets_db_1 = require("./bbcSheets.db");
const _models_1 = require("../models/_models");
exports.CUSTOMER_NUMBER_SEPARATOR = '~@~';
const getLastDigitFromAllValues = async (allBbcDates) => {
    const allIds = allBbcDates.reduce((acc, bbcDate) => [...acc, ...bbcDate.ids], []);
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                'bbcSheetId': {
                    $in: allIds,
                },
            },
        },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
        {
            $group: {
                _id: '$bbc.bbcDate',
                borrowerId: { $first: '$bbc.borrowerId' },
                bbcDate: { $first: '$bbcDate' },
                items: {
                    $addToSet: {
                        'invoiceAmount': '$invoiceAmount',
                    },
                },
            },
        },
        {
            $project: {
                '_id': '$borrowerId',
                'bbcDate': '$_id',
                'digitArray': {
                    $map: {
                        input: '$items',
                        as: 'item',
                        in: {
                            $substr: [
                                {
                                    $toString: '$$item.invoiceAmount',
                                },
                                0,
                                1,
                            ],
                        },
                    },
                },
            },
        },
        {
            $sort: {
                bbcDate: 1,
            },
        },
        {
            $group: {
                '_id': 1,
                'bbcDates': {
                    $push: '$bbcDate',
                },
                'digitArrays': {
                    $push: '$digitArray',
                },
            },
        },
    ]);
};
exports.getLastDigitFromAllValues = getLastDigitFromAllValues;
const getReceivableItemsSKUAndValue = async (bbcDate, borrowerId) => await Receivable_model_1.ReceivableModel.aggregate([
    {
        $match: { bbcDate, borrowerId },
    },
    { $unwind: '$invoices' },
    {
        $group: {
            _id: '$invoices.invoiceNumber',
            qty: { $first: '$invoices.invoiceAmount' },
        },
    },
    {
        $sort: { qty: -1 },
    },
]);
exports.getReceivableItemsSKUAndValue = getReceivableItemsSKUAndValue;
const getReceivablesAndTheirQtyByBorrowerId = async (borrowerId, allBbcDates) => await Receivable_model_1.ReceivableModel.aggregate([
    {
        $match: {
            borrowerId,
            bbcDate: {
                $in: allBbcDates.map((i) => i.bbcDate),
            },
        },
    },
    { $unwind: '$invoices' },
    {
        $group: {
            _id: '$bbcDate',
            qty: { $sum: '$invoices.invoiceAmount' },
        },
    },
    {
        $sort: {
            _id: 1,
        },
    },
]);
exports.getReceivablesAndTheirQtyByBorrowerId = getReceivablesAndTheirQtyByBorrowerId;
const today = new Date();
const thirtyDaysAgo = (0, dayjs_1.default)(today).subtract(30, 'day').toDate();
const sixtyDaysAgo = (0, dayjs_1.default)(today).subtract(60, 'day').toDate();
const ninetyDaysAgo = (0, dayjs_1.default)(today).subtract(90, 'day').toDate();
const aggregateSKUDateAgingPlot = async (bbcSheetIds) => {
    const generateSumAggregation = (start, end) => ({
        $sum: {
            $add: {
                $cond: [
                    {
                        $and: [
                            { $lte: ['$invoiceDate', start] },
                            { $gte: ['$invoiceDate', end] },
                        ],
                    },
                    '$invoiceAmount',
                    '$$REMOVE',
                ],
            },
        },
    });
    const a = await ReceivableItem_model_1.ReceivableItemModel.aggregate([
        { $match: { 'bbcSheetId': { $in: bbcSheetIds } } },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
        {
            $group: {
                _id: '$bbcDate',
                '0-30': generateSumAggregation(today, thirtyDaysAgo),
                '30-60': generateSumAggregation(thirtyDaysAgo, sixtyDaysAgo),
                '60-90': generateSumAggregation(sixtyDaysAgo, ninetyDaysAgo),
                '90+': {
                    $sum: {
                        $add: {
                            $cond: [
                                {
                                    $lte: ['$invoiceDate', ninetyDaysAgo],
                                },
                                '$invoiceAmount',
                                '$$REMOVE',
                            ],
                        },
                    },
                },
            },
        },
    ]);
    return a[0];
};
exports.aggregateSKUDateAgingPlot = aggregateSKUDateAgingPlot;
const aggregateAllValuesForBbc = async (sheetIds) => {
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                'bbcSheetId': {
                    $in: sheetIds,
                },
            },
        },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
        {
            $group: {
                '_id': '$invoiceNumber',
                'value': {
                    $first: '$invoiceAmount',
                },
                'invoiceDetail': {
                    $first: '$invoiceDetail1',
                },
                'customerTitle': {
                    $first: '$customerTitle',
                },
            },
        },
        {
            $project: {
                '_id': 0,
                'invoiceNumber': '$_id',
                'value': 1,
                'invoiceDetail': 1,
                'customerTitle': 1,
            },
        },
        {
            $sort: {
                'value': -1,
            },
        },
        {
            $limit: 500,
        },
    ]);
};
exports.aggregateAllValuesForBbc = aggregateAllValuesForBbc;
const aggregateBbcExposures = async (bbcSheetIds) => {
    const getTotalBbcValue = await ReceivableItem_model_1.ReceivableItemModel.aggregate([
        { $match: { 'bbcSheetId': { $in: bbcSheetIds } } },
        { $group: { _id: 0, total: { $sum: '$invoiceAmount' } } },
    ]);
    const receivableTotal = getTotalBbcValue[0].total;
    const topItemsForBbc = await ReceivableItem_model_1.ReceivableItemModel.aggregate([
        { $match: { 'bbcSheetId': { $in: bbcSheetIds } } },
        {
            $group: {
                _id: '$customerTitle',
                totalItemValue: { $sum: '$invoiceAmount' },
            },
        },
        { $sort: { totalItemValue: -1 } },
        { $limit: 5 },
        { $project: { _id: 0, name: '$_id', totalItemValue: 1 } },
    ]);
    return { receivableTotal, topItemsForBbc };
};
exports.aggregateBbcExposures = aggregateBbcExposures;
const aggregateBbcExposuresGrouped = async (bbcSheetIds) => {
    const commonAggregation = [
        {
            $match: {
                'bbcSheetId': { $in: bbcSheetIds },
            },
        },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
        {
            $lookup: {
                from: _models_1.MODEL_NAMES.customerGroups,
                let: {
                    'res_cod_it': 'customerTitle',
                    'borrowerId': '$borrowerId',
                },
                pipeline: [
                    {
                        $match: {
                            $expr: {
                                $eq: [
                                    '$bbc.borrowerId', '$$borrowerId',
                                ],
                            },
                        },
                    },
                    {
                        $unwind: '$items',
                    },
                ],
                as: 'item',
            },
        },
        {
            $project: {
                'bbc': 1,
                '_id': 1,
                'skuDate': 1,
                'customerTitle': 1,
                'invoiceAmount': 1,
                'group': {
                    '$filter': {
                        'input': '$item',
                        'as': 'groupEx',
                        'cond': {
                            '$eq': [
                                '$$groupEx.items', '$customerTitle',
                            ],
                        },
                    },
                },
            },
        },
        {
            $addFields: {
                'groupName': {
                    $first: '$group.groupName',
                },
            },
        },
        {
            $project: {
                'borrowerId': 1,
                'bbc': 1,
                'skuDate': 1,
                'customerTitle': {
                    $ifNull: [
                        '$groupName', '$customerTitle',
                    ],
                },
                'invoiceAmount': 1,
            },
        },
    ];
    const getTotalBbcValue = await ReceivableItem_model_1.ReceivableItemModel.aggregate([
        ...commonAggregation,
        {
            $group: {
                '_id': 0,
                'total': {
                    '$sum': '$invoiceAmount',
                },
            },
        },
    ]);
    const receivableTotal = getTotalBbcValue[0].total;
    const topItemsForBbc = await ReceivableItem_model_1.ReceivableItemModel.aggregate([
        ...commonAggregation,
        {
            $group: {
                '_id': '$customerTitle',
                'totalItemValue': {
                    $sum: '$invoiceAmount',
                },
            },
        },
        { $sort: { 'totalItemValue': -1 } },
        { $limit: 5 },
        { $project: { '_id': 0, 'name': '$_id', 'totalItemValue': 1 } },
    ]);
    return { receivableTotal, topItemsForBbc };
};
exports.aggregateBbcExposuresGrouped = aggregateBbcExposuresGrouped;
const getAllCustomers = async (borrowerId) => {
    const bbcSheets = await (0, collaterals_db_1.getBBCSheetsForBorrowerAndType)(borrowerId, collaterals_enum_1.ECollaterals.RECEIVABLE);
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                'bbcSheetId': {
                    $in: bbcSheets.map((bbcSheet) => new mongoose_1.default.Types.ObjectId(String(bbcSheet._id))),
                },
            },
        },
        {
            $group: {
                '_id': null,
                'customers': {
                    $addToSet: '$customerTitle',
                },
            },
        },
        {
            $project: {
                '_id': 0,
            },
        },
    ]);
};
exports.getAllCustomers = getAllCustomers;
const getAverageInvoiceSize = async (borrowerId) => {
    const bbcGroups = await (0, bbcSheets_db_1.getUniqueDates)(borrowerId, 100, collaterals_enum_1.ECollaterals.RECEIVABLE);
    const sheetIds = bbcGroups.reduce((acc, bbc) => [...acc, ...bbc.ids], []);
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                'bbcSheetId': {
                    $in: sheetIds,
                },
            },
        },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
        {
            $group: {
                '_id': '$bbc._id',
                'bbcDate': {
                    $first: '$bbc.bbcDate',
                },
                'totalAmount': {
                    $sum: '$invoiceAmount',
                },
                'totalInvoices': {
                    $sum: 1,
                },
                'averageInvoiceSize': {
                    $avg: '$invoiceAmount',
                },
            },
        },
        {
            $project: {
                '_id': 1,
                'bbcDate': 1,
                'totalAmount': 1,
                'totalInvoices': 1,
                'averageInvoiceSize': {
                    $round: [
                        '$averageInvoiceSize', 2,
                    ],
                },
            },
        },
        {
            $sort: {
                'bbcDate': 1,
            },
        },
    ]);
};
exports.getAverageInvoiceSize = getAverageInvoiceSize;
const getAverageOverInvoiceSize = async (borrowerId, averageInvoiceSize) => {
    const bbcSheets = await (0, bbcSheets_db_1.getBBCSheetsByType)([averageInvoiceSize._id], collaterals_enum_1.ECollaterals.RECEIVABLE);
    const sheetIds = bbcSheets.map((sheet) => sheet._id);
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                'bbcSheetId': {
                    $in: sheetIds,
                },
            },
        },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
        {
            $match: {
                'invoiceAmount': { $gte: averageInvoiceSize.averageInvoiceSize },
            },
        },
        {
            $sort: {
                'invoiceAmount': -1,
            },
        },
        {
            $limit: 5,
        },
        {
            $addFields: {
                'bbcDate': '$bbc.bbcDate',
            },
        },
    ]);
};
exports.getAverageOverInvoiceSize = getAverageOverInvoiceSize;
const getPartialPaidTable = async (bbcSheetIds) => {
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                'bbcSheetId': { $in: bbcSheetIds },
            },
        },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
        {
            $sort: {
                'bbc.bbcDate': 1,
            },
        },
    ]);
};
exports.getPartialPaidTable = getPartialPaidTable;
const getFirstLastBBCInvoiceWithNumberOccurrence = async (bbcSheetIds, { customerTitle, invoiceNumber, }, firstLast) => {
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                $and: [
                    { 'bbcSheetId': { $in: bbcSheetIds } },
                    { 'customerTitle': customerTitle },
                    { 'invoiceNumber': invoiceNumber },
                ],
            },
        },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
        {
            $sort: {
                'bbc.bbcDate': firstLast === 'first' ? 1 : -1,
            },
        },
        {
            $limit: 1,
        },
    ]);
};
exports.getFirstLastBBCInvoiceWithNumberOccurrence = getFirstLastBBCInvoiceWithNumberOccurrence;
const getUniqInvoices = async (bbcSheetIds) => {
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                'bbcSheetId': {
                    $in: bbcSheetIds,
                },
            },
        },
        ...collaterals_db_1.COLLATERALS_LOOKUP,
        {
            $sort: {
                'bbc.bbcDate': 1,
            },
        },
        {
            $group: {
                '_id': null,
                'uniqueNumbers': { $addToSet: '$invoiceNumber' },
                'uniqueValues': { $addToSet: { $concat: ['$customerTitle', exports.CUSTOMER_NUMBER_SEPARATOR, '$invoiceNumber'] } },
            },
        },
    ]);
};
exports.getUniqInvoices = getUniqInvoices;
const setReceivableManualInputsToggle = async (bbcDateId, useManualInputs) => {
    await ReceivableAvailability_model_1.ReceivableAvailabilityModel.updateOne({ bbcDateId }, { useManualInputs });
};
exports.setReceivableManualInputsToggle = setReceivableManualInputsToggle;
const getReceivableItemsCustomerAndValue = async (sheetIds) => await ReceivableItem_model_1.ReceivableItemModel.aggregate([
    {
        $match: {
            bbcSheetId: { $in: sheetIds.map((sheetId) => new mongoose_1.default.Types.ObjectId(sheetId)) },
        },
    }, {
        $group: {
            _id: '$customerTitle',
            totalAmount: {
                $sum: '$invoiceAmount',
            },
        },
    }, {
        $sort: {
            totalAmount: -1,
        },
    },
]);
exports.getReceivableItemsCustomerAndValue = getReceivableItemsCustomerAndValue;
const getDuplicates = async (bbcDateId) => {
    const bbcSheets = await (0, bbcSheets_db_1.getBBCSheetsByType)([bbcDateId], collaterals_enum_1.ECollaterals.RECEIVABLE);
    const bbcSheetIds = bbcSheets.map((sheet) => sheet._id);
    return ReceivableItem_model_1.ReceivableItemModel.aggregate([
        {
            $match: {
                'bbcSheetId': { $in: bbcSheetIds },
            },
        },
        {
            $project: {
                '_id': 1,
                'invoiceNumber': '$invoiceNumber',
            },
        },
        {
            $group: {
                '_id': '$invoiceNumber',
                'count': {
                    $sum: 1,
                },
            },
        },
        {
            $match: {
                _id: {
                    $ne: null,
                },
                count: {
                    $gt: 1,
                },
            },
        },
    ]);
};
exports.getDuplicates = getDuplicates;
const getAverageOver = async (borrowerId) => {
    const average = await (0, exports.getAverageInvoiceSize)(borrowerId);
    const aggregationPromises = average.map((item) => {
        return (0, exports.getAverageOverInvoiceSize)(borrowerId, item);
    });
    const aggregations = await Promise.all(aggregationPromises);
    return aggregations.reduce((acc, i) => [...acc, ...i], []);
};
exports.getAverageOver = getAverageOver;
const compareInvoices = (items1, items2) => {
    const addedInvoices = lodash_1.default.differenceBy(items1, items2, 'invoiceNumber');
    const removedInvoices = lodash_1.default.differenceBy(items2, items1, 'invoiceNumber');
    return { addedInvoices, removedInvoices };
};
exports.compareInvoices = compareInvoices;
