package nccloud.web.mmpac.pickm.action;

import nc.itf.ic.m4a.IGeneralInMaintain;
import nc.itf.mmpac.pickm.IPickmQueryService;
import nc.itf.mmpac.pickm.IPickmTransTypeService;
import nc.itf.uap.pf.busiflow.PfButtonClickContext;
import nc.pubitf.mmpac.mo.pickm.IMoPubService4Pickm;
import nc.util.mmf.busi.service.PFPubService;
import nc.util.mmf.framework.base.MMMapUtil;
import nc.util.mmf.framework.base.MMNumberUtil;
import nc.util.mmf.framework.base.MMValueCheck;
import nc.vo.bd.material.prod.MaterialProdModeEnum;
import nc.vo.ic.m4a.entity.GeneralInHeadVO;
import nc.vo.ic.m4a.entity.GeneralInVO;
import nc.vo.mmpac.mo.param.MoQueryParam4Pickm;
import nc.vo.mmpac.pickm.consts.PickmLangConsts;
import nc.vo.mmpac.pickm.entity.AggPickmVO;
import nc.vo.mmpac.pickm.entity.PickmHeadVO;
import nc.vo.mmpac.pickm.entity.PickmItemVO;
import nc.vo.mmpac.pickm.enumeration.FbillstatusEnum;
import nc.vo.mmpac.pickm.enumeration.FitemsourceEnum;
import nc.vo.mmpac.pickm.enumeration.FsourcetypeEnum;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.compiler.PfParameterVO;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pubapp.pattern.pub.MapList;
import nc.vo.scmpub.res.billtype.ICBillType;
import nccloud.dto.mmpac.pickm.pub.entity.PickmQueryInfoDTO;
import nccloud.framework.core.exception.ExceptionUtils;
import nccloud.framework.core.json.IJson;
import nccloud.framework.service.ServiceLocator;
import nccloud.framework.web.action.itf.ICommonAction;
import nccloud.framework.web.container.IRequest;
import nccloud.framework.web.json.JsonFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 备料计划转库存的其它入库
 *
 * @author mzr
 * @date 2025/7/4
 */
