package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.base;

import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesPackageContainerSnService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.rulematch.containerbind.ContainerBindManager;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.rulematch.containerbind.checkqty.MesAbstractContainerBindCheckQtyService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.util.MesPcnException;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesContainerPartsModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesContainerSnBindModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.codemaker.SnowflakeIdMaker;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.*;
import cn.estsh.i3plus.pojo.mes.repository.*;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.exception.ImppBusiException;
import cn.estsh.impp.framework.boot.util.ResultBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description : 容器条码-业务方法实现
 * @Reference :
 * @Author : logic
 * @CreateDate : 2025/6/16 10:44
 * @Modify:
 **/
@Service
@Slf4j
public class MesPackageContainerSnServiceImpl implements IMesPackageContainerSnService {

    @Autowired
    private MesContainerSnRepository mesContainerSnRepository;

    @Autowired
    private MesContainerTypeRepository mesContainerTypeRepository;

    @Autowired
    private MesContainerTypePartRepository containerTypePartRepository;

    @Autowired
    private MesContainerSnPartRepository containerSnPartRepository;

    @Autowired
    private MesContainerPackageRepository containerPackageRepository;

    @Autowired
    private MesContainerPackageDetailRepository containerPackageDetailRepository;

    @Autowired
    private SnowflakeIdMaker snowflakeIdMaker;

    @Autowired
    private MesContainerPackageDetailBindingRepository packageDetailBindingRepository;
    /**
     * 验证容器条码和零件号是否对应
     * @param organizeCode
     * @param sn
     * @return
     */
    public MesContainerSnBindModel packageContain(String organizeCode,String userName, String containSn, String sn) {
        MesContainerSn produceSn = getMesContainerSnAndValidate(organizeCode, sn);
        if (produceSn == null) {
            return null;
        }
        // 获取容器条码 并判断是否是容器与容器绑定
        MesContainerSn mesContainerSn = getMesContainerSnAndValidate(organizeCode, containSn);
        return containerToContainer(organizeCode,userName, mesContainerSn, produceSn);
    }

    private List<MesContainerSnPart> getMesContainerSnParts(String organizeCode, MesContainerSn containerSn) {
        Set<String> partNoSet = new HashSet<>();
        List<MesContainerSnPart> mesContainerSnParts = getMesContainerSnPart(organizeCode, containerSn.getContainerSn());
        if (!CollectionUtils.isEmpty(mesContainerSnParts)) {
            for (MesContainerSnPart mesContainerSnPart : mesContainerSnParts) {
                if (StringUtils.isEmpty(mesContainerSnPart.getPartNo())) {
                    continue;
                }
                partNoSet.add(mesContainerSnPart.getPartNo());
            }
        }

        List<MesContainerTypePart> mesContainerTypeParts = getMesContainerTypePart(organizeCode, containerSn.getContainerTypeCode());
        if (!CollectionUtils.isEmpty(mesContainerTypeParts)) {
            for (MesContainerTypePart mesContainerTypePart : mesContainerTypeParts) {
                if (partNoSet.contains(mesContainerTypePart.getPartNo())) {
                    continue;
                }

                MesContainerSnPart mesContainerSnPart = new MesContainerSnPart();
                mesContainerSnPart.setMatchType(mesContainerTypePart.getMatchType());
                mesContainerSnPart.setContainerTypeCode(mesContainerTypePart.getContainerTypeCode());
                mesContainerSnPart.setPartNo(mesContainerTypePart.getPartNo());

                mesContainerSnParts.add(mesContainerSnPart);
            }
        }

        if (CollectionUtils.isEmpty(mesContainerSnParts)) {
            MesPcnException.throwBusiException("扫描的容器条码:%s,对应容器零件关系不存在", containerSn.getContainerSn());
        }
        return mesContainerSnParts;
    }

