package com.sw.mes.itemclean.clean.service.impl;

import com.sw.mes.core.api.system.YbFeignClients;
import com.sw.mes.core.context.BaseContextHandler;
import com.sw.mes.core.dto.MaterialModelDto;
import com.sw.mes.core.dto.ProductionOrderDto;
import com.sw.mes.core.dto.materialCleanDto.MaterialCleanModelDto;
import com.sw.mes.core.enums.FactoryModelWorkTypeEnum;
import com.sw.mes.core.enums.ItemCleanEnums;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultCode;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.utils.StringUtils;
import com.sw.mes.itemclean.clean.domain.*;
import com.sw.mes.itemclean.clean.dto.*;
import com.sw.mes.itemclean.clean.dto.auto.*;
import com.sw.mes.itemclean.clean.service.*;
import com.sw.mes.itemclean.clean.vo.MaterialUnpackingVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.bouncycastle.jcajce.provider.symmetric.SEED;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Slf4j
public class MaterialCleanToAutoServiceImpl implements MaterialCleanToAutoService {

    @Autowired
    ModelMapper modelMapper;

    @Autowired
    MaterialStoreSignBoxService materialStoreSignBoxService;

    @Autowired
    MaterialUnpackingService materialUnpackingService;

    @Autowired
    MaterialCleaningService materialCleaningService;

    @Autowired
    MaterialBrokenService materialBrokenService;

    @Autowired
    MaterialGroupService materialGroupService;

    @Autowired
    MaterialGroupDetailService materialGroupDetailService;

    @Autowired
    GenerateBusinessNoService generateBusinessNoService;

    @Autowired
    YbFeignClients ybFeignClients;

    @Override
    public IOTResponseUnpackingDto getUnpackingInfoByProductBatchNo(IOTRequestUnpackingDto iotRequestUnpackingDto) {

        String currentProductBatchNo = iotRequestUnpackingDto.getCurrentProductBatchNo();
        IOTResponseUnpackingDto iotResponseUnpackingDto = new IOTResponseUnpackingDto();
        if (ItemCleanEnums.AutoModel.自动.getKey() == iotRequestUnpackingDto.getAutoModel()) {
            //自动模式下:
            //1 校验领料表中是否存在
            MaterialStoreSignBox materialStoreSignBox = materialStoreSignBoxService.getByProductBatchNo(currentProductBatchNo);
            if (null == materialStoreSignBox) {
                throw new BusinessException("该批次: " + currentProductBatchNo + " 领料信息不存在!");
            }
            //todo:等待清洗模型关系,再开发
            //2.1 找到对应的清洗物料模型对应关系
            String materialCode = materialStoreSignBox.getMaterialCode();
            Result<MaterialCleanModelDto> cleanModelDtoResult = ybFeignClients.findMaterialCleanByCode(materialCode);

            if (!cleanModelDtoResult.getCode().equals(ResultCode.SUCCESS.code)) {
                throw new RuntimeException("查询原料清洗产品模型发生错误");
            }
            MaterialCleanModelDto materialCleanModelDto = cleanModelDtoResult.getData();
            if (materialCleanModelDto == null) {
                throw new RuntimeException("原料清洗产品模型不存在物料编码:" + materialCode);
            }
            // 2.2 以及匹配时间范围内的硅料工单
            String finishedCode = materialCleanModelDto.getFinishedCode();
            Result<MaterialModelDto> result = ybFeignClients.getMaterialByCode(finishedCode);
            MaterialModelDto model = result.getData();
            if (model == null) {
                throw new BusinessException("物料主数据不存在成品编码:【" + finishedCode + "】！");
            }
            String finishedCodeName = model.getName();
            String hasGone = materialCleanModelDto.getHasGone();
            String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            Result<List<ProductionOrderDto>> orderListResult = ybFeignClients.listBySearchConditions(String.valueOf(FactoryModelWorkTypeEnum.CLEAN.getKey()), finishedCode, dateStr, dateStr);
            if (!orderListResult.getCode().equals(ResultCode.SUCCESS.code)) {
                throw new RuntimeException("查询计划工单发生错误:" + orderListResult.getMessage());
            }
            List<ProductionOrderDto> productionOrderDtos = orderListResult.getData();
            if (CollectionUtils.isEmpty(productionOrderDtos)) {
                throw new RuntimeException("不存在物料编码: " + finishedCode + "的计划工单！");
            }
            ProductionOrderDto productionOrderDto = productionOrderDtos.get(0);
            String aufnr = productionOrderDto.getAufnr();

            //2.2 将余料进行整箱分选
            MaterialUnpackingVo materialUnpackingVo = fromMaterialStoreSignBox(materialStoreSignBox);
            materialUnpackingVo.setMaterialCode(finishedCode);
            materialUnpackingVo.setMaterialName(finishedCodeName);
            materialUnpackingVo.setMaterialLevel(materialCleanModelDto.getLevel());
            materialUnpackingVo.setMaterialGear(materialCleanModelDto.getResistanceRange());
            materialUnpackingVo.setOtherWeight(BigDecimal.ZERO);
            materialUnpackingVo.setAufnr(aufnr);
            if(StringUtils.isBlank(hasGone)){
                materialUnpackingVo.setHasGone(ItemCleanEnums.MaterialHasGone.清洗.getValue());
            }else {
                materialUnpackingVo.setHasGone(hasGone);
            }
            FxToBoxInfoPrintDto finishStorageSign = null;
            try {
                finishStorageSign = materialUnpackingService.createFinishStorageSign(materialUnpackingVo);
            } catch (Exception e) {
                log.error("auto_createFinishStorageSign", e);
                throw new RuntimeException("分选异常:" + e.getMessage());
            }
            iotResponseUnpackingDto = fromFxToBoxInfoPrintDto(finishStorageSign);
        } else {
            //手动模式: 直接通过分选pp号获取分选信息
            MaterialUnpacking materialUnpacking = materialUnpackingService.getFxProductBatchNo(currentProductBatchNo);
            if (null == materialUnpacking) {
                throw new RuntimeException("pp批次号" + currentProductBatchNo + "分选记录不存在!");
            }
            iotResponseUnpackingDto = fromMaterialUnpacking(materialUnpacking);
        }
        return iotResponseUnpackingDto;
    }

