"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.completeLoad = void 0;
const typeorm_1 = require("typeorm");
const auth_base_1 = require("@things-factory/auth-base");
const integration_accounting_1 = require("@things-factory/integration-accounting");
const sales_base_1 = require("@things-factory/sales-base");
const worksheet_base_1 = require("@things-factory/worksheet-base");
const integration_lmd_1 = require("@things-factory/integration-lmd");
const integration_powrup_1 = require("@things-factory/integration-powrup");
const setting_base_1 = require("@things-factory/setting-base");
const integration_base_1 = require("@things-factory/integration-base");
function parseNonNegativeInt(value) {
    const n = parseInt(value !== null && value !== void 0 ? value : '0', 10);
    return Number.isFinite(n) ? Math.max(0, n) : 0;
}
exports.completeLoad = {
    async completeLoad(_, { orderId, worksheetId }, context) {
        const { domain, tx, user } = context.state;
        return completeLoading(domain, tx, user, false, orderId, worksheetId);
    },
    async completeLoadPartially(_, { orderId, worksheetId }, context) {
        const { domain, tx, user } = context.state;
        return completeLoading(domain, tx, user, true, orderId, worksheetId);
    }
};
async function completeLoading(domain, tx, user, partial, orderId, worksheetId) {
    var _a, _b, _c;
    // Fetch release order - optimized to reduce DB locks (14 relations → 4 relations)
    // - orderProducts re-fetched at line 200 with fresh relations
    // - deliveryOrders re-fetched at line 109
    // - Only load essential relations needed before those re-fetches
    console.time('completeLoading - fetch releaseGood');
    const releaseGood = await tx.getRepository(sales_base_1.ReleaseGood).findOne({
        where: {
            name: orderId,
            domain: domain,
            status: (0, typeorm_1.In)([sales_base_1.ORDER_STATUS.LOADING, sales_base_1.ORDER_STATUS.PROCESSING, sales_base_1.ORDER_STATUS.PARTIAL_PROCESSING])
        },
        relations: ['bizplace', 'bizplace.domain', 'orderInventories', 'lastMileDelivery']
    });
    console.timeEnd('completeLoading - fetch releaseGood');
    if (!releaseGood) {
        throw new Error('Release good not found or not in a valid status');
    }
    const orderInventories = releaseGood.orderInventories;
    const worksheet = await tx.getRepository(worksheet_base_1.Worksheet).findOne({
        where: {
            id: worksheetId,
            domain: domain,
            status: (0, typeorm_1.In)([worksheet_base_1.WORKSHEET_STATUS.EXECUTING, worksheet_base_1.WORKSHEET_STATUS.PARTIAL_EXECUTING]),
            type: worksheet_base_1.WORKSHEET_TYPE.LOADING
        },
        relations: ['worksheetDetails']
    });
    if (!worksheet) {
        throw new Error('Loading worksheet not found or not in a valid status');
    }
    const currentTime = new Date();
    //complete load
    if (!partial) {
        //validate all order inventories are loaded
        if (orderInventories.some(oi => oi.status !== sales_base_1.ORDER_INVENTORY_STATUS.LOADED &&
            oi.status !== sales_base_1.ORDER_INVENTORY_STATUS.RETURNING &&
            oi.status !== sales_base_1.ORDER_INVENTORY_STATUS.TERMINATED &&
            oi.status !== sales_base_1.ORDER_INVENTORY_STATUS.MISSING)) {
            throw new Error('Item is not completely loaded');
        }
        //update ro transport option depending on do types
        let deliveryOrders = await tx.getRepository(sales_base_1.DeliveryOrder).find({
            where: { releaseGood: releaseGood, domain: domain },
            relations: ['releaseGood']
        });
        if (deliveryOrders.length > 0) {
            let ownTransport = 0;
            let warehouseTransport = 0;
            let ownTransportFlag;
            for (let i = 0; i < deliveryOrders.length; i++) {
                let deliveryOrder = deliveryOrders[i];
                deliveryOrder.ownCollection ? ownTransport++ : warehouseTransport++;
            }
            ownTransportFlag = ownTransport > warehouseTransport;
            releaseGood.ownTransport = ownTransportFlag;
        }
        // If minimum seal is 0 (or invalid/negative), auto-close any open totes for this order.
        // This supports the "0 seal required" scenario without blocking tote usage during QC/loading.
        try {
            let sealNoSetting = await tx.getRepository(setting_base_1.Setting).findOne({
                where: {
                    domain: (_a = releaseGood.bizplace) === null || _a === void 0 ? void 0 : _a.domain,
                    name: 'minimum-seal-number'
                }
            });
            if (!sealNoSetting) {
                sealNoSetting = await tx.getRepository(setting_base_1.Setting).findOne({
                    where: {
                        domain,
                        name: 'minimum-seal-number'
                    }
                });
            }
            const minimumSealRequired = parseNonNegativeInt(sealNoSetting === null || sealNoSetting === void 0 ? void 0 : sealNoSetting.value);
            if (minimumSealRequired <= 0) {
                await tx
                    .getRepository(sales_base_1.OrderTote)
                    .createQueryBuilder()
                    .update(sales_base_1.OrderTote)
                    .set({ closedDate: currentTime, updater: user })
                    .where('release_good_id = :releaseGoodId', { releaseGoodId: releaseGood.id })
                    .andWhere('closed_date IS NULL')
                    .execute();
            }
        }
        catch (e) {
            // do not fail completion if tote auto-close fails
            console.error('Failed to auto-close order totes:', e);
        }
        await updateOrderInventories(tx, orderInventories, sales_base_1.ORDER_INVENTORY_STATUS.TERMINATED, user, currentTime);
        await updateWorksheet(tx, worksheet, worksheet_base_1.WORKSHEET_STATUS.DONE, user, currentTime);
        (0, integration_base_1.webhookHandler)(releaseGood, releaseGood.bizplace, integration_base_1.WebhookEventsEnum.LoadingCompleted);
        await updateReleaseGood(tx, releaseGood, sales_base_1.ORDER_STATUS.DONE, user, currentTime);
        if (((_b = releaseGood === null || releaseGood === void 0 ? void 0 : releaseGood.lastMileDelivery) === null || _b === void 0 ? void 0 : _b.isTms) &&
            deliveryOrders.length > 1 &&
            ((_c = releaseGood === null || releaseGood === void 0 ? void 0 : releaseGood.lastMileDelivery) === null || _c === void 0 ? void 0 : _c.status) === 'active') {
            const tmsService = (0, integration_lmd_1.getTmsService)(releaseGood.lastMileDelivery.platform);
            tmsService.createAndUpdateShipment(releaseGood, deliveryOrders);
        }
        const orderSource = releaseGood.source;
        switch (orderSource) {
            case auth_base_1.ApplicationType.XILNEX:
                const xilnex = await tx.getRepository(integration_accounting_1.Account).findOne({
                    where: { domain: releaseGood.bizplace.domain, status: 'active', platform: 'xilnex' },
                    relations: ['domain']
                });
                if (xilnex) {
                    const xilnexCtrl = new worksheet_base_1.XilnexController(tx, domain, user);
                    await xilnexCtrl.deliveryTransferNote(tx, xilnex, releaseGood.id);
                }
                break;
            case auth_base_1.ApplicationType.POWRUP:
                const powrup = await tx.getRepository(integration_powrup_1.Powrup).findOne({ active: true, platform: 'POWRUP' });
                const rtsTriggerLevel = await tx
                    .getRepository(setting_base_1.Setting)
                    .findOne({
                    where: { domain, category: 'id-rule', name: 'rts-trigger-level' }
                })
                    .then((setting) => {
                    return parseInt((setting === null || setting === void 0 ? void 0 : setting.value) || 0);
                });
                if (powrup && rtsTriggerLevel === 3) {
                    (0, typeorm_1.getManager)().transaction(async (txMgr) => {
                        const powrupController = new sales_base_1.PowrupController();
                        const hasPackage = (await txMgr.getRepository(sales_base_1.OrderPackage).count({ where: { releaseGood: { id: releaseGood.id } } })) > 0;
                        if (!hasPackage && !releaseGood.marketPackCallSuccess) {
                            const orderProducts = await txMgr.getRepository(sales_base_1.OrderProduct).find({
                                where: { releaseGood: { id: releaseGood.id } },
                                relations: ['product', 'productDetail']
                            });
                            await powrupController.packOrder(powrup, Object.assign(Object.assign({}, releaseGood), { orderProducts }), domain, user, txMgr);
                        }
                        await powrupController.initiateShipment(powrup, releaseGood, domain, user, txMgr);
                    });
                }
                break;
            default:
                break;
        }
    }
    else {
        await updateOrderInventories(tx, orderInventories, sales_base_1.ORDER_INVENTORY_STATUS.TERMINATED, user, currentTime);
        await updateWorksheet(tx, worksheet, worksheet_base_1.WORKSHEET_STATUS.PARTIAL_EXECUTING, user, currentTime);
        await updateReleaseGood(tx, releaseGood, sales_base_1.ORDER_STATUS.PARTIAL_PROCESSING, user, currentTime);
    }
}
async function updateOrderInventories(tx, orderInventories, status, user, currentTime) {
    for (const oi of orderInventories) {
        if (oi.status === sales_base_1.ORDER_INVENTORY_STATUS.LOADED) {
            await tx.getRepository(sales_base_1.OrderInventory).update(oi.id, {
                status,
                updater: user,
                updatedAt: currentTime
            });
        }
    }
}
async function updateWorksheet(tx, worksheet, status, user, currentTime) {
    await tx.getRepository(worksheet_base_1.Worksheet).update(worksheet.id, {
        status,
        updater: user,
        updatedAt: new Date(),
        endedAt: status === worksheet_base_1.WORKSHEET_STATUS.DONE ? new Date() : null
    });
}
async function updateReleaseGood(tx, releaseGood, status, user, currentTime) {
    await tx.getRepository(sales_base_1.ReleaseGood).update(releaseGood.id, {
        status,
        ownTransport: releaseGood.ownTransport,
        updater: user,
        updatedAt: new Date()
    });
    if (status === sales_base_1.ORDER_STATUS.DONE) {
        (0, integration_base_1.webhookHandler)(releaseGood, releaseGood.bizplace, integration_base_1.WebhookEventsEnum.ReleaseOrderCompleted);
    }
}
//# sourceMappingURL=complete-load.js.map