"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InventoryService = void 0;
const mongoose_1 = __importDefault(require("mongoose"));
const dayjs_1 = __importDefault(require("dayjs"));
const InventoryItem_model_1 = require("../models/InventoryItem.model");
const collaterals_enum_1 = require("../enums/collaterals.enum");
const bbcSheets_db_1 = require("../db/bbcSheets.db");
const bbcDates_db_1 = require("../db/bbcDates.db");
const collaterals_db_1 = require("../db/collaterals.db");
const numbers_helper_1 = require("../helpers/numbers.helper");
const unit_cost_difference_1 = require("../queries/inventory/unit-cost-difference");
const turn_1 = require("../queries/inventory/turn");
const inconsistent_data_1 = require("../queries/inventory/inconsistent-data");
const movement_1 = require("../queries/inventory/movement");
const extension_1 = require("../queries/inventory/extension");
const CustomerGroup_model_1 = require("../models/CustomerGroup.model");
const invoice_difference_1 = require("../queries/inventory/invoice-difference");
const inventories_1 = require("../db/inventories");
const payable_accounts_1 = require("../db/payable-accounts");
const groups_1 = require("../db/groups");
class InventoryService {
    collateralsService;
    constructor(collateralsService) {
        this.collateralsService = collateralsService;
    }
    async updateInventorySKU({ bbcDate, borrowerId, items }) {
        const skuDates = await (0, inventories_1.getAllTimeOldestSKUDateNew)(borrowerId, bbcDate);
        return items.map((i) => {
            const previousSKUDate = skuDates.find((d) => i.sku.toString().trim() === d._id);
            if (!previousSKUDate) {
                return { ...i, skuDate: bbcDate };
            }
            const isPreviousDateGreaterThanSubmittedDate = new Date(previousSKUDate.oldestDate).getTime() > new Date(bbcDate).getTime();
            if (isPreviousDateGreaterThanSubmittedDate) {
                return { ...i, skuDate: bbcDate };
            }
            return { ...i, skuDate: previousSKUDate.oldestDate };
        });
    }
    async getBenford(borrowerId) {
        const sheetIds = await (0, bbcSheets_db_1.getUniqueDates)(borrowerId, 3, collaterals_enum_1.ECollaterals.INVENTORY);
        const inventory = await (0, inventories_1.getLastDigitFromAllValues)(sheetIds);
        return this.collateralsService.getCollateralsBenford(inventory);
    }
    async getInventoryAgingPlot(borrowerId, rangeStart, rangeEnd) {
        const latestFiveNew = await (0, bbcSheets_db_1.getUniqueDatesForPeriod)(borrowerId, collaterals_enum_1.ECollaterals.INVENTORY, new Date(rangeStart), new Date(rangeEnd));
        const aggregationPromises = latestFiveNew.map((bbcGroup) => (0, inventories_1.aggregateSKUDateAgingPlot)(bbcGroup.ids));
        const aggregations = await Promise.all(aggregationPromises);
        return [
            { name: '0-30', data: aggregations.map((i) => i['0-30']) },
            { name: '30-60', data: aggregations.map((i) => i['30-60']) },
            { name: '60-90', data: aggregations.map((i) => i['60-90']) },
            { name: '90+', data: aggregations.map((i) => i['90+']) },
        ];
    }
    async getAllSkuValues(borrowerId, startDate, endDate) {
        const bbcDates = await (0, bbcDates_db_1.getBBCDatesForPeriod)(borrowerId, new Date(startDate), new Date(endDate));
        const sheetGroups = await (0, bbcSheets_db_1.getBBCSheetsByTypeGroupedByBBC)(bbcDates.map((bbcDate) => bbcDate._id.toString()), collaterals_enum_1.ECollaterals.INVENTORY);
        const aggregationPromises = sheetGroups.map((sheetGroup) => (0, inventories_1.aggregateAllValuesForBbc)(sheetGroup.sheets.map((sheet) => new mongoose_1.default.Types.ObjectId(String(sheet._id)))));
        const aggregations = await Promise.all(aggregationPromises);
        const chartData = [];
        function toEntries(a) {
            return a.map((value, index) => [index, value]);
        }
        const allSheets = await (0, collaterals_db_1.getBBCSheetsForBorrowerAndType)(borrowerId, collaterals_enum_1.ECollaterals.INVENTORY);
        const allSheetsIds = allSheets.map((sheet) => sheet._id);
        const uniqSkus = [...new Set(aggregations.reduce((acc, skuGroup) => {
                return [...acc, ...skuGroup.map((skuObject) => skuObject.sku)];
            }, []))];
        const skusWithDates = uniqSkus.reduce((acc, sku) => ({ ...acc, [sku]: null }), {});
        await Promise.all(uniqSkus.map(async (sku) => {
            const firstSeen = (await this.getFirstSeenNew(allSheetsIds.map((id) => new mongoose_1.default.Types.ObjectId(String(id))), sku)).pop();
            skusWithDates[sku] = firstSeen.bbcDate;
        }));
        for (const [bbcIndex, item] of toEntries(aggregations)) {
            chartData.push({
                name: (0, dayjs_1.default)(bbcDates[bbcIndex]?.bbcDate).format('YYYY/MM/DD'),
                data: [],
            });
            for (const [itemIndex, skuAndValue] of toEntries(item)) {
                chartData[bbcIndex].data.push([
                    itemIndex + 1,
                    skuAndValue.value,
                    null,
                    {
                        sku: skuAndValue.sku,
                        skuDescription: skuAndValue.skuDescription,
                        category: skuAndValue.category,
                        firstSeen: (0, dayjs_1.default)(skusWithDates[skuAndValue.sku]).format('YYYY/MM/DD'),
                    },
                ]);
            }
        }
        return chartData;
    }
    async getFirstSeenNew(sheetIds, sku) {
        return InventoryItem_model_1.InventoryItemModel.aggregate([
            {
                $match: {
                    'bbcSheetId': { $in: sheetIds },
                    'sku': sku,
                },
            },
            {
                $lookup: {
                    from: 'bbcsheets',
                    localField: 'bbcSheetId',
                    foreignField: '_id',
                    as: 'bbcSheet',
                },
            },
            {
                $unwind: {
                    path: '$bbcSheet',
                },
            },
            {
                $lookup: {
                    from: 'bbcdates',
                    localField: 'bbcSheet.bbcDateId',
                    foreignField: '_id',
                    as: 'bbc',
                },
            },
            {
                $unwind: {
                    path: '$bbc',
                },
            },
            {
                $sort: {
                    'bbc.bbcDate': 1,
                },
            },
            {
                $limit: 1,
            },
            {
                $project: {
                    '_id': 0,
                    'bbcDate': '$bbc.bbcDate',
                },
            },
        ]);
    }
    async getInconsistentData(bbcDateId) {
        return (0, inconsistent_data_1.getInconsistentData)({ bbcDateId: new mongoose_1.default.Types.ObjectId(bbcDateId) });
    }
    async getUnitCostDifference(borrowerId) {
        return (0, unit_cost_difference_1.getUnitCostDifference)({ borrowerId: new mongoose_1.default.Types.ObjectId(borrowerId) });
    }
    async getExposures(borrowerId, useCustomerGroup) {
        const latestThree = await (0, bbcSheets_db_1.getUniqueDates)(borrowerId, 3, collaterals_enum_1.ECollaterals.INVENTORY);
        const aggregationPromises = latestThree.map((bbcDate) => useCustomerGroup
            ? (0, inventories_1.aggregateBbcExposuresGrouped)(bbcDate.ids)
            : (0, inventories_1.aggregateBbcExposures)(bbcDate.ids));
        const aggregations = await Promise.all(aggregationPromises);
        const allCategoryNames = [];
        const formattedSeriesData = [
            { name: latestThree[0]?.bbcDate, data: [] },
            { name: latestThree[1]?.bbcDate, data: [] },
            { name: latestThree[2]?.bbcDate, data: [] },
        ];
        aggregations.forEach((setOfBbcExposures) => {
            setOfBbcExposures.topItemsForBbc.map((topItem) => {
                if (!allCategoryNames.includes(topItem.name)) {
                    allCategoryNames.push(topItem.name);
                }
            });
        });
        aggregations.forEach((setOfBbcExposures, i) => {
            allCategoryNames.map((categoryName) => {
                const foundValue = setOfBbcExposures.topItemsForBbc.find((topItem) => topItem.name === categoryName);
                const convertedValue = foundValue ? (0, numbers_helper_1.convertToPercentage)(foundValue.totalItemValue, setOfBbcExposures.inventoryTotal) : 0;
                formattedSeriesData[i].data.push(convertedValue);
            });
        });
        return { allCategoryNames, formattedSeriesData };
    }
    async getInventoryTurn(borrowerId, startDate, endDate) {
        return (0, turn_1.getInventoryTurn)({
            borrowerId: new mongoose_1.default.Types.ObjectId(borrowerId),
            startDate: new Date(startDate),
            endDate: new Date(endDate),
        });
    }
    async getInvoiceMovement(borrowerId, bbcDateId) {
        return (0, movement_1.getInvoiceMovement)({
            borrowerId: new mongoose_1.default.Types.ObjectId(borrowerId),
            bbcDateId: new mongoose_1.default.Types.ObjectId(bbcDateId),
        });
    }
    async getContras(borrowerId, startDate, endDate) {
        const bbcDates = await (0, bbcDates_db_1.getBBCDatesByBorrower)(borrowerId);
        const bbcIds = bbcDates.map((bbc) => bbc._id.toString());
        const bbcSheets = await (0, bbcSheets_db_1.getBBCSheetsByType)(bbcIds, collaterals_enum_1.ECollaterals.ACCOUNT_PAYABLE);
        const aps = await (0, payable_accounts_1.getBBCAPByAPPeriod)(bbcSheets.map((bbcSheet) => new mongoose_1.default.Types.ObjectId(String(bbcSheet._id))), startDate, endDate);
        const customerAPGroups = await (0, groups_1.getAPCustomerGroups)(borrowerId);
        const contras = [];
        await Promise.all(aps.map(async (ap) => {
            const contra = {
                invoiceDate: ap.apDate,
                customer: ap.customerName,
                invoiceNumber: ap.poNumber,
                amount: ap.amount,
                newAPName: ap.customerName,
                contra: 0,
            };
            const customerAPGroup = customerAPGroups.find((group) => group.items === ap.customerName);
            if (customerAPGroup) {
                const mappedGroup = await (0, groups_1.getMappedGroups)({ group2: customerAPGroup._id.toString() });
                if (mappedGroup && mappedGroup.length) {
                    const customerGroup = await CustomerGroup_model_1.CustomerGroupModel.findById(mappedGroup[0].group1);
                    if (customerGroup) {
                        contra.newAPName = customerAPGroup.groupName;
                        contra.contra = 1;
                    }
                }
            }
            contras.push(contra);
        }));
        return contras.sort((a, b) => new Date(a.invoiceDate).valueOf() - new Date(b.invoiceDate).valueOf());
    }
    async getExtension(borrowerId, startDate, endDate) {
        return (0, extension_1.getExtension)({
            borrowerId: new mongoose_1.default.Types.ObjectId(borrowerId),
            startDate: new Date(startDate),
            endDate: new Date(endDate),
        });
    }
    async compareInventories(bbcDateId) {
        return await (0, invoice_difference_1.getInventoryDifference)({ bbcDateId: new mongoose_1.default.Types.ObjectId(bbcDateId) });
    }
}
exports.InventoryService = InventoryService;
