package com.sw.mes.itemclean.clean.controller;


import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.ExceptionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sw.mes.core.api.system.YbFeignClients;
import com.sw.mes.core.context.BaseContextHandler;
import com.sw.mes.core.dto.CarrierConfigDto;
import com.sw.mes.core.dto.DictionaryItemDto;
import com.sw.mes.core.dto.materialCleanDto.MaterialCleanModelDto;
import com.sw.mes.core.enums.CleanFactoryCodeEnum;
import com.sw.mes.core.enums.EnumValuesFactory;
import com.sw.mes.core.enums.ErpEnum;
import com.sw.mes.core.enums.ItemCleanEnums;
import com.sw.mes.core.response.*;
import com.sw.mes.core.utils.*;
import com.sw.mes.itemclean.clean.domain.*;
import com.sw.mes.itemclean.clean.dto.*;
import com.sw.mes.itemclean.clean.dto.batchNoOperate.BatchNoOperate;
import com.sw.mes.itemclean.clean.dto.boxNoOperate.BatchNo;
import com.sw.mes.itemclean.clean.dto.boxNoOperate.BoxNoOperate;
import com.sw.mes.itemclean.clean.mapper.MaterialApplyOrderMapper;
import com.sw.mes.itemclean.clean.service.*;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.modelmapper.ModelMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;


@RestController
@RequestMapping("/clean/materialApplyOrder")
@Slf4j
@Api(tags = "领料单")
public class MaterialApplyOrderController {

    @Autowired
    ModelMapper modelMapper;

    @Autowired
    private MaterialApplyOrderRelationService materialApplyOrderRelationService;

    @Autowired
    private MaterialApplyOrderService materialApplyOrderService;

    @Autowired
    private MaterialApplyOrderMapper materialApplyOrderMapper;

    @Autowired
    private YbFeignClients ybFeignClients;

    @Autowired
    private GenerateBusinessNoService generateBusinessNoService;

    @Autowired
    private MaterialStoreSignBoxService materialStoreSignBoxService;

    @Autowired
    private MaterialPlanOrderService materialPlanOrderService;

    @Autowired
    private WashingPlanService washingPlanService;

    @Autowired
    private CleaningProcessFlowService cleaningProcessFlowService;

    @Autowired
    private CleanReworkingService cleanReworkingService;

    @Autowired
    private MaterialUnpackingService materialUnpackingService;

    @Value("${spring.wmsServiceUrl}")
    private String wmsServiceUrl;

    private final String recycleToWms = "/api/InboundRecycledMaterial";

    @Autowired
    @Qualifier(value = "cleanMesThreadPoolTaskExecutor")
    private ThreadPoolTaskExecutor cleanMesThreadPoolExecutor;

    @Value("${spring.profiles.active}")
    private String active;

    @Autowired
    private RestTemplate restTemplate;


