"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findLoadableReleaseGood = void 0;
const warehouse_base_1 = require("@things-factory/warehouse-base");
const sales_base_1 = require("@things-factory/sales-base");
/**
 * Helper function to get all inventory counts in a single query
 * Returns counts for LOADING status, LOADED status, and total
 */
async function getInventoryCounts(tx, domainId, releaseGoodId, binLocationId) {
    const qb = tx
        .getRepository(sales_base_1.OrderInventory)
        .createQueryBuilder('orderInventory')
        .select('COUNT(*)', 'total')
        .addSelect(`SUM(CASE WHEN orderInventory.status = :loadingStatus THEN 1 ELSE 0 END)`, 'loadingTotal')
        .addSelect(`SUM(CASE WHEN orderInventory.status = :loadedStatus THEN 1 ELSE 0 END)`, 'loadedTotal')
        .where('orderInventory.release_good_id = :releaseGoodId', { releaseGoodId })
        .andWhere('orderInventory.domain_id = :domainId', { domainId })
        .setParameter('loadingStatus', sales_base_1.ORDER_INVENTORY_STATUS.LOADING)
        .setParameter('loadedStatus', sales_base_1.ORDER_INVENTORY_STATUS.LOADED);
    if (binLocationId) {
        qb.andWhere('orderInventory.bin_location_id = :binLocationId', { binLocationId });
    }
    const result = await qb.getRawOne();
    const loadingTotal = parseInt(result.loadingTotal) || 0;
    const loadedTotal = parseInt(result.loadedTotal) || 0;
    return {
        loadingTotal,
        loadingCompleted: loadedTotal,
        loadedTotal,
        loadedCompleted: loadedTotal,
        total: parseInt(result.total) || 0
    };
}
/**
 * Assigns itemCounts and tabCounts to a release good based on inventory counts
 *
 * Business logic for "completed" items:
 * - QC tab: completed = items that passed QC (LOADING + LOADED status)
 * - LOADING tab: completed = items that were loaded (LOADED status)
 * - LOADED tab: completed = items that are loaded (LOADED status)
 */
function assignCountsToReleaseGood(releaseGood, counts, tabName, isBinScan = false) {
    const { loadingTotal, loadingCompleted, loadedTotal, loadedCompleted, total } = counts;
    // Calculate completed count for current tab (backward compatibility)
    // For QC tab: completed = items that passed QC (LOADING + LOADED)
    // For LOADING/LOADED tabs: completed = items that are loaded (LOADED)
    // This logic applies to both BIN scan and ORDER scan
    const currentCompleted = tabName === 'QC' ? loadingTotal + loadedTotal : loadedTotal;
    // Backward compatibility: itemCounts for current tab
    releaseGood['itemCounts'] = {
        total,
        pending: total - currentCompleted
    };
    // tabCounts for both LOADING and LOADED tabs
    releaseGood['tabCounts'] = {
        LOADING: {
            total: loadingTotal,
            completed: loadingCompleted,
            pending: loadingTotal - loadingCompleted
        },
        LOADED: {
            total: loadedTotal,
            completed: loadedCompleted,
            pending: loadedTotal - loadedCompleted
        }
    };
}
exports.findLoadableReleaseGood = {
    async findLoadableReleaseGood(_, { orderNo, tabName }, context) {
        const { domain, tx } = context.state;
        let releaseGoods = [];
        let foundReleaseGood = await tx
            .getRepository(sales_base_1.ReleaseGood)
            .createQueryBuilder('releaseGood')
            .where('releaseGood.domain_id = :domainId', { domainId: domain.id })
            .andWhere('releaseGood.name = :orderNo', { orderNo })
            .andWhere('releaseGood.status IN (:...status)', {
            status: [
                sales_base_1.ORDER_STATUS.SORTING,
                sales_base_1.ORDER_STATUS.LOADING,
                sales_base_1.ORDER_STATUS.PROCESSING,
                sales_base_1.ORDER_STATUS.PARTIAL_PROCESSING,
                sales_base_1.ORDER_STATUS.DONE
            ]
        })
            .getOne();
        if (foundReleaseGood && foundReleaseGood.status == sales_base_1.ORDER_STATUS.DONE) {
            throw new Error('This order is DONE');
        }
        else if (foundReleaseGood) {
            // Get all counts in a single query
            const counts = await getInventoryCounts(tx, domain.id, foundReleaseGood.id);
            assignCountsToReleaseGood(foundReleaseGood, counts, tabName, false);
            releaseGoods.push(foundReleaseGood);
            return releaseGoods;
        }
        else {
            const binLocation = await tx.getRepository(warehouse_base_1.Location).findOne({
                where: { domain, name: orderNo }
            });
            if (binLocation) {
                // BIN scan: Find all OrderInventory linked to this BIN regardless of status
                // This allows UI to see orders even when all items are LOADED (so it can auto-switch to LOADED tab)
                const orderInventoryByBin = await tx
                    .getRepository(sales_base_1.OrderInventory)
                    .createQueryBuilder('orderInventory')
                    .innerJoinAndSelect('orderInventory.releaseGood', 'releaseGood')
                    .innerJoinAndSelect('releaseGood.bizplace', 'bizplace')
                    .innerJoinAndSelect('bizplace.domain', 'domain')
                    .leftJoinAndSelect('releaseGood.sortedBy', 'sortedBy')
                    .where('orderInventory.domain_id = :domainId', { domainId: domain.id })
                    .andWhere('orderInventory.bin_location_id = :locationId', { locationId: binLocation.id })
                    .andWhere('releaseGood.status IN (:...status)', {
                    status: [sales_base_1.ORDER_STATUS.LOADING, sales_base_1.ORDER_STATUS.PROCESSING, sales_base_1.ORDER_STATUS.PARTIAL_PROCESSING]
                })
                    // Include OrderInventory in relevant statuses for loading workflow
                    // This ensures we only get items that are part of the loading process
                    .andWhere('orderInventory.status IN (:...relevantStatuses)', {
                    relevantStatuses: [
                        sales_base_1.ORDER_INVENTORY_STATUS.SORTING,
                        sales_base_1.ORDER_INVENTORY_STATUS.LOADING,
                        sales_base_1.ORDER_INVENTORY_STATUS.LOADED
                    ]
                })
                    .orderBy('releaseGood.createdAt', 'ASC')
                    .getMany();
                // Get unique release goods
                releaseGoods = orderInventoryByBin.reduce((acc, oi) => {
                    if (!acc.some(rg => rg.id === oi.releaseGood.id)) {
                        acc.push(oi.releaseGood);
                    }
                    return acc;
                }, []);
                // Get counts for each release good (scoped to this BIN)
                for (const releaseGood of releaseGoods) {
                    const counts = await getInventoryCounts(tx, domain.id, releaseGood.id, binLocation.id);
                    assignCountsToReleaseGood(releaseGood, counts, tabName, true);
                }
            }
            // Return releaseGoods if found, even if LOADING.total=0 (UI will auto-switch to LOADED tab)
            // Only throw error if BIN has no OrderInventory items at all
            if (releaseGoods.length > 0)
                return releaseGoods;
            else {
                // No releaseGoods found in this BIN - BIN is empty or has no items in loading workflow
                const errorMessage = tabName === 'QC'
                    ? 'No items pending QC verification'
                    : tabName === 'LOADING'
                        ? 'No items found in this bin'
                        : 'No items pending dispatch';
                throw new Error(errorMessage);
            }
        }
    }
};
//# sourceMappingURL=find-loadable-release-good.js.map