package nc.bs.pu.m21.plugin;

import java.util.*;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import nc.bs.framework.common.NCLocator;
import nc.bs.logging.Log;
import nc.bs.pub.common.PfServiceScmUtil;
import nc.bs.pub.pa.PreAlertObject;
import nc.bs.pub.pa.PreAlertReturnType;
import nc.bs.pub.taskcenter.BgWorkingContext;
import nc.bs.pub.taskcenter.IBackgroundWorkPlugin;
import nc.bs.pubapp.AppBsContext;
import nc.impl.pubapp.pattern.data.vo.VOQuery;
import nc.impl.pubapp.pattern.data.vo.VOUpdate;
import nc.impl.pubapp.pattern.page.db.IDDBPage;
import nc.util.mmf.framework.base.MMArrayUtil;
import nc.util.mmf.framework.db.MMSqlBuilder;
import nc.vo.pu.m20.entity.PraybillHeaderVO;
import nc.vo.pu.m20.entity.PraybillItemVO;
import nc.vo.pu.m20.entity.PraybillVO;
import nc.vo.pu.m21.entity.OrderHeaderVO;
import nc.vo.pu.m21.entity.OrderItemVO;
import nc.vo.pu.m21.entity.OrderVO;
import nc.vo.pub.BusinessException;
import nc.vo.pub.VOStatus;
import nc.vo.pubapp.pattern.model.entity.bill.AbstractBill;
import nc.vo.scmpub.res.billtype.POBillType;
import nc.vo.scmpub.util.AppInfoContext;
import nccloud.commons.lang.ArrayUtils;
import nccloud.dto.scmpub.script.entity.SCMScriptResultDTO;
import nccloud.pubitf.riart.pflow.CloudPFlowContext;
import nccloud.pubitf.scmpub.commit.service.IBatchRunScriptService;

public class BatchTransferToPurchaseOrder implements IBackgroundWorkPlugin {
    private static final Log logger = Log.getInstance("devpoordertask");

    @Override
    public PreAlertObject executeTask(BgWorkingContext bgWorkingContext) throws BusinessException {
        logger.info("开始执行批量转换请购单到采购订单任务", this.getClass(), "executeTask");
        // 获取阈值 限制数量以及是否过滤失败
        // 限制数量 每次查询的数量
        String limitNum = (String) bgWorkingContext.getKeyMap().get("limitNum");
        // 是否过滤失败 配置true的时候 过滤 过滤条件为 vdef31 != N 配置 false时 不过滤 查询全部数据
        String filterFailed = (String) bgWorkingContext.getKeyMap().get("filterFailed");
        // 如果配置的是过滤 那么就是Y 并且 过滤条件为 vdef31 != N
        String failed = filterFailed.equals("Y") ? "N" : "";
        PreAlertObject retObj = new PreAlertObject();
        retObj.setReturnType(PreAlertReturnType.RETURNNOTHING);
        try {
            // 1. 查询满足条件的请购单聚合VO
            PraybillVO[] purchaseRequestVOs = getQualifiedPurchaseRequests(failed, limitNum);
            logger.info("查询到满足条件的请购单数量: " + purchaseRequestVOs.length, this.getClass(), "executeTask");
            if (purchaseRequestVOs.length == 0) {
                logger.info("未找到满足条件的请购单，任务结束", this.getClass(), "executeTask");
                return null;
            }
            // 循环打印请购单VO的信息
            for (PraybillVO vo : purchaseRequestVOs) {
                logger.info("请购单信息:\n");
                logger.info("单据号:" + vo.getHVO().getVbillcode(), this.getClass(), "executeTask");
            }
            // 2. 批量转换处理
            processBatchTransfer(purchaseRequestVOs);
            logger.info("批量转换请购单到采购订单完成", this.getClass(), "executeTask");
        } catch (Exception e) {
            logger.error("执行批量转换请购单到采购订单任务失败", e, this.getClass(), "executeTask");
        }
        logger.info("批量转换请购单到采购订单任务执行完成", this.getClass(), "executeTask");
        return retObj;
    }

    /**
     * 查询满足条件的请购单
     * 条件：表体请购单主数量-累计订货主数量>0，且没有行关闭
     */
    private PraybillVO[] getQualifiedPurchaseRequests(String isFilter, String limitNum) throws BusinessException {
        logger.info("开始查询满足条件的请购单", this.getClass(), "getQualifiedPurchaseRequests");
        try {
            String sql = getSql(isFilter, limitNum);
            if (sql == null) {
                logger.warn("生成的SQL为空，返回空结果", this.getClass(), "getQualifiedPurchaseRequests");
                return new PraybillVO[0];
            }
            List<PraybillVO> resultList = new ArrayList<>();
            int pageSize = 100;
            IDDBPage page = new IDDBPage(sql, pageSize);
            int pageCount = 0;
            while (page.hasNext()) {
                pageCount++;
                String[] ids = page.next();
                PraybillVO[] aggvos = getBGWorkInfo(ids);
                if (MMArrayUtil.isNotEmpty(aggvos)) {
                    resultList.addAll(Arrays.asList(aggvos));
                    logger.debug("第" + pageCount + "页处理得到聚合VO数量: " + aggvos.length, this.getClass(), "getQualifiedPurchaseRequests");
                }
            }
            logger.info("分页查询完成，总页数: " + pageCount + ", 最终结果数量: " + resultList.size(), this.getClass(), "getQualifiedPurchaseRequests");
            return resultList.toArray(new PraybillVO[resultList.size()]);
        } catch (Exception e) {
            logger.error("查询满足条件的请购单失败", e, this.getClass(), "getQualifiedPurchaseRequests");
            return new PraybillVO[0];
        }
    }