    @ApiOperation(value = "分页查询列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "rows", value = "行数", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "page", value = "页码", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_materialName", value = "物料名称", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialLevel", value = "物料等级", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialBoxNo", value = "领料单箱号", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialModel", value = "物料型号", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialProp", value = "物料属性", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialComp", value = "厂家/来源", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_productBatchNo", value = "物料批次", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_orderType", value = "领料单类型", dataType = "integer", paramType = "query"),
            //@ApiImplicitParam(name = "search_EQ_sonId", value = "儿子箱子id", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "search_GTE_applyTime", value = "领料开始时间", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_LTE_applyTime", value = "领料结束时间", dataType = "string", paramType = "query"),
    })
    @GetMapping("/listByPage")
    public Result<ResponsePage<MaterialApplyOrderDto>> listByPage(ServletRequest request, @ApiIgnore RequestPage requestPage) {
        //分页查询
        //MaterialApplyOrder中的sonId字段暂时弃用，子箱相关信息到 material_apply_order_relation表中查询
        QueryWrapper<MaterialApplyOrder> queryWrapper =  DynmaicQueryWrapper.searchFilter(request, MaterialApplyOrder.class);
        queryWrapper.ne("material_prop",5);
        queryWrapper.orderByDesc("create_time");
        Page<MaterialApplyOrder> listPage = materialApplyOrderService.page(new Page<>(requestPage.getPage(), requestPage.getRows()), queryWrapper);
        List<MaterialApplyOrder> orders = listPage.getRecords();
        List<MaterialApplyOrderDto> materialApplyOrderDtos=new ArrayList<>();
        for (MaterialApplyOrder order : orders) {
            String s = "";
            List<MaterialApplyOrderRelation> materialApplyOrderRelations = materialApplyOrderRelationService.findByMaterialBoxNoParent(order.getMaterialBoxNo());
            if (materialApplyOrderRelations.size()>0){
                for (MaterialApplyOrderRelation materialApplyOrderRelation : materialApplyOrderRelations) {
                    if (StringUtils.isNotEmpty(materialApplyOrderRelation.getMaterialBoxNoSon())) {
                        s += materialApplyOrderRelation.getMaterialBoxNoSon() + ",";
                    }
                }
            }
            MaterialApplyOrderDto materialApplyOrderDto = toLazyDto(order);
            materialApplyOrderDto.setMaterialBoxNoSons(s);
            materialApplyOrderDtos.add(materialApplyOrderDto);
        }
        ResponsePage responsePage = new ResponsePage(materialApplyOrderDtos, listPage.getTotal());
        return ResultGenerator.success(responsePage);
    }

    @ApiOperation(value = "获取所有列表")
    @GetMapping("/listAll")
    public Result<List<MaterialApplyOrderDto>> listAll(ServletRequest request) {
        QueryWrapper<MaterialApplyOrder> queryWrapper =  DynmaicQueryWrapper.searchFilter(request, MaterialApplyOrder.class);
        List<MaterialApplyOrder> materialApplyOrders = materialApplyOrderService.list(queryWrapper);
        List<MaterialApplyOrderDto> materialApplyOrderDtos = materialApplyOrders.stream()
                .map(materialApplyOrder -> toLazyDto(materialApplyOrder))
                .collect(Collectors.toList());
        return ResultGenerator.success(materialApplyOrderDtos);
    }

    @ApiOperation(value = "详细信息")
    @GetMapping("/{id}")
    public Result<MaterialApplyOrderDto> get(@PathVariable @ApiParam(value="设备类型id") Integer id) {
        MaterialApplyOrder materialApplyOrder = materialApplyOrderService.getById(id);
        if (null == materialApplyOrder)
            return ResultGenerator.fail("该对象不存在");
        return ResultGenerator.success(toEagerDto(materialApplyOrder));
    }

    /**
     * 测试用
     * @param applyTime
     * @return
     */
    @ApiOperation(value = "测试获取时间")
    @GetMapping("/getFinishedTime")
    @Deprecated
    public Date getFinishedTime(@RequestParam @ApiParam(value="当前时间") String applyTime) {
        Date parse = null;
        try {
            parse = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(applyTime);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println(LocalDateTime.now());
        return formatApplyTime(parse);
    }



    @ApiOperation(value = "根据生产批次查询产品模型")
    @GetMapping("/findByCleanProductBatchNo")
    public Result<MaterialCleanModelDto> findByClanProductBatchNo(@RequestParam @ApiParam(value = "清洗批次号")String cleanProductBatchNo){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("clan_product_batch_no", cleanProductBatchNo);
        List<MaterialApplyOrder> list = materialApplyOrderService.list(queryWrapper);
        MaterialCleanModelDto materialCleanModelDto = new MaterialCleanModelDto();

        //有领料申请单的情况
        if (!CollectionUtils.isEmpty(list)) {
            MaterialApplyOrder materialApplyOrder = list.get(0);
            //物料名称
            materialCleanModelDto.setName(materialApplyOrder.getMaterialName());
            //物料编码
            materialCleanModelDto.setCode(materialApplyOrder.getMaterialCode());
            //电阻档位
            materialCleanModelDto.setResistanceRangeCode(materialApplyOrder.getMaterialGear());
            //等级
            materialCleanModelDto.setLevel(materialApplyOrder.getMaterialLevel());
            //根据物料编码查清洗模型
            Result<MaterialCleanModelDto> result = ybFeignClients.findMaterialCleanByCode(materialApplyOrder.getMaterialCode());
            if (!result.getCode().equals(ResultCode.SUCCESS.code)) {
                throw new RuntimeException("查询原料清洗产品模型发生错误");
            }
            MaterialCleanModelDto dto = result.getData();
            if (dto == null) {
                throw new RuntimeException("不存在" + materialApplyOrder.getMaterialCode() + "原料清洗产品模型！");
            }
            //电阻范围
            materialCleanModelDto.setResistanceRange(dto.getResistanceRange());
            //掺杂类型
            materialCleanModelDto.setDopedType(dto.getDopedType());
//            MaterialStoreSignBox materialStoreSignBox = materialStoreSignBoxService.getByBoxNo(materialApplyOrder.getMaterialBoxNo());
//            if (null != materialStoreSignBox){
//                //todo
//                //电阻范围
//                materialCleanModelDto.setResistanceRange(materialStoreSignBox.getMaterialGear());
//                //掺杂类型
//                materialCleanModelDto.setDopedType("");
//            }
            return ResultGenerator.success(materialCleanModelDto);

        }else {
            //没有清洗领料单的情况，查询清洗模型（根据厂家代码、硅料代码）
            Result<MaterialCleanModelDto> byBatchNo = ybFeignClients.findByBatchNo(cleanProductBatchNo);
            if (!byBatchNo.getCode().equals(ResultCode.SUCCESS.code)) {
                throw new RuntimeException("查询原料清洗产品模型发生错误");
            }
            MaterialCleanModelDto cleanModelDto = byBatchNo.getData();
            return ResultGenerator.success(cleanModelDto);
        }
    }

    @ApiOperation(value = "创建")
    @PostMapping("/create")
    public Result create(@RequestBody @Valid @ApiParam(value = "Dto对象") List<MaterialApplyOrderDto> materialApplyOrderDtos, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        if(materialApplyOrderDtos !=null && materialApplyOrderDtos.size()>0){
            Result<List<MaterialCleanModelDto>> byName = ybFeignClients.findByName(materialApplyOrderDtos.get(0).getMaterialName());
            List<MaterialCleanModelDto> data = byName.getData();
            if(null == data || data.size() < 1){
                return ResultGenerator.fail("不存在物料名称为【" + materialApplyOrderDtos.get(0).getMaterialName() + "】的原料清洗产品模型，无法领料");
            } else if (StringUtils.isEmpty(materialApplyOrderDtos.get(0).getMaterialCode())) {
                for (MaterialApplyOrderDto materialApplyOrderDto : materialApplyOrderDtos) {
                    materialApplyOrderDto.setMaterialCode(data.get(0).getCode());
                }
            }
            Map<String, Map<String, List<MaterialApplyOrderDto>>> collect = materialApplyOrderDtos.stream().collect(Collectors.groupingBy(materialApplyOrder -> materialApplyOrder.getMaterialName(), Collectors.groupingBy(materialApplyOrder -> materialApplyOrder.getMaterialCode())));
            Set<Map.Entry<String, Map<String, List<MaterialApplyOrderDto>>>> entries = collect.entrySet();
            for (Map.Entry<String, Map<String, List<MaterialApplyOrderDto>>> entry : entries) {
                Map<String, List<MaterialApplyOrderDto>> value = entry.getValue();
                Set<Map.Entry<String, List<MaterialApplyOrderDto>>> entries1 = value.entrySet();
                for (Map.Entry<String, List<MaterialApplyOrderDto>> stringListEntry : entries1) {
                    List<MaterialApplyOrderDto> value1 = stringListEntry.getValue();
                    //申领数量
                    BigDecimal quantityClaimed = value1.stream().map(dto -> dto.getWeight()).reduce(BigDecimal.ZERO, BigDecimal::add);

                    //计划时间内可领料重量
                    WashingPlanDto washingPlanDto = new WashingPlanDto();
                    washingPlanDto.setMaterialName(entry.getKey());
                    washingPlanDto.setMaterialCode(stringListEntry.getKey());
                    List<WashingPlanDto> list = washingPlanService.queryListByParam(washingPlanDto);
                    if(CollectionUtils.isEmpty(list)){
                        return ResultGenerator.fail("不存在物料名称为【" + washingPlanDto.getMaterialName() + "】，物料编号为【" + washingPlanDto.getMaterialCode() + "】的计划，无法领料");
                    }
                    Date date = new Date();
                    if(list.get(0).getStartTime().getTime() > date.getTime() || list.get(0).getEndTime().getTime() < date.getTime()){
                        return ResultGenerator.fail("物料名称为【" + washingPlanDto.getMaterialName() + "】，物料编号为【" + washingPlanDto.getMaterialCode() + "】的计划领料时间不满足要求");
                    }
                    BigDecimal planWeight = list.stream().map(dto -> dto.getPlannedWeight()).reduce(BigDecimal.ZERO, BigDecimal::add);

                    //当前物料名称、物料编号在计划时间内已领物料数量
                    List<MaterialApplyOrder> materialApplyOrder1 = materialApplyOrderService.getMaterialApplyOrder(entry.getKey(), stringListEntry.getKey(), list.get(0).getStartTime(), list.get(0).getEndTime());
                    if(CollectionUtils.isNotEmpty(materialApplyOrder1)){
                        BigDecimal reduce = materialApplyOrder1.stream().map(dto -> dto.getWeight()).reduce(BigDecimal.ZERO, BigDecimal::add);
                        if(planWeight.subtract(reduce).compareTo(quantityClaimed) < 0){
                            BigDecimal subtract = quantityClaimed.subtract(planWeight.subtract(reduce));
                            return ResultGenerator.fail("物料名称为【" + washingPlanDto.getMaterialName() + "】，物料编号为【" + washingPlanDto.getMaterialCode() + "】的领料数量超出计划量【" + subtract.toString() + "KG】，无法领料");
                        }
                    } else {
                        if(planWeight.compareTo(quantityClaimed) < 0){
                            BigDecimal subtract = quantityClaimed.subtract(planWeight);
                            return ResultGenerator.fail("物料名称为【" + washingPlanDto.getMaterialName() + "】，物料编号为【" + washingPlanDto.getMaterialCode() + "】的领料数量超出计划量【" + subtract.toString() + "KG】，无法领料");
                        }
                    }
                }
            }

            List<MaterialApplyOrder> materialApplyOrders = new ArrayList<>();
            materialApplyOrderDtos.stream().forEach(entity -> {
                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.eq("material_box_no", entity.getMaterialBoxNo());
                //MaterialApplyOrder one = materialApplyOrderService.getOne(queryWrapper);
                List list = materialApplyOrderService.list(queryWrapper);
                if (!CollectionUtils.isEmpty(list)) {
                    throw new RuntimeException("箱号" + entity.getMaterialBoxNo() + "已存在！");
                }
                MaterialApplyOrder materialApplyOrder = fromDto(entity);
                materialApplyOrder.setApplyName(BaseContextHandler.getUsername());
                // “日期 ”要进行加工：如果领料日期在8点半之前，前面的日期会记前一天
                Date createTime = formatApplyTime(new Date());
                LocalDateTime localDateTime = createTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                materialApplyOrder.setApplyTime(LocalDateTime.now());
                materialApplyOrder.setCreateUser(BaseContextHandler.getUsername());
                materialApplyOrder.setCreateTime(localDateTime);
                materialApplyOrders.add(materialApplyOrder);
                //todo:查询待领料表中是否存在重量并大于0;
                // 大于0则无需再过账到wms,(说明在回收料发起入库的时候已经入库到wms)
                // 小于等于0,则需要过账到wms,并回写到回收料数据中(说明当时没有录入重量)
                MaterialStoreSignBox materialStoreSignBox = materialStoreSignBoxService.getByBoxNo(materialApplyOrder.getMaterialBoxNo());
                if (null != materialStoreSignBox) {
                    BigDecimal oldWeight = materialStoreSignBox.getWeight();
                    if (null != oldWeight && oldWeight.compareTo(BigDecimal.ZERO) > 0) {


                    } else {
                        //todo:传到wms过账
                        if (active.equals("prod")) {
                            cleanMesThreadPoolExecutor.execute(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        //TODO 过账到wms
                                        RecycledMaterialInDto recycledMaterialInDto = buildRecycledMaterialInDto(materialApplyOrder);
                                        String url = wmsServiceUrl + recycleToWms;
                                        ResultWms resultJson = requestRecycleMaterialToWMS(url, recycledMaterialInDto, "清洗领料过账到WMS");

                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        log.error("清洗领料触发过账到wms", e);
                                    }
                                }
                            });
                        }
                        //回写到回收料箱号信息重量
                        ybFeignClients.updateRecycledManageWeight(materialStoreSignBox.getBoxNo(), entity.getWeight());
                    }
                }
                //更新此箱号对应的箱子记录 是否成箱=1
                materialApplyOrderService.updateBoxByMaterialApplyOrder(materialApplyOrder);
                //updateBoxByMaterialApplyOrder(materialApplyOrder);

                //记录批次站点
                cleaningProcessFlowService.inStation(materialApplyOrder.getClanProductBatchNo(), materialApplyOrder.getClanProductBatchNo(), materialApplyOrder.getWeight(),materialApplyOrder.getUnusedWeight(), materialApplyOrder.getUsedWeight(), null,
                        materialApplyOrder.getHasGone(), null, materialApplyOrder.getBoxNo(), EnumValuesFactory.CleaningWipStorageCode.领料.getValue(), EnumValuesFactory.CleaningWipStorageStatus.工序待进站.getKey());

            });
            materialApplyOrderService.saveBatch(materialApplyOrders);
        }
        return ResultGenerator.success();
    }

    @ApiOperation(value = "合批")
    @PostMapping("/blending")
    public Result blending(@RequestBody @Valid @ApiParam(value = "Dto对象") List<MaterialApplyOrderDto> materialApplyOrderDtos, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        RecyclScanBoxNoParam param = new RecyclScanBoxNoParam();
        if(materialApplyOrderDtos !=null && materialApplyOrderDtos.size()>0){

            String productBatchNo = materialApplyOrderDtos.get(0).getProductBatchNo();
            MaterialStoreSignBox storeSignBox = materialStoreSignBoxService.getByProductBatchNo(productBatchNo);
            //物料等级
            String materialLevel = storeSignBox.getMaterialLevel();
            //物料档位
            String materialGear = storeSignBox.getMaterialGear();
            //物料名称
            String materialName = storeSignBox.getMaterialName();

            for (MaterialApplyOrderDto materialApplyOrderDto : materialApplyOrderDtos) {
                MaterialStoreSignBox storeSignBox1 = materialStoreSignBoxService.getByProductBatchNo(materialApplyOrderDto.getProductBatchNo());
                if(null == storeSignBox1){
                    throw new RuntimeException("不存在批次号为【" + materialApplyOrderDto.getProductBatchNo() +  "】的待领料数据");
                }
                if(!storeSignBox1.getMaterialLevel().equals(materialLevel)) {
                    throw new RuntimeException("存在" + materialLevel + "和" + storeSignBox1.getMaterialLevel() + "不同等级的物料无法合批");
                }
                if(!storeSignBox1.getMaterialGear().equals(materialGear)) {
                    throw new RuntimeException("存在" + materialGear + "和" + storeSignBox1.getMaterialGear() + "不同档位的物料无法合批");
                }
                if(!storeSignBox1.getMaterialName().equals(materialName)) {
                    throw new RuntimeException("存在" + materialName + "和" + storeSignBox1.getMaterialName() + "不同物料名称的物料无法合批");
                }
            }

            //总重量
            BigDecimal quantityClaimed = materialApplyOrderDtos.stream().map(dto -> dto.getWeight()).reduce(BigDecimal.ZERO, BigDecimal::add);
            MaterialApplyOrderDto materialApplyOrderDto = materialApplyOrderDtos.stream().max(Comparator.comparing(MaterialApplyOrderDto::getWeight)).get();

            param.setAccptWeight(quantityClaimed);
            param.setBoxNo(materialApplyOrderDto.getBoxNo());

            //被合批箱子要置空
            for (MaterialApplyOrderDto applyOrderDto : materialApplyOrderDtos) {
                if(!applyOrderDto.getBoxNo().equals(materialApplyOrderDto.getBoxNo())){
                    //领料扣减
                    String productBatchNo1 = applyOrderDto.getProductBatchNo();
                    CleanReworking byBatchNo = cleanReworkingService.getByBatchNo(productBatchNo1);
                    if(null != byBatchNo){
                        byBatchNo.setUsedWeight(applyOrderDto.getWeight());
                        byBatchNo.setUnusedWeight(byBatchNo.getWeight().subtract(applyOrderDto.getWeight()));
                        materialUnpackingService.updateBoxStatus(byBatchNo.getMaterialBoxNo(), byBatchNo.getWeight().subtract(applyOrderDto.getWeight()), null);
                    }

//                    CarrierConfigDto carrierConfigDto = new CarrierConfigDto();
//                    carrierConfigDto.setCarrierNo(applyOrderDto.getBoxNo());
//                    carrierConfigDto.setStatus(0);
//                    ybFeignClients.updateCarrierConfigStatus(carrierConfigDto);
                }
            }
        }
        return ResultGenerator.success(param);
    }

    /**
     * 原生多晶、返工、落地领料
     * @param param
     * @param bindingResult
     * @return
     */
    @ApiOperation(value = "领料扫码")
    @PostMapping("/receiveMaterialByScan")
    public Result<MaterialApplyOrderDto> receiveMaterialByScan(@RequestBody @Valid @ApiParam(value = "Dto对象") GeneralScanBoxNoParam param, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        if (param.getBoxNo().isEmpty() || param.getScanName().isEmpty()){
            throw new RuntimeException("查询参数不能为空！");
        }
        BoxPropertyDto boxPropertyDto = materialStoreSignBoxService.generalScanBoxNo(param);
        MaterialApplyOrder materialApplyOrder = fromBoxDto(boxPropertyDto,param.getScanName());
        MaterialApplyOrderDto materialApplyOrderDto = toLazyDto(materialApplyOrder);
        materialApplyOrderDto.setMaterialSource(boxPropertyDto.getMaterialResource());
        //materialApplyOrderService.save(materialApplyOrder);
        //更新此箱号对应的箱子记录 是否成箱=1
        //updateBox(boxPropertyDto);
        return ResultGenerator.success(materialApplyOrderDto);
    }


    /**
     * 回收料扫码，领料时会录入重量，单独一个接口
     * @param param
     * @param bindingResult
     * @return
     */
    @PostMapping("/receiveMaterialByScanForRecycle")
    public Result<MaterialApplyOrderDto> receiveMaterialByScanForRecycle(@RequestBody @Valid @ApiParam(value = "Dto对象") RecyclScanBoxNoParam param, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        if (param.getBoxNo().isEmpty() || param.getScanName().isEmpty() || param.getAccptWeight() == null) {
            throw new RuntimeException("接收重量不能为空！");
        }
        if (param.getAufnr().isEmpty()) {
            throw new RuntimeException("回收料领料ERP工单不能为空！");
        }
        //通过领料箱(卡板箱号找到待领料箱号)  （此段代码为从包头平移）
        MaterialStoreSignBox storeSignBox = materialStoreSignBoxService.getByKbxBoxNo(param.getBoxNo());
        if (null == storeSignBox || storeSignBox.getMaterialBoxNo().isEmpty()) {
            throw new RuntimeException("领料箱号对应待领料数据不存在！");
        }
        BoxPropertyDto boxPropertyDto = materialStoreSignBoxService.generalScanBoxNo(new GeneralScanBoxNoParam(storeSignBox.getMaterialBoxNo(), param.getScanName()));
        MaterialApplyOrder materialApplyOrder = fromBoxDto(boxPropertyDto, param.getScanName());
        MaterialApplyOrderDto materialApplyOrderDto = toLazyDto(materialApplyOrder);
        materialApplyOrderDto.setWeight(param.getAccptWeight());
        materialApplyOrderDto.setAufnr(param.getAufnr());
        //clanProductBatchNo 清洗批次号
        String productBatchNo = storeSignBox.getProductBatchNo();
        String newBatchNo = getNewBatchNo(productBatchNo);
        materialApplyOrderDto.setProductBatchNo(productBatchNo);
        materialApplyOrderDto.setErpWarehouseCode(storeSignBox.getErpWarehouseCode());
        materialApplyOrderDto.setClanProductBatchNo(newBatchNo);

        return ResultGenerator.success(materialApplyOrderDto);
    }



    private String getNewBatchNo(String productBatchNo){
        String leftS = "";
        String rightS = "";
        String midS = "";
        //替换中间四位时间字段
        if (!StringUtils.isEmpty(productBatchNo) && productBatchNo.length()>=11){
            leftS = productBatchNo.substring(0,2);

            //清洗领料车间要改，暂时写死，原料一车间：1
            rightS = productBatchNo.substring(6,10)+ CleanFactoryCodeEnum.云南清洗车间.getKey();
            midS = dateStringNew();
        }
        return leftS+midS+rightS;
    }


    /**
     * 获取日期 例如： 年份：22年
     *               月份：1-9月用数字表示，10-12月用A/B/C表示
     *               日期：1-31号
     *               22A23  --  22年10月23日
     * @return
     */
    private String dateStringNew(){
        Calendar instance = Calendar.getInstance();
        instance.setTime(new Date());

        String yearAll = Convert.toStr(instance.get(Calendar.YEAR));
        //取最后一位
        String strYear = yearAll.substring(yearAll.length() - 1);

        int intMonth = instance.get(Calendar.MONTH) + 1;
        String strMonth = Convert.toStr(intMonth);
        if (intMonth>9){
            switch (intMonth){
                case 10:
                    strMonth="A";
                    break;
                case 11:
                    strMonth="B";
                    break;
                case 12:
                    strMonth="C";
                    break;
            }
        }

        String strDay = Convert.toStr(instance.get(Calendar.DAY_OF_MONTH));

        //给 1月3日 补充0；3 -> 03
        String supplementZeroStrDay = StringUtils.leftPad(strDay, 2, "0");

        return strYear + strMonth + supplementZeroStrDay;
    }



    @ApiOperation(value = "领料扫码")
    @PostMapping("/findByBoxNo")
    @Deprecated
    public Result<MaterialApplyOrderDto> findByBoxNo(@RequestBody @Valid @ApiParam(value = "Dto对象")CreateOderDto createOderDto,BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        MaterialApplyOrderDto materialApplyOrderDto = new MaterialApplyOrderDto();
        String oldBoxNo = createOderDto.getBoxNo();
        //通过BoxNo去线边仓获取物料料号，料号去物料模型获取其他信息，再生成批次号和箱号
        //TODO 通过箱号去线边仓获取物料料号
        String code = "";
        Integer sign = createOderDto.getSign();
        if(ItemCleanEnums.MaterialType.回收料.getKey() == sign){
            if (null == createOderDto.getWeight()){
                return ResultGenerator.fail("回收料重量必填！");
            }else{
                materialApplyOrderDto.setWeight(createOderDto.getWeight());
            }
        }else{
            //TODO 非回收料获取重量
            //materialApplyOrderDto.setWeight()
        }
        Result<MaterialCleanModelDto> result = ybFeignClients.findMaterialCleanByCode(code);
        if (!result.getCode().equals(ResultCode.SUCCESS.code)) {
            return ResultGenerator.fail(result.getMessage());
        }
        MaterialCleanModelDto dto = Optional.of(result).map(Result::getData).orElse(null);
        if (dto == null) {
            return ResultGenerator.fail("不存在"+code+"原料清洗产品模型！");
        }
        //通过物料模型组装领料订单
        this.assemble(materialApplyOrderDto,dto);
        String batchNo = null;
        String boxNo = null;
        try {
            batchNo = generateBusinessNoService.generateProductBatchNo(new BatchNoOperate(ItemCleanEnums.BatchType.原料生产, code));
            boxNo = generateBusinessNoService.generateBoxNo(new BoxNoOperate(ItemCleanEnums.BoxNoType.默认, new BatchNo(batchNo)));
        }catch(RuntimeException e){
            return ResultGenerator.fail(e.getMessage());
        }
        materialApplyOrderDto.setProductBatchNo(batchNo);
        materialApplyOrderDto.setMaterialBoxNo(boxNo);
        materialApplyOrderDto.setOrderType(sign);
        materialApplyOrderDto.setMaterialProp(sign);
        return ResultGenerator.success(materialApplyOrderDto);
    }

    @ApiOperation(value = "更新")
    @PostMapping("/update")
    public Result update(@RequestBody @Valid @ApiParam(value = "Dto对象") MaterialApplyOrderDto dto, BindingResult bindingResult) {
        if (bindingResult.hasErrors())
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        if (dto.getId() == null)
            return ResultGenerator.fail("id不能为空");
        MaterialApplyOrder entity = materialApplyOrderService.getById(dto.getId());
        if (entity == null)
            return ResultGenerator.fail("原信息不存在");
        try {
            MaterialApplyOrder entityfromFto = fromDto(dto);
            BeanUtils.copyProperties(entityfromFto, entity, BeanUtil.getIgnoreProperties(entityfromFto, null, null));
            materialApplyOrderService.saveOrUpdate(entity);
            return ResultGenerator.success();
        } catch (Exception e) {
            log.error(ExceptionUtil.stacktraceToString(e));
            return ResultGenerator.fail(e.getMessage());
        }
    }

    @ApiOperation(value = "删除")
    @PostMapping("/delete")
    public Result remove(@ApiParam(value = "id集合,逗号分隔,如2,4", type = "query") @RequestParam Integer[] ids) {
        for (Integer id : ids) {
            materialApplyOrderMapper.deleteById(id);
        }
        return ResultGenerator.success();
    }


    /**
     * 导出原料清洗订单
     * @param request
     * @param response
     */
    @ApiOperation(value = "导出原料清洗订单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "search_LIKE_materialName", value = "物料名称", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialLevel", value = "物料等级", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialModel", value = "物料型号", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialBoxNo", value = "领料单箱号", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialComp", value = "厂家/来源", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_materialProp", value = "物料属性", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_productBatchNo", value = "物料批次", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_orderType", value = "领料单类型", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_sonId", value = "儿子箱子id", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "search_GTE_applyTime", value = "领料开始时间", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_LTE_applyTime", value = "领料结束时间", dataType = "string", paramType = "query"),
    })
    @GetMapping("/export")
    public void export(ServletRequest request,  HttpServletResponse response) {
        try {
            QueryWrapper<MaterialApplyOrder> queryWrapper =  DynmaicQueryWrapper.searchFilter(request, MaterialApplyOrder.class);
            List<MaterialApplyOrder> list = materialApplyOrderService.list(queryWrapper);
            List<MaterialApplyOrderDto> dtos = list.stream()
                    .map(entity -> toLazyDto(entity))
                    .collect(Collectors.toList());

            for (MaterialApplyOrderDto dto : dtos) {
                String s = "";
                List<MaterialApplyOrderRelation> materialApplyOrderRelations = materialApplyOrderRelationService.findByMaterialBoxNoParent(dto.getMaterialBoxNo());
                if (materialApplyOrderRelations.size() > 0) {
                    for (MaterialApplyOrderRelation materialApplyOrderRelation : materialApplyOrderRelations) {
                        if (StringUtils.isNotEmpty(materialApplyOrderRelation.getMaterialBoxNoSon())) {
                            s += materialApplyOrderRelation.getMaterialBoxNoSon() + ",";
                        }
                    }
                }
                dto.setMaterialBoxNoSons(s);
            }
            EasyExcelUtils.write(response, MaterialApplyOrderDto.class, "导出原料清洗订单", "导出原料清洗订单", dtos);
        } catch (Exception e) {
            throw new RuntimeException("导出原料清洗订单失败，错误信息：" + e.getMessage());
        }
    }

    @ApiOperation(value = "通过领料箱号获取信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "materialBoxNo", value = "物料箱号", dataType = "String", paramType = "query"),
    })
    @GetMapping(value = "/findByMaterialBoxNo")
    public @ResponseBody
    Result findByMaterialBoxNo(String materialBoxNo) {
        MaterialApplyOrder materialApplyOrder = materialApplyOrderService.getByMaterialBoxNo(materialBoxNo);
        if (null == materialApplyOrder) {
            return ResultGenerator.fail("该对象不存在");
        }
        return ResultGenerator.success(toEagerDto(materialApplyOrder));
    }

    public MaterialApplyOrderDto toLazyDto(MaterialApplyOrder entity) {
        return modelMapper.map(entity, MaterialApplyOrderDto.class);
    }

    public MaterialApplyOrderDto toEagerDto(MaterialApplyOrder entity) {
        MaterialApplyOrderDto dto = modelMapper.map(entity, MaterialApplyOrderDto.class);
        return dto;
    }

    public MaterialApplyOrder fromDto(MaterialApplyOrderDto dto) {
        return modelMapper.map(dto, MaterialApplyOrder.class);
    }


    public MaterialApplyOrder fromBoxDto(BoxPropertyDto boxPropertyDto,String scanName) {
        MaterialApplyOrder materialApplyOrder = modelMapper.map(boxPropertyDto, MaterialApplyOrder.class);
        materialApplyOrder.setId(null);
//        switch (boxPropertyDto.getMaterialType()){
//            case 1: materialApplyOrder.setMaterialProp(1);
//                break;
//            case 2:materialApplyOrder.setMaterialProp(2);
//                break;
//            case 3:materialApplyOrder.setMaterialProp(3);
//                break;
//            case 4:materialApplyOrder.setMaterialProp(4);
//                break;
//        }
        switch (scanName) {
            case "原生多晶领料":
                materialApplyOrder.setOrderType(1);
                break;
            case "回收料领料":
                materialApplyOrder.setOrderType(2);
                break;
            case "落地料领料":
                materialApplyOrder.setOrderType(3);
                break;
            case "返工领料":
                materialApplyOrder.setOrderType(4);
                break;
        }
        materialApplyOrder.setMaterialProp(boxPropertyDto.getMaterialType());
        materialApplyOrder.setApplyName(BaseContextHandler.getUsername());
        materialApplyOrder.setApplyTime(LocalDateTime.now());
        materialApplyOrder.setCreateUser(BaseContextHandler.getUsername());
        materialApplyOrder.setCreateTime(LocalDateTime.now());
        //materialApplyOrder.setOrderType(boxPropertyDto.getMaterialType());
        materialApplyOrder.setDelFlag(0);
        Result<MaterialCleanModelDto> result = ybFeignClients.findMaterialCleanByCode(boxPropertyDto.getMaterialCode());
        if (!result.getCode().equals(ResultCode.SUCCESS.code)) {
            throw new RuntimeException("查询原料清洗产品模型发生错误");
        }
        MaterialCleanModelDto materialCleanModelDto = result.getData();
        if (materialCleanModelDto == null) {
            throw new RuntimeException("不存在"+boxPropertyDto.getMaterialCode()+"原料清洗产品模型！");
        }
        materialApplyOrder.setMaterialComp(materialCleanModelDto.getFactory());
        //物料型号、型号编码赋值
        materialApplyOrder.setMaterialModel(materialCleanModelDto.getDopedType());
        materialApplyOrder.setMaterialModelCode(materialCleanModelDto.getDopedTypeCode());
        materialApplyOrder.setBoxNo(boxPropertyDto.getBoxNo());
        return materialApplyOrder;
    }

    public Result updateBoxByMaterialApplyOrder(MaterialApplyOrder materialApplyOrder){
        if (materialApplyOrder.getMaterialBoxNo() == null)
            return ResultGenerator.fail("箱号不能为空");
        MaterialStoreSignBox entity = materialStoreSignBoxService.getByBoxNo(materialApplyOrder.getMaterialBoxNo());
        if (entity == null)
            return ResultGenerator.fail("原信息不存在");
        try {
            entity.setPickingStatus(1);
            materialStoreSignBoxService.saveOrUpdate(entity);
            return ResultGenerator.success();
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }



    public Date formatApplyTime(Date time){
        // 按照规则加工领料申请单的领料时间
        int nowDateHour = time.getHours();
        int nowDateMinute = time.getMinutes();
        int nowSecond = time.getSeconds();

        if (8 == nowDateHour && nowDateMinute >= 30 && nowSecond >= 0) {
            return new Date();
        } else {
            //8:30:01后 - 24点前
            if (nowDateHour >= 9) {
                return new Date();
            } else {     //24点后--8:29:59,日期记前一天
                String nowDateSring = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
                //获取前一天时间  yyyy-MM-dd-1 08:30:00
                Calendar c = Calendar.getInstance();
                try {
                    c.setTime(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(nowDateSring));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                int day1 = c.get(Calendar.DATE);
                c.set(Calendar.DATE, day1 - 1);
                return c.getTime();
            }
        }
    }


    public Result updateBox(BoxPropertyDto boxPropertyDto){
        if (boxPropertyDto.getId() == null)
            return ResultGenerator.fail("id不能为空");
        MaterialStoreSignBox entity = materialStoreSignBoxService.getById(boxPropertyDto.getId());
        if (entity == null)
            return ResultGenerator.fail("原信息不存在");
        try {
            entity.setPickingStatus(1);
            materialStoreSignBoxService.saveOrUpdate(entity);
            return ResultGenerator.success();
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    //通过物料模型组装物料领料单
    private void assemble(MaterialApplyOrderDto materialApplyOrderDto, MaterialCleanModelDto dto) {
        materialApplyOrderDto.setMaterialCode(dto.getCode());
        materialApplyOrderDto.setMaterialName(dto.getName());
        materialApplyOrderDto.setMaterialLevel(dto.getLevel());
        //TODO 物料型号,挡位未知
//        materialApplyOrderDto.setMaterialModel();
//        materialApplyOrderDto.setMaterialGear();
        materialApplyOrderDto.setMaterialComp(dto.getFactory());
    }


    /**
     * 组装清洗过账到wms数据
     *
     * @param materialApplyOrder
     * @return
     */
    private RecycledMaterialInDto buildRecycledMaterialInDto(MaterialApplyOrder materialApplyOrder) {
        RecycledMaterialInDto recycledMaterialInDto = new RecycledMaterialInDto();
        recycledMaterialInDto.setBatchNo(materialApplyOrder.getProductBatchNo());
        recycledMaterialInDto.setInQty(materialApplyOrder.getWeight());
        recycledMaterialInDto.setLevelID(materialApplyOrder.getMaterialLevel());
        recycledMaterialInDto.setMaterialClassID("1");
        recycledMaterialInDto.setMaterialNo(materialApplyOrder.getMaterialCode());
        recycledMaterialInDto.setOperateDT(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        recycledMaterialInDto.setOperator(BaseContextHandler.getUsername());
        recycledMaterialInDto.setOutQty(materialApplyOrder.getWeight());
        recycledMaterialInDto.setPlanNo(materialApplyOrder.getProductBatchNo());
        recycledMaterialInDto.setRemark(null);
        recycledMaterialInDto.setSpecification(materialApplyOrder.getMaterialModel());
        recycledMaterialInDto.setUnit("KG");
        return recycledMaterialInDto;
    }


    private ResultWms requestRecycleMaterialToWMS(String url, RecycledMaterialInDto recycledMaterialInDto, String requestName) {
        String resultJson;
        boolean isErr = false;
        try {
            HttpHeaders headers = new HttpHeaders();
            MediaType mediaType = MediaType.parseMediaType("application/json; charset=UTF-8");
            headers.setContentType(mediaType);
            headers.add("Accept", MediaType.APPLICATION_JSON.toString());
            List<RecycledMaterialInDto> recycledMaterialInDtos = new ArrayList<>();
            recycledMaterialInDtos.add(recycledMaterialInDto);
            HttpEntity<List<RecycledMaterialInDto>> httpEntity = new HttpEntity<>(recycledMaterialInDtos, headers);
            ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
            resultJson = responseEntity.getBody();
        } catch (Exception e) {
            e.printStackTrace();
            resultJson = e.getMessage();
            isErr = true;
        }
        if (isErr) {
            return null;
        } else {
            return JSON.parseObject(resultJson, new TypeReference<ResultWms>() {
            });
        }
    }


    //此接口平移自包头
    @ApiOperation(value = "通过领料卡板箱号获取ERP工单信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "materialBoxNo", value = "卡板箱号", dataType = "String", paramType = "query"),
    })
    @GetMapping(value = "/findERPInfoByMaterialBoxNo")
    public @ResponseBody
    Result findERPInfoByMaterialBoxNo(String materialBoxNo) {
        MaterialStoreSignBox materialStoreSignBox = materialStoreSignBoxService.getByKbxBoxNo(materialBoxNo);
        if (null == materialStoreSignBox) {
            return ResultGenerator.fail("该对象不存在");
        }
        Result<MaterialCleanModelDto> result = ybFeignClients.findMaterialCleanByCode(materialStoreSignBox.getMaterialCode());
        if (!result.getCode().equals(ResultCode.SUCCESS.code)) {
            throw new RuntimeException("查询原料清洗产品模型发生错误");
        }
        MaterialCleanModelDto materialCleanModelDto = result.getData();
        if (materialCleanModelDto == null) {
            throw new RuntimeException("不存在" + materialStoreSignBox.getMaterialCode() + "原料清洗产品模型！");
        }
        //通过成品编码查询清洗计划工单
        List<String> aufnrList = new ArrayList<>();
        List<MaterialPlanOrder> erpList = materialPlanOrderService.findByMatnr(materialCleanModelDto.getFinishedCode());
        if (CollectionUtils.isEmpty(erpList)) {
            throw new RuntimeException("查询ERP工单为空!");
        } else {
            aufnrList = erpList.stream().map(MaterialPlanOrder::getAufnr).collect(Collectors.toList());
        }
        return ResultGenerator.success(aufnrList);
    }

    @ApiOperation(value = "通用-通过箱号获取箱内物料信息(也可用于校验重量等信息)")
    @GetMapping("/getInfoByBoxNo")
    public Result<BoxInfoDto> getInfoByBoxNo(String boxNo,String sourceProcess) {
        BoxInfoDto boxInfoDto = materialApplyOrderService.getByBoxNoAndLastSit(boxNo,sourceProcess);
        if (boxInfoDto == null) {
            return ResultGenerator.fail("该箱号不存在");
        } else {
            return ResultGenerator.success(boxInfoDto);
        }
    }
}