    @Override
    public void materialCleaningUp(IOTRequestMaterialCleaningUpDto dto) {
        String fxProductBatchNo = dto.getFxProductBatchNo();
        String basketNo = dto.getBasketNo();
        MaterialUnpacking materialUnpacking = materialUnpackingService.getUseInfoByPpProductBatchNo(fxProductBatchNo);
        if (null == materialUnpacking) {
            throw new BusinessException("批次" + fxProductBatchNo + "物料已经被清空");
        }
        MaterialCleaning cleaning = materialCleaningService.getNotCleanByBoxNo(basketNo);
        if (cleaning != null) {
            throw new BusinessException("该花篮" + basketNo + "被清洗上下料工序占用");
        }
        //调用创建清洗上料信息接口
        materialCleaningService.materialDetailCleaningUp(dto.getDeviceNo(), materialUnpacking.getBoxNo(), materialUnpacking.getMaterialCode(), materialUnpacking.getMaterialName(), materialUnpacking.getMaterialLevel(), materialUnpacking.getMaterialModel(), materialUnpacking.getMaterialGear(), fxProductBatchNo, dto.getBasketNo(), dto.getWeight(), "0", "","");
    }

    @Override
    public void materialCleaningErrorDown(IOTRequestMaterialCleaningErrorDownDto iotRequestMaterialCleaningErrorDownDto) {
        //不做任何操作
    }

    @Override
    public IOTResponseBrokenUpDto materialCleaningDownAndBrokenUp(IOTRequestMaterialBrokenUpDto iotRequestMaterialBrokenUpDto) {
        BoxInfoDto boxInfoDto = materialBrokenService.getInfoByBoxNo(iotRequestMaterialBrokenUpDto.getBoxNo());
        if (null == boxInfoDto) {
            throw new BusinessException("该载具号" + iotRequestMaterialBrokenUpDto.getBoxNo() + "未追溯到数据!");
        }
        MaterialBrokenUpDto materialBrokenUpDto = new MaterialBrokenUpDto();
        materialBrokenUpDto.setBoxInfo(boxInfoDto);
        materialBrokenUpDto.setDeviceNo(iotRequestMaterialBrokenUpDto.getDeviceNo());
        materialBrokenUpDto.setStation("0");
        MaterialBroken materialBroken = materialBrokenService.materialBrokenUp(materialBrokenUpDto);
        IOTResponseBrokenUpDto iotResponseBrokenUpDto = new IOTResponseBrokenUpDto();
        iotResponseBrokenUpDto.setMaterialCode(materialBroken.getMaterialCode());
        iotResponseBrokenUpDto.setMaterialName(materialBroken.getMaterialName());
        iotResponseBrokenUpDto.setMaterialGear(materialBroken.getMaterialGear());
        iotResponseBrokenUpDto.setMaterialLevel(materialBroken.getMaterialLevel());
        iotResponseBrokenUpDto.setMaterialModel(materialBroken.getMaterialModel());
        iotResponseBrokenUpDto.setWeight(materialBroken.getWeight());
        iotResponseBrokenUpDto.setFxProductBatchNo(materialBroken.getProductBatchNo());
        iotResponseBrokenUpDto.setBoxNo(materialBroken.getBoxNo());
        return iotResponseBrokenUpDto;
    }