    /**
     * 构建查询SQL 查询视图
     */
    private String getSql(String isFilter, String limitNum) {
        MMSqlBuilder sb = new MMSqlBuilder();
        sb.append(" SELECT PK_PRAYBILL_B");
        sb.append(" FROM TRANS_PRAYBILL_PURCHASE");
        if (!isFilter.isEmpty()) {
            sb.appendNotEqual(" WHERE vdef31 ", isFilter);
        }
        if (!limitNum.equals("0")) {
            sb.append(" AND ROWNUM ", "<", limitNum);
        }
        String finalSql = sb.toString();
        logger.debug("SQL构建完成->" + finalSql, this.getClass(), "getSql");
        return finalSql;
    }

    /**
     * 根据ID获取请购单聚合VO
     */
    private PraybillVO[] getBGWorkInfo(String[] ids) {
        // 查询请购单表体
        VOQuery<PraybillItemVO> itemQuery = new VOQuery<>(PraybillItemVO.class);
        PraybillItemVO[] itemVOs = itemQuery.query(ids);
        if (MMArrayUtil.isEmpty(itemVOs)) {
            logger.warn("根据ID未查询到请购单表体数据", this.getClass(), "getBGWorkInfo");
            return new PraybillVO[0];
        }
        logger.debug("查询到请购单表体数量: " + itemVOs.length, this.getClass(), "getBGWorkInfo");
        // 获取表头ID
        List<String> headerIds = new ArrayList<>();
        for (PraybillItemVO itemVO : itemVOs) {
            if (!headerIds.contains(itemVO.getPk_praybill())) {
                headerIds.add(itemVO.getPk_praybill());
            }
        }
        logger.debug("需要查询的表头ID数量: " + headerIds.size(), this.getClass(), "getBGWorkInfo");
        // 查询请购单表头
        VOQuery<PraybillHeaderVO> headerQuery = new VOQuery<>(PraybillHeaderVO.class);
        PraybillHeaderVO[] headerVOs = headerQuery.query(headerIds.toArray(new String[headerIds.size()]));
        logger.debug("查询到请购单表头数量: " + (headerVOs != null ? headerVOs.length : 0), this.getClass(), "getBGWorkInfo");
        return this.getAggvofromHeaderAndItem(headerVOs, itemVOs);
    }

    /**
     * 组装采购订单聚合VO
     */
    private PraybillVO[] getAggvofromHeaderAndItem(PraybillHeaderVO[] headerVOs, PraybillItemVO[] itemVOs) {
        if (MMArrayUtil.isEmpty(headerVOs) || MMArrayUtil.isEmpty(itemVOs)) {
            logger.warn("表头或表体数据为空，无法组装聚合VO", this.getClass(), "getAggvofromHeaderAndItem");
            return new PraybillVO[0];
        }
        List<PraybillVO> aggList = new ArrayList<>();
        for (PraybillHeaderVO headerVO : headerVOs) {
            List<PraybillItemVO> itemList = new ArrayList<>();
            for (PraybillItemVO itemVO : itemVOs) {
                if (headerVO.getPk_praybill().equals(itemVO.getPk_praybill())) {
                    itemList.add(itemVO);
                }
            }
            if (!itemList.isEmpty()) {
                PraybillVO aggVO = new PraybillVO();
                aggVO.setParentVO(headerVO);
                aggVO.setChildrenVO(itemList.toArray(new PraybillItemVO[itemList.size()]));
                aggList.add(aggVO);
            }
        }
        logger.debug("聚合VO组装完成，数量: " + aggList.size(), this.getClass(), "getAggvofromHeaderAndItem");
        return aggList.toArray(new PraybillVO[aggList.size()]);
    }

    /**
     * 批量转换请购单到采购订单
     */
    private void processBatchTransfer(PraybillVO[] vos) {
        logger.info("开始批量转换请购单到采购订单，请购单数量: " + vos.length, this.getClass(), "processBatchTransfer");
        // 调用单据转换规则生成采购订单（20->21）
        OrderVO[] orderVOs = PfServiceScmUtil.exeVOChangeByBillItfDef("20", "21", vos);
        if (orderVOs == null || orderVOs.length == 0) {
            logger.warn("单据转换未生成任何采购订单", this.getClass(), "processBatchTransfer");
            return;
        }
        for (OrderVO orderVO : orderVOs) {
            // 对采购订单赋值行号
            OrderHeaderVO hvo = orderVO.getHVO();
            hvo.setStatus(2);
            OrderItemVO[] bvo = orderVO.getBVO();
            for (int j = 0; j < bvo.length; j++) {
                int rowNum = (j + 1) * 10;
                bvo[j].setStatus(2);
                bvo[j].setCrowno(String.valueOf(rowNum));
            }
        }
        // 批量处理
        processBatch(vos, orderVOs);
    }