public class PickmToGeneralInAction implements ICommonAction {
    @Override
    public Object doAction(IRequest request) {
        String read = request.read();
        IJson json = JsonFactory.create();
        try {
            // 获取请求查询信息
            PickmQueryInfoDTO paramDTO = json.fromJson(read, PickmQueryInfoDTO.class);
            // 获取主键
            String[] cpickmids = paramDTO.getCpickmids();
            String[] cpickmbids = paramDTO.getCpickmbids();
            if (MMValueCheck.isEmpty(cpickmids) && (null == cpickmbids || cpickmbids.length == 0)) {
                return null;
            }
            AggPickmVO[] aggVOs = null;
            IPickmQueryService service = ServiceLocator.find(IPickmQueryService.class);
            if (MMValueCheck.isNotEmpty(cpickmids)) {
                aggVOs = service.queryBillsByPks(cpickmids);
            } else if (MMValueCheck.isNotEmpty(cpickmbids)) {
                aggVOs = service.queryAggPickmVObyBid(cpickmbids);
            }
            if (MMValueCheck.isEmpty(aggVOs)) {
                /*@res "单据已被修改或删除，请刷新界面重新操作！"*/
                ExceptionUtils.wrapBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("5008100_0", "05008100-0009"));
            }
            // 过滤
            AggPickmVO[] filterVOs = this.filterAggPickmVOForDirectTrans(aggVOs);
            if (MMValueCheck.isEmpty(filterVOs)) {
                ExceptionUtils.wrapBusinessException(PickmLangConsts.getErrNoDataToReqPickm());
            }
            // 转换数据
            GeneralInVO[] inVOS = convertToGeneralInVO(filterVOs, null);
            // 其它入库新增
            IGeneralInMaintain generalInMaintain = ServiceLocator.find(IGeneralInMaintain.class);
            GeneralInVO[] insertVos = generalInMaintain.insert(inVOS);
            Map<String, Object> returnMap = new HashMap<>();
            returnMap.put("data", insertVos);
            returnMap.put("success", true);
            return returnMap;
        } catch (Exception e) {
            ExceptionUtils.wrapException(e);
        }
        return null;
    }

    /**
     * 方法功能描述：批量执行VO转换，若来源及目标单据类型没有注册或传入来源单据不能转换，则抛出业务异常
     *
     * @param sourceBillVOs AggregatedValueObject[]型参数，来源单据VO数组
     * @param srcParaVo     PfParameterVO型参数，平台的运行参数类，一般为NULL即可
     * @return AggregatedValueObject[]型VO转换后的目标单据数组
     * @throws BusinessException 若VO转换失败，则抛出业务异常
     */
    private GeneralInVO[] convertToGeneralInVO(AggregatedValueObject[] sourceBillVOs, PfParameterVO srcParaVo)
            throws BusinessException {
        // 来源交易类型或单据类型，需要在单据类型中注册
        String srcBillOrTranstype = "55A3";
        // 目标交易类型或单据类型，需要在单据类型中注册
        String destBillOrTranstype = ICBillType.GeneralIn.getCode();
        // classifyMode int型参数，调用模式，参照PfButtonClickContext中定义，代码中调用为接口方式 ClassifyByItfdef
        int classifyMode = PfButtonClickContext.ClassifyByItfdef;
        GeneralInVO[] inVOS = (GeneralInVO[]) PFPubService.runChangeData(srcBillOrTranstype, destBillOrTranstype, sourceBillVOs, srcParaVo, classifyMode);
        if (MMValueCheck.isEmpty(inVOS)) {
            ExceptionUtils.wrapBusinessException("备料计划转换其它入库失败");
        }
        for (GeneralInVO inVO : inVOS) {
            // 其它入库单的仓库、交易类型取自【业务参数设置】的默认值
            GeneralInHeadVO head = inVO.getHead();
            head.setCtrantypeid("01");
            head.setVtrantypecode("01");
        }
        return inVOS;
    }

    /*
     * 过滤备料计划 完成态，非生产，来源生产订单完工或关闭，表体非发料，非备料，可执行量<0
     */
    private AggPickmVO[] filterAggPickmVOForDirectTrans(AggPickmVO[] aggvos) throws BusinessException {
        if (aggvos == null) {
            return null;
        }
        List<AggPickmVO> resultVO = new ArrayList<AggPickmVO>();
        // 查询生产订单参数
        List<MoQueryParam4Pickm> moParams = new ArrayList<MoQueryParam4Pickm>();
        MapList<Integer, String> moidMap = new MapList<Integer, String>();
        List<String> transTypeIds = new ArrayList<String>();
        for (AggPickmVO aggvo : aggvos) {
            PickmHeadVO head = aggvo.getParentVO();
            // 完成态
            if (FbillstatusEnum.FINISH_STATE.equalsValue(head.getFbillstatus())) {
                continue;
            }
            // 表体为空
            if (MMValueCheck.isEmpty(aggvo.getChildren(PickmItemVO.class))) {
                continue;
            }

            // 行判断是否符合
            PickmItemVO[] items = (PickmItemVO[]) aggvo.getChildren(PickmItemVO.class);
            List<PickmItemVO> itemList = new ArrayList<PickmItemVO>();
            for (PickmItemVO item : items) {
                // 发料为否
                if (!MMValueCheck.isTrue(item.getBcandeliver())) {
                    continue;
                }
                // 备料来源不是备料
                if (!FitemsourceEnum.PREPARE.equalsValue(item.getFitemsource())) {
                    continue;
                }
                // 2、需求主数量>0；
                // 需求主数量=计划出库数量-累计出库数量-累计委外数量-累计待转数量-累计入库数量-预留；
                if (!MMNumberUtil.isGtZero(MMNumberUtil.sub(item.getNplanoutnum(), item.getNaccoutnum(),
                        item.getNatpnum(), item.getNpscnum(), item.getNtransnum(), item.getNtransinnum()))) {
                    continue;
                }
                itemList.add(item);
            }
            if (MMValueCheck.isEmpty(itemList)) {
                continue;
            }
            AggPickmVO vo = new AggPickmVO();
            vo.setParent(head);
            vo.setChildren(PickmItemVO.class, itemList.toArray(new PickmItemVO[0]));
            resultVO.add(vo);
            transTypeIds.add(head.getVbusitypeid());
            // 如果来源于生产订单,构造查询生产订单参数
            if (FsourcetypeEnum.MOBILL_STATE.equalsValue(head.getFsourcetype())) {
                // 流程
                if (MaterialProdModeEnum.PRODMODE_PROD.equalsValue(head.getFprodmode())) {
                    moidMap.put(head.getFprodmode(), head.getCsourcebillrowid());
                }
                // 离散
                if (MaterialProdModeEnum.PRODMODE_SEPPROD.equalsValue(head.getFprodmode())) {
                    moidMap.put(head.getFprodmode(), head.getCsourcebillid());
                }
            }
        }
        // 过滤后结果为空
        if (MMValueCheck.isEmpty(resultVO)) {
            return null;
        }
        // 交易类型
        IPickmTransTypeService wwService = ServiceLocator
                .find(IPickmTransTypeService.class);
        Map<String, Boolean> isWWPickm =
                wwService.isWWPickmTransType(transTypeIds.toArray(new String[0]));
        // 查询来源生产订单是否为完工或关闭态
        Map<String, UFBoolean> ismoFinisOrClose = new HashMap<String, UFBoolean>();
        // 来源生产订单信息为空
        if (!MMMapUtil.isEmpty(moidMap)) {
            // 构造查询生产订单参数
            for (Integer prodmode : moidMap.keySet()) {
                MoQueryParam4Pickm param = new MoQueryParam4Pickm();
                param.setProdMode(prodmode);
                param.setIds(moidMap.get(prodmode).toArray(new String[0]));
                moParams.add(param);
            }
            IMoPubService4Pickm moService = ServiceLocator
                    .find(IMoPubService4Pickm.class);
            ismoFinisOrClose =
                    moService.getMOItemFinishOrCloseStatus(moParams.toArray(new MoQueryParam4Pickm[0]));

        }
        // 循环上一轮结果，过滤来源生产订单为关闭或完工的备料 计划
        List<AggPickmVO> resultMoVO = new ArrayList<AggPickmVO>();
        for (AggPickmVO aggvo : resultVO) {
            PickmHeadVO head = aggvo.getParentVO();
            // 交易类型非生产
            if (isWWPickm.containsKey(head.getVbusitypeid())
                    && MMValueCheck.isTrue(isWWPickm.get(head.getVbusitypeid()))) {
                continue;
            }
            // 如果不是来源于生产订单,构造查询生产订单参数
            if (!FsourcetypeEnum.MOBILL_STATE.equalsValue(head.getFsourcetype())) {
                resultMoVO.add(aggvo);
                continue;
            }
            String moid = "";
            // 流程
            if (MaterialProdModeEnum.PRODMODE_PROD.equalsValue(head.getFprodmode())) {
                moid = head.getCsourcebillrowid();
            }
            // 离散
            if (MaterialProdModeEnum.PRODMODE_SEPPROD.equalsValue(head.getFprodmode())) {
                moid = head.getCsourcebillid();
            }
            // 来源生产订单为完工或关闭态
            if (MMValueCheck.isNotEmpty(ismoFinisOrClose) && ismoFinisOrClose.containsKey(moid)
                    && MMValueCheck.isTrue(ismoFinisOrClose.get(moid))) {
                continue;
            }
            resultMoVO.add(aggvo);
        }
        if (MMValueCheck.isEmpty(resultMoVO)) {
            return null;
        }
        return resultMoVO.toArray(new AggPickmVO[0]);
    }
}