    @Override
    public void materialBrokenDownToPackaging(IOTRequestMaterialBrokenDownDto iotRequestMaterialBrokenDownDto) {
        //查询破碎记录
        MaterialBroken materialBroken = materialBrokenService.getBrokenInfoByBoxNo(iotRequestMaterialBrokenDownDto.getBoxNo());
        if (null == materialBroken) {
            throw new BusinessException("该箱号" + iotRequestMaterialBrokenDownDto.getBoxNo() + "不存在可使用破碎物料");
        }
        BrokenToPackDto dto = new BrokenToPackDto();
        dto.setMaterialBoxNo(iotRequestMaterialBrokenDownDto.getMaterialBoxNo());
        dto.setDeviceNo(iotRequestMaterialBrokenDownDto.getDeviceNo());
        dto.setBoxNo(iotRequestMaterialBrokenDownDto.getBoxNo());
        dto.setWeight(iotRequestMaterialBrokenDownDto.getWeight());
        dto.setSuppliesGrain(iotRequestMaterialBrokenDownDto.getSuppliesGrain());
        dto.setBoxNum(1);
        dto.setBrokenId(materialBroken.getId());
        dto.setProductBatchNo(materialBroken.getProductBatchNo());
        dto.setMaterialGear(materialBroken.getMaterialGear());
        dto.setMaterialCode(materialBroken.getMaterialCode());
        dto.setMaterialName(materialBroken.getMaterialName());
        dto.setMaterialLevel(materialBroken.getMaterialLevel());
        dto.setMaterialModel(materialBroken.getMaterialModel());
        dto.setDownUser(BaseContextHandler.getUsername());
        dto.setDownTime(LocalDateTime.now());
        dto.setCreateUser(BaseContextHandler.getUsername());
        dto.setCreateTime(LocalDateTime.now());
        dto.setDelFlag(ItemCleanEnums.MaterialDelFlag.未删除.getKey());
        MaterialGroupDetail materialGroupDetail = materialBrokenService.materialBrokenToPackaging(dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void autoGroupStore(IOTRequestMaterialGroupStoreDto iotRequestMaterialGroupStoreDto) {
        //1 校验箱盒信息
        List<MaterialGroupDetail> materialGroupDetails = checkGroupStore(iotRequestMaterialGroupStoreDto.getDetailBoxs());
        //2 构建组托、合计重量
        MaterialGroup materialGroup = buildMaterialGroup(materialGroupDetails);
        materialGroup.setTrayCode(iotRequestMaterialGroupStoreDto.getTrayCode());
        materialGroup.setTrayNumber(iotRequestMaterialGroupStoreDto.getTrayNumber());
        materialGroupService.saveOrUpdate(materialGroup);
        //3 更新组托明细状态
        List<Integer> idList = materialGroupDetails.stream().map(MaterialGroupDetail::getId).collect(Collectors.toList());
        materialGroupDetailService.updateStatusByIds(idList, materialGroup);
        //发起入库
        materialGroupService.groupStoreById(materialGroup.getId());
    }

    @Override
    public void groupCallAgvById(Integer id) {
        //1查询组托详情
        MaterialGroup materialGroup = materialGroupService.getById(id);
        List<MaterialGroupDetail> details = materialGroupDetailService.getGroupDetailsByGroupId(id);
        if (null == materialGroup || CollectionUtils.isEmpty(details)) {
            throw new BusinessException("组托物料为空!");
        }
        //todo:待调用mcs满托呼叫agv接口
        MesRequestMcsAgvDto mesRequestMcsAgvDto = new MesRequestMcsAgvDto();
        mesRequestMcsAgvDto.setGroupNo(materialGroup.getGroupNo());
        mesRequestMcsAgvDto.setDetails(details);
        mesRequestMcsAgvDto.setTrayCode(materialGroup.getTrayCode());
        mesRequestMcsAgvDto.setTrayNumber(materialGroup.getTrayNumber());
        mesRequestMcsAgvDto.setWeight(materialGroup.getWeight());
    }

    @Override
    public IOTResponseBrokenUpDto getBrokenUpByProductBatchNo(IOTRequestUnpackingToBreakDto iotRequestUnpackingToBreakDto) {

        if (ItemCleanEnums.AutoModel.自动.getKey() != iotRequestUnpackingToBreakDto.getAutoModel()) {
            throw new BusinessException("调用模式错误,入参标识必须是自动模式!");
        }
        //1 自动分选
        IOTRequestUnpackingDto iotRequestUnpackingDto = new IOTRequestUnpackingDto();
        iotRequestUnpackingDto.setAutoModel(iotRequestUnpackingToBreakDto.getAutoModel());
        iotRequestUnpackingDto.setCurrentProductBatchNo(iotRequestUnpackingToBreakDto.getCurrentProductBatchNo());
        IOTResponseUnpackingDto iotResponseUnpackingDto = this.getUnpackingInfoByProductBatchNo(iotRequestUnpackingDto);
        if (!ItemCleanEnums.MaterialHasGone.破碎.getValue().equals(iotResponseUnpackingDto.getHasGone())) {
            throw new BusinessException("该批次号:" + iotRequestUnpackingToBreakDto.getCurrentProductBatchNo() + "对应物料编码的清洗模型分选方向不是" + ItemCleanEnums.MaterialHasGone.破碎.getValue());
        }

        //2 自动破碎上料
        IOTRequestMaterialBrokenUpDto iotRequestMaterialBrokenUpDto = new IOTRequestMaterialBrokenUpDto();
        iotRequestMaterialBrokenUpDto.setDeviceNo(iotRequestUnpackingToBreakDto.getDeviceNo());
        iotRequestMaterialBrokenUpDto.setBrokenUpCode(iotRequestMaterialBrokenUpDto.getBrokenUpCode());
        iotRequestMaterialBrokenUpDto.setUniqueCode(iotRequestMaterialBrokenUpDto.getUniqueCode());
        iotRequestMaterialBrokenUpDto.setBoxNo(iotResponseUnpackingDto.getBoxNo());
        IOTResponseBrokenUpDto iotResponseBrokenUpDto = this.materialCleaningDownAndBrokenUp(iotRequestMaterialBrokenUpDto);
        return iotResponseBrokenUpDto;
    }


    /**
     * 校验箱盒信息
     *
     * @param boxNos
     */
    private List<MaterialGroupDetail> checkGroupStore(List<String> boxNos) {
        if (boxNos == null || boxNos.size() <= 0) {
            throw new RuntimeException("组托内容为空");
        }
        List<MaterialGroupDetail> details = materialGroupDetailService.getGroupDetailInfosByMaterialBoxNo(boxNos);
        if (null == details || details.size() != boxNos.size()) {
            throw new RuntimeException("未查询到相同数量的待组托箱盒信息");
        }
        Set<String> set = details.stream().map(MaterialGroupDetail::getProductBatchNo).collect(Collectors.toSet());
        if (set.size() != 1) {
            throw new RuntimeException("不是相同批次号不能组托");
        }
        return details;
    }

    /**
     * 自动封装打托信息
     *
     * @param dtos
     * @return
     */
    private MaterialGroup buildMaterialGroup(List<MaterialGroupDetail> dtos) {
        MaterialGroupDetail detailDto = dtos.get(0);
        MaterialGroup materialGroup = new MaterialGroup();
        BigDecimal totalWeight = dtos.stream().map(MaterialGroupDetail::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
        materialGroup.setId(detailDto.getId());
        materialGroup.setWeight(totalWeight);
        materialGroup.setMaterialCode(detailDto.getMaterialCode());
        materialGroup.setMaterialName(detailDto.getMaterialName());
        materialGroup.setMaterialLevel(detailDto.getMaterialLevel());
        materialGroup.setMaterialModel(detailDto.getMaterialModel());
        materialGroup.setMaterialGear(detailDto.getMaterialGear());
        materialGroup.setDeviceNo("");
        materialGroup.setProductBatchNo(detailDto.getProductBatchNo());
        materialGroup.setGroupNo(generateBusinessNoService.generateForGroupNo());
        materialGroup.setCreateUser(BaseContextHandler.getUsername());
        materialGroup.setCreateTime(LocalDateTime.now());
        materialGroup.setUpdateUser(BaseContextHandler.getUsername());
        materialGroup.setUpdateTime(LocalDateTime.now());
        materialGroup.setRemark("");
        materialGroup.setSuppliesGrain(detailDto.getSuppliesGrain());
        materialGroup.setStatus(ItemCleanEnums.MaterialGroupStatus.未入库.getKey());
        materialGroup.setWarehousingUser(BaseContextHandler.getUsername());
        materialGroup.setWarehousingTime(LocalDateTime.now());
        MaterialUnpacking fxProductBatchNo = materialUnpackingService.getFxProductBatchNo(detailDto.getProductBatchNo());
        if (null != fxProductBatchNo) {
            materialGroup.setAufnr(fxProductBatchNo.getAufnr());
        }
        return materialGroup;
    }

    public MaterialUnpackingVo fromMaterialStoreSignBox(MaterialStoreSignBox storeSignBox) {
        return modelMapper.map(storeSignBox, MaterialUnpackingVo.class);
    }

    public IOTResponseUnpackingDto fromMaterialUnpacking(MaterialUnpacking unpacking) {
        return modelMapper.map(unpacking, IOTResponseUnpackingDto.class);
    }

    public IOTResponseUnpackingDto fromFxToBoxInfoPrintDto(FxToBoxInfoPrintDto unpacking) {
        return modelMapper.map(unpacking, IOTResponseUnpackingDto.class);
    }

}