    private void processBatch(PraybillVO[] vos, OrderVO[] orderVOs) {
        CloudPFlowContext cloudContext = this.getCloudPFlowContext(orderVOs);
        // 每次检查之前全部设置为成功
        Arrays.stream(vos).forEach(currentVO -> {
            PraybillHeaderVO hvo = currentVO.getHVO();
            hvo.setVdef30("success");
            hvo.setVdef31("Y");
            hvo.setStatus(VOStatus.UPDATED);
        });
        if (orderVOs.length == 1) {
            PraybillVO singleVO = vos[0];
            PraybillHeaderVO singleHVO = singleVO.getHVO();
            try {
                (NCLocator.getInstance().lookup(IBatchRunScriptService.class)).runBacth(cloudContext, OrderVO.class);
            } catch (Exception e) {
                singleHVO.setVdef30(e.getMessage().substring(0, !e.getMessage().isEmpty() && e.getMessage().length() < 300 ? e.getMessage().length() : 300));
                singleHVO.setVdef31("N");
                singleHVO.setStatus(VOStatus.UPDATED);
                logger.error("单个处理时失败", e, this.getClass(), "processBatch");
            }
            updatePrayBillVOs(List.of(singleVO));
            return;
        }
        SCMScriptResultDTO scriptResult = ((IBatchRunScriptService) NCLocator.getInstance().lookup(IBatchRunScriptService.class)).runBacth(cloudContext, OrderVO.class);
        AbstractBill[] sucessVOs = scriptResult.getSucessVOs();
        // 对生成的采购订单进行日志信息记录
        sucessVOs = scriptResult.getSucessVOs();
        logger.info("批量处理成功,采购订单信息如下:\n");
        for (AbstractBill sucessVO : sucessVOs) {
            OrderVO orderVO = (OrderVO) sucessVO;
            logger.info("采购订单主键" + orderVO.getHVO().getPk_order(), this.getClass(), "processBatch");
            logger.info("采购订单信息:" + JSONObject.toJSONString(orderVO.getHVO()), this.getClass(), "processBatch");
        }
        // 要进行批量更新的数组
        List<PraybillVO> failedHVOList = new ArrayList<>(vos.length - sucessVOs.length);
        Map<Integer, String> errorMessageMap = scriptResult.getErrorMessageMap();
        // 记录失败信息
        if (!errorMessageMap.isEmpty()) {
            errorMessageMap.keySet().forEach(key -> {
                String errMsg = errorMessageMap.get(key) == null ? "" : errorMessageMap.get(key);
                PraybillVO vo = vos[key];
                PraybillHeaderVO hvo = vo.getHVO();
                hvo.setVdef30(errMsg.substring(0, Math.min(errMsg.length(), 300)));
                hvo.setVdef31("N");
                hvo.setStatus(VOStatus.UPDATED);
                failedHVOList.add(vo);
                logger.warn("单据转换生成采购订单时发生错误: " + scriptResult.getErrorMessage(), this.getClass(), "processBatchTransfer");
            });
        }
        updatePrayBillVOs(failedHVOList);
    }

    private void updatePrayBillVOs(List<PraybillVO> hvoList) {
        PraybillHeaderVO[] hvoBatchUpdatedList = {};
        if (hvoList.isEmpty()) {
            logger.warn("批量更新请购单表头失败,获取表头数组长度为0", this.getClass(), "processBatchTransfer");
            return;
        }
        for (PraybillVO hvo : hvoList) {
            hvoBatchUpdatedList = ArrayUtils.add(hvoBatchUpdatedList, hvo.getHVO());
            logger.info("更新请购单表头: " + hvo.getHVO().getPk_praybill(), this.getClass(), "processBatchTransfer");
        }
        if (hvoBatchUpdatedList.length == 0) {
            logger.warn("批量更新请购单表头失败,需要更新的数组为0", this.getClass(), "processBatchTransfer");
            return;
        }
        String[] headupname = new String[]{"vdef30", "vdef31"};
        VOUpdate<PraybillHeaderVO> headupsrv = new VOUpdate<>();
        headupsrv.update(hvoBatchUpdatedList, headupname);
    }

    private CloudPFlowContext getCloudPFlowContext(OrderVO[] vos) {
        CloudPFlowContext context = new CloudPFlowContext();
        context.setActionName("SAVEBASE");
        context.setBillType(POBillType.Order.getCode());
        context.setBillVos(vos);
        context.setUserObj(null);
        AppInfoContext.setBtnCode("Save");
        return context;
    }
}