    private List<MesContainerPartsModel> getContainerParts(String organizeCode, MesContainerSn containerSn) {
        List<MesContainerPartsModel> result = new ArrayList<>();
        Set<String> partNoSet = new HashSet<>();
        List<MesContainerSnPart> snPartList = containerSnPartRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, "containerTypeCode", "containerSn"},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), containerSn.getContainerTypeCode(), containerSn.getContainerSn()});
        if (!CollectionUtils.isEmpty(snPartList)) {
            for (MesContainerSnPart snPart : snPartList) {
                if (StringUtils.isEmpty(snPart.getPartNo())) {
                    continue;
                }

                partNoSet.add(snPart.getPartNo());
                MesContainerPartsModel model = MesContainerPartsModel.builder()
                        .partNo(snPart.getPartNo())
                        .partName(snPart.getPartName())
                        .matchType(snPart.getMatchType())
                        .matchRule(snPart.getMatchRule())
                        .qty(snPart.getQty())
                        .build();
                result.add(model);
            }
        }

        List<MesContainerTypePart> partList = containerTypePartRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, "containerTypeCode"},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), containerSn.getContainerTypeCode()});
        if (!CollectionUtils.isEmpty(partList)) {
            for (MesContainerTypePart partPart : partList) {
                if (StringUtils.isEmpty(partPart.getPartNo())) {
                    continue;
                }

                if (partNoSet.contains(partPart.getPartNo())) {
                    continue;
                }
                MesContainerPartsModel model = MesContainerPartsModel.builder()
                        .partNo(partPart.getPartNo())
                        .partName(partPart.getPartName())
                        .matchType(partPart.getMatchType())
                        .matchRule(partPart.getMatchRule())
                        .qty(partPart.getQty())
                        .build();
                result.add(model);
            }
        }
        return result;
    }

    public MesContainerSnBindModel containerToContainer(String organizeCode, String userName, MesContainerSn masterContainerSn, MesContainerSn subContainerSn) {
        MesContainerSnBindModel model = MesContainerSnBindModel.builder().build();

        // 获取容器类型
        MesContainerType mesContainerType = getMesContainerType(organizeCode, masterContainerSn.getContainerSn(),  masterContainerSn.getContainerTypeCode());
        if (!Objects.equals(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), mesContainerType.getIsAllowRecursion())) {
            MesPcnException.throwBusiException("扫描的容器条码:%s,不允许绑定容器", masterContainerSn.getContainerSn());
        }
        // 判断子容器是否是已装箱状态
        MesContainerPackage masterContainerPackage = getMesContainerPackage(organizeCode, masterContainerSn.getContainerSn());
        if (masterContainerPackage == null) {
            masterContainerPackage = createMesContainerPackage(userName, masterContainerSn);
        }
        if (Objects.equals(masterContainerPackage.getPackageStatus(), MesExtEnumUtil.CONTAINER_PACKAGE_STATUS.STATUS_20.getValue())) {
            MesPcnException.throwMesBusiException("容器条码【%s】已关箱，不能再进行上料", masterContainerPackage.getContainerSn());
        }

        MesContainerPackage subContainerPackage = getMesContainerPackage(organizeCode, subContainerSn.getContainerSn());
        if (subContainerPackage == null || !Objects.equals(subContainerPackage.getPackageStatus(), MesExtEnumUtil.CONTAINER_PACKAGE_STATUS.STATUS_20.getValue())) {
            MesPcnException.throwBusiException("扫描的子容器条码:%s,不是已关箱状态", subContainerSn.getContainerSn());
        }
        //  获取 容器类型与零件关系
        List<MesContainerPartsModel> masterContainerParts = getContainerParts(organizeCode, masterContainerSn);
        List<MesContainerPartsModel> subContainerSnParts = getContainerParts(organizeCode, subContainerSn);
        List<String> subParts = subContainerSnParts.stream().map(MesContainerPartsModel::getPartNo).collect(Collectors.toList());
        List<String> masterParts = masterContainerParts.stream().map(MesContainerPartsModel::getPartNo).collect(Collectors.toList());
        for (String subPart : subParts) {
            if (!masterParts.contains(subPart)) {
                MesPcnException.throwBusiException("扫描的主容器条码:%s,与子容器条码不匹配，无法包装", subContainerSn.getContainerSn(),subContainerSn.getContainerSn());
            }
        }
        /**
         * 验证标包
         * 1 查询子包装的上料明细
         * 2 查询总包装下面的最终条码上料明细
         * 3 校验标包是否满足
         */
        List<MesContainerPackageDetail> masterPackageDetails = getMesContainerPackageDetail(organizeCode, masterContainerSn.getContainerSn(), false);
        for (MesContainerPackageDetail masterPackageDetail : masterPackageDetails) {
            if (Objects.equals(masterPackageDetail.getBarCode(), model.getBarCode())) {
                MesPcnException.throwMesBusiException("容器条码【%s】与条码【%s】已绑定，请检查数据", masterContainerSn.getContainerSn(), model.getBarCode());
            }
        }

        List<MesContainerPackageDetail> subPackageDetails = getMesContainerPackageDetail(organizeCode, subContainerSn.getContainerSn(), true);
        // 调用涛哥的根据条码对应标包验证。todo
        MesAbstractContainerBindCheckQtyService checkQtyService = ContainerBindManager.INSTANCE.getCheckQtyService(MesExtEnumUtil.CONTAINER_TYPE_MIX_TYPE.getByValue(mesContainerType.getMixType()));

        for (MesContainerPackageDetail subPackageDetail : subPackageDetails) {
            MesContainerPartsModel containerPart = MesContainerPartsModel.builder()
                    .partNo(subPackageDetail.getPartNo())
                    .build();

            Map<String, Object> checkQtyResult = checkQtyService.doCheck(organizeCode, masterContainerPackage, subPackageDetails, masterContainerParts);
            if (checkQtyResult != null && Objects.equals(checkQtyResult.get(MesPcnExtConstWords.RESULT), false)) {
                MesPcnException.throwMesBusiException(checkQtyResult.get(MesPcnExtConstWords.MESSAGE).toString());
            }
        }
        MesContainerPackageDetail mesContainerPackageDetailBean = crreateMesContainerPackageDetail(userName, masterContainerSn, subContainerSn, masterContainerPackage);
        masterPackageDetails.add(mesContainerPackageDetailBean);

        MesContainerPackageDetailBinding containerPackageDetailBinding = createContainerPackageDetailBinding(masterContainerPackage, mesContainerPackageDetailBean, MesExtEnumUtil.CONTAINER_RAW_SN_BINDING_STATUS.BINDING, userName);

        model.setContainerPackage(masterContainerPackage);
        model.setPackageDetails(masterPackageDetails);
        model.addPackageDetailBinding(containerPackageDetailBinding);

        containerPackageRepository.save(masterContainerPackage);
        containerPackageDetailRepository.save(mesContainerPackageDetailBean);
        packageDetailBindingRepository.save(containerPackageDetailBinding);
        return model;
    }

    private MesContainerPackage createMesContainerPackage(String userName, MesContainerSn masterContainerSn) {
        MesContainerPackage masterContainerPackage;
        // 新增上料表，和上料明细
        masterContainerPackage = new MesContainerPackage();
        masterContainerPackage.setId(snowflakeIdMaker.nextId());
        masterContainerPackage.setOrganizeCode(masterContainerSn.getOrganizeCode());
        masterContainerPackage.setContainerSn(masterContainerSn.getContainerSn());
        masterContainerPackage.setPackageStatus(10);
        ConvertBean.serviceModelInitialize(masterContainerPackage, userName);
        containerPackageRepository.save(masterContainerPackage);
        return masterContainerPackage;
    }

    private MesContainerPackageDetail crreateMesContainerPackageDetail(String userName, MesContainerSn masterContainerSn, MesContainerSn subContainerSn, MesContainerPackage masterContainerPackage) {
        MesContainerPackageDetail detail = new MesContainerPackageDetail();
        detail.setContainerSn(masterContainerSn.getContainerSn());
        detail.setPid(masterContainerPackage.getId());
        detail.setBarCode(subContainerSn.getContainerSn());
        detail.setLoadPartTime(TimeTool.getNowTime(true));
        ConvertBean.serviceModelInitialize(detail, userName);
        return detail;
    }


    private MesContainerPackageDetailBinding createContainerPackageDetailBinding(MesContainerPackage containerPackage, MesContainerPackageDetail packageDetail, MesExtEnumUtil.CONTAINER_RAW_SN_BINDING_STATUS snBindingStatus, String userName) {
        MesContainerPackageDetailBinding binding = new MesContainerPackageDetailBinding();
        binding.setOrganizeCode(containerPackage.getOrganizeCode());
        binding.setPid(containerPackage.getId());
        binding.setSourceId(packageDetail.getId());
        binding.setContainerSn(containerPackage.getContainerSn());
        binding.setBarCode(packageDetail.getBarCode());
        binding.setQty(packageDetail.getQty());
        binding.setSnStatus(snBindingStatus.getValue());
        binding.setMatchType(packageDetail.getMatchType());
        ConvertBean.serviceModelInitialize(binding, userName);
        return binding;
    }

    private MesContainerSn getMesContainerSnAndValidate(String organizeCode, String sn) {
        // 判断条码是否存在
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(sn, "containerSn", ddlPackBean);
        List<MesContainerSn> mesContainerSns = mesContainerSnRepository.findByHqlWhere(ddlPackBean);
        if (CollectionUtils.isEmpty(mesContainerSns)) {
            MesPcnException.throwBusiException("扫描的容器条码:%s,不存在", sn);
        }
        if (mesContainerSns.size() > 1) {
            MesPcnException.throwBusiException("条码:%s, 不唯一", sn);
        }
        return mesContainerSns.get(0);
    }

    private MesContainerSn getMesContainerSn(String organizeCode, String sn) {
        // 判断条码是否存在
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);

        DdlPreparedPack.getStringEqualPack(sn, "containerSn", ddlPackBean);

        MesContainerSn mesContainerSn = mesContainerSnRepository.getByProperty(ddlPackBean);

        return mesContainerSn;
    }


    private MesContainerType getMesContainerType(String organizeCode,String sn, String containerTypeCode) {
        // 判断条码是否存在
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);

        DdlPreparedPack.getStringEqualPack(containerTypeCode, "containerTypeCode", ddlPackBean);

        List<MesContainerType> mesContainerTypes = mesContainerTypeRepository.findByHqlWhere(ddlPackBean);
        if (CollectionUtils.isEmpty(mesContainerTypes)) {
            MesPcnException.throwBusiException("扫描的容器条码:%s,对应容器类型不存在", sn, containerTypeCode);
        }
        if (mesContainerTypes.size() > 1) {
            MesPcnException.throwBusiException("扫描的容器条码:%s,对应容器类型:%s,不唯一", sn, containerTypeCode);
        }

        return mesContainerTypes.get(0);
    }

    private List<MesContainerSnPart> getMesContainerSnPart(String organizeCode, String sn) {
        // 判断条码是否存在
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);

        DdlPreparedPack.getStringEqualPack(sn, "containerSn", ddlPackBean);

        List<MesContainerSnPart> mesContainerTypes = containerSnPartRepository.findByHqlWhere(ddlPackBean);

        return mesContainerTypes;
    }

    private List<MesContainerTypePart> getMesContainerTypePart(String organizeCode, String containerTypeCode) {
        // 判断条码是否存在
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);

        DdlPreparedPack.getStringEqualPack(containerTypeCode, "containerTypeCode", ddlPackBean);

        List<MesContainerTypePart> mesContainerTypeParts = containerTypePartRepository.findByHqlWhere(ddlPackBean);

        return mesContainerTypeParts;
    }

    private MesContainerPackage getMesContainerPackage(String organizeCode, String sn) {
        // 判断条码是否存在
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);

        DdlPreparedPack.getStringEqualPack(sn, "containerSn", ddlPackBean);

        MesContainerPackage mesContainerPackage = containerPackageRepository.getByProperty(ddlPackBean);

        return mesContainerPackage;
    }

    /**
     * flag true 代表是主包装找子零件，false 子包装找子零件
     * @param organizeCode
     * @param sn
     * @param flag
     * @return
     */
    private List<MesContainerPackageDetail> getMesContainerPackageDetail(String organizeCode, String sn, boolean flag) {
        List<MesContainerPackageDetail> resultDetail = new ArrayList<>();

        // 判断条码是否存在
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);

        DdlPreparedPack.getStringEqualPack(sn, "containerSn", ddlPackBean);

        List<MesContainerPackageDetail> mesContainerPackageDetails = containerPackageDetailRepository.findByHqlWhere(ddlPackBean);
        if (flag) {
            for (MesContainerPackageDetail mesContainerPackageDetail : mesContainerPackageDetails) {
                if (!StringUtils.isEmpty(mesContainerPackageDetail.getPartNo())) {
                    resultDetail.add(mesContainerPackageDetail);
                } else {
                    resultDetail.addAll(getMesContainerPackageDetail(organizeCode,mesContainerPackageDetail.getBarCode(), false));
                }
            }
        } else {
            resultDetail.addAll(mesContainerPackageDetails);
        }
        return resultDetail;
    }
}
