package com.prolog.eis.service.page.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.prolog.cs.basic.item.model.vo.ItemBaseInfoVO;
import com.prolog.eis.common.util.JsonHelper;
import com.prolog.eis.constants.cfg.LocationCfgConstants;
import com.prolog.eis.dto.item.ItemSyncVO;
import com.prolog.eis.constants.base.BaseTaskTypeConstants;
import com.prolog.eis.constants.base.ContainerTaskTypeConstants;
import com.prolog.eis.constants.wms.WmsConstants;
import com.prolog.eis.core.dto.route.ContainerLocationDto;
import com.prolog.eis.core.model.biz.route.ContainerLocation;
import com.prolog.eis.dto.contaienr.ContainerCleanDto;
import com.prolog.eis.dto.rf.*;
import com.prolog.eis.enums.base.LayerEnum;
import com.prolog.eis.enums.station.StationTypeEnum;
import com.prolog.eis.enums.wms.WmsCarryTaskInCode;
import com.prolog.eis.model.container.*;
import com.prolog.eis.model.sys.SysParam;
import com.prolog.eis.router.vo.ContainerLocationVo;
import com.prolog.eis.service.container.*;
import com.prolog.eis.service.feign.FeignGoodsService;
import com.prolog.eis.service.feign.RouteFeignService;
import com.prolog.eis.service.inbound.BizInboundTaskService;
import com.prolog.eis.service.inbound.InventoryService;
import com.prolog.eis.service.page.PdaService;
import com.prolog.eis.service.sys.SysParamService;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.utils.AssertUtils;
import com.prolog.framework.utils.MapUtils;
import com.prolog.upcloud.base.inventory.model.BatchNumberSync;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;

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

/**
 * @desc:
 * @author: zhangJie
 * @date: 2023/9/1 10:42
 */
@Service
@RequiredArgsConstructor
public class PdaServiceImpl implements PdaService {

    private final RouteFeignService routeFeignService;
    private final StationCfgService stationCfgService;
    private final ContainerInfoService containerInfoService;
    private final ContainerInfoDetailService containerInfoDetailService;
    private final RouteFeignService  plgFeignRouteService;
    private final LocationCfgService locationCfgService;
    private final BizInboundTaskService bizInboundTaskService;
    private final EmptyContainerTaskService emptyContainerTaskService;
    private final FeignGoodsService goodsService;
    private final InventoryService inventoryService;
    private final ContainerTaskService containerTaskService;
    private final FeignGoodsService feignGoodsService;
    private final SysParamService sysParamService;


    @Override
    public void cleanContainerItem(ContainerCleanDto containerCleanDto)throws Exception {
        Criteria criteria = new Criteria(ContainerTask.class);
        if (StrUtil.isNotBlank(containerCleanDto.getLocationNo())) {
            ContainerLocationDto containerLocationDto = routeFeignService.findContainerInfoByLocation(MapUtils.put("locationNo", containerCleanDto.getLocationNo()).getMap());
            AssertUtils.isNotTrue(Objects.isNull(containerLocationDto)||StrUtil.isBlank(containerLocationDto.getContainerNo()), "当前点位无容器信息");
            AssertUtils.isNotTrue(StrUtil.isNotBlank(containerCleanDto.getContainerNo()) && StrUtil.isNotBlank(containerLocationDto.getContainerNo()) && !StrUtil.equals(containerLocationDto.getContainerNo(), containerCleanDto.getContainerNo()), "当前点位容器和传入容器不一致");
            criteria.restrictionBuilder().eq(ContainerTask::getContainerNo, containerLocationDto.getContainerNo()).lt(ContainerTask::getStatus, 3).build();
            Long count = containerTaskService.findCountByCriteria(criteria);
            AssertUtils.isNotTrue(count>0, "释放失败，存在出库单未拣货！");
            cleanContainer(containerLocationDto.getContainerNo(), containerLocationDto.getCurrentArea());
        } else if (StrUtil.isNotBlank(containerCleanDto.getContainerNo())) {
            ContainerLocationVo containerLocationVo = routeFeignService.findLocationByContainerList(Arrays.asList(containerCleanDto.getContainerNo())).stream().findFirst().orElseThrow(() -> new PrologException("容器点位不存在"));
            AssertUtils.isNotTrue(StrUtil.isNotBlank(containerCleanDto.getLocationNo()) && StrUtil.isNotBlank(containerLocationVo.getCurrentLocation()) && !StrUtil.equals(containerLocationVo.getCurrentLocation(), containerCleanDto.getLocationNo()), "当前容器点位和传入的点位不一致");
            criteria.restrictionBuilder().eq(ContainerTask::getContainerNo, containerCleanDto.getContainerNo()).lt(ContainerTask::getStatus, 3).build();
            Long count = containerTaskService.findCountByCriteria(criteria);
            AssertUtils.isNotTrue(count>0, "释放失败，存在出库单未拣货！");
            cleanContainer(containerCleanDto.getContainerNo(), containerLocationVo.getCurrentArea());
        } else {
            throw new PrologException("参数不能为空");
        }
    }

    private void cleanContainer(String containerNo,String areaNo)throws Exception {
        StationCfg stationCfg = stationCfgService.findByMap(MapUtils.put("areaNo", areaNo).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("对应站台点位未配置"));
        if (stationCfg.getStationType().intValue() == StationTypeEnum.BHGP_TYPE.getCode()) {
            //不合格品点位释放把托盘搬到碟盘机后再释放
            emptyContainerTaskService.save(containerNo, LayerEnum.TWO,WmsCarryTaskInCode.MJZ);
        } else {
            routeFeignService.containerOffShelf(containerNo);
        }
    }

    @Override
    public List<DemonstrateTask> demonstrateList(DemonstrateTaskDto demonstrateTaskDto) throws Exception {
        setItemIds(demonstrateTaskDto);
        List<DemonstrateTask> data = containerInfoService.findStockList(demonstrateTaskDto);
        List<String> itemIds = data.stream().map(item -> item.getItemId()).collect(Collectors.toList());
        final List<String> lotIds = data.stream().map(DemonstrateTask::getLotId).collect(Collectors.toList());
        List<ItemSyncVO> itemSyncVOS = goodsService.queryItemMst(itemIds);
        List<BatchNumberSync> batchNumberSync = inventoryService.getBatchNumberSync(lotIds);
        for (DemonstrateTask datum : data) {
            BatchNumberSync numberSync= batchNumberSync.stream().filter(inner -> inner.getBatchId().equals(datum.getLotId())).findFirst().orElseThrow(() -> new PrologException("为查询到批次信息"));
            ItemSyncVO itemSyncVO = itemSyncVOS.stream().filter(item -> StrUtil.equals(item.getItemId(), datum.getItemId())).findFirst().get();
            datum.setItemCode(itemSyncVO.getItemCode());
            datum.setItemName(itemSyncVO.getItemName());
            datum.setLotId(numberSync.getBatchNum());
        }
        return data;
    }
    private void setItemIds(DemonstrateTaskDto req) {
        if (StrUtil.isNotBlank(req.getItemName())) {
            List<ItemBaseInfoVO> itemInfoList = goodsService.getItemByName(req.getItemName());
            if (CollectionUtils.isEmpty(itemInfoList)) {
                req.setItemIds("-1");
            } else {
                List<String> itemIds1 = itemInfoList.stream().map(ItemBaseInfoVO::getItemId).collect(Collectors.toList());
                req.setItemIds(StrUtil.join(",", itemIds1));
            }
        }
    }
    @Override
    public void demonstrateTaskReq(DemonstrateTaskReqDto demonstrateTaskReqDto) throws Exception {
        ContainerInfoDetail containerInfoDetail = containerInfoDetailService.findByMap(MapUtils.put("containerSubNo",demonstrateTaskReqDto.getContainerSubNo()).getMap()).stream().findFirst().orElseThrow(()->new PrologException("容器详情信息未查询到"));
        ContainerInfo containerInfo = containerInfoService.findByMap(MapUtils.put("containerNo",containerInfoDetail.getContainerNo()).getMap()).stream().findFirst().orElseThrow(()->new PrologException("容器信息未查询到"));
        AssertUtils.isNotTrue(containerInfo.getTaskType() != 0,"当前容器正在运行中，不可演示出库");

        String targetAreaNo = null;
        if (demonstrateTaskReqDto.getType() == 2) {
            LocationCfg locationCfg = locationCfgService.findByMap(MapUtils.put("wmsAreaNo", WmsCarryTaskInCode.NG01.getCode()).put("type", 6).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("不合格品库区未配置"));
            if (!routeFeignService.checkAreaIn(locationCfg.getAreaNo())) {
                throw new PrologException("不合格品库区没有空闲货位");
            }
            targetAreaNo = locationCfg.getAreaNo();
        } else {
            targetAreaNo = getTargetAreaNo(containerInfo.getWarehouseArea());
        }


        containerInfoService.updateMapById(containerInfo.getId(),MapUtils.put("taskType", ContainerTaskTypeConstants.DEMO).getMap());


        //创建搬运任务
        plgFeignRouteService.createCarryTask(containerInfo.getContainerNo(), null, null, null, targetAreaNo, null,
                String.valueOf(BaseTaskTypeConstants.DEMO), 1, "演示出库搬运",null);

        /*CarryTask carryTask = new CarryTask();
        carryTask.setId(StrUtil.uuid());
        carryTask.setPalletNo(containerInfo.getContainerNo());
        carryTask.setContainerNo(containerInfo.getContainerNo());
        carryTask.setTaskType(LocationConstants.PATH_TASK_TYPE_CARRY);
        carryTask.setEndRegion(targetAreaNo);
        carryTask.setCreateTime(new Date());
        carryTask.setBusinessType(String.valueOf(BaseTaskTypeConstants.DEMO));
        carryTask.setTaskRemark("演示出库搬运");
        plgFeignRouteService.createBatchCarry(Arrays.asList(carryTask));*/
    }

    private String getTargetAreaNo(String warehouseArea) throws Exception {
        //四向库为在线拣选位 //整件为拣选站台   //拆零为上架站台
        List<StationCfg> stationList = stationCfgService.findByMap(MapUtils.put("isLock", 0).getMap());
        if(warehouseArea.equals(WmsConstants.MJZ)){
            //四向库为在线拣选位
            stationList = stationList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.SXKJX_TYPE.getCode())).collect(Collectors.toList());
        }else if(warehouseArea.equals(WmsConstants.AGVL)){
            //拆零为叫料站台
            stationList = stationList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.CL_TYPE.getCode())).collect(Collectors.toList());
        }else{
            //整件为拣选站台
            stationList = stationList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.JX_TYPE.getCode())).collect(Collectors.toList());
        }
        List<ContainerLocation> containerLocationVos = plgFeignRouteService.findContainerLocationByTargetAreaNos(stationList.stream().map(StationCfg::getAreaNo).distinct().collect(Collectors.toList()));
        Map<String,Long> taskNum = containerLocationVos.stream().collect(Collectors.groupingBy(ContainerLocation::getTargetArea, Collectors.counting()));
        //获取区域任务数
        for (StationCfg station : stationList) {
            station.setTaskNum(0l);
            if(taskNum.containsKey(station.getAreaNo())){
                station.setTaskNum(taskNum.get(station.getAreaNo()));
            }
        }
        stationList = stationList.stream().sorted(Comparator.comparing(StationCfg :: getTaskNum)).collect(Collectors.toList());
        return stationList.get(0).getAreaNo();
    }

    @Override
    public DemonstrateTaskInfo demonstrateTaskInfo(DemonstrateTaskReqDto demonstrateTaskReqDto) throws Exception {
        DemonstrateTaskInfo demonstrateTaskInfo = containerInfoService.findDemonstrateTaskInfo(demonstrateTaskReqDto);
        ItemSyncVO itemInfo = goodsService.getItemInfo(demonstrateTaskInfo.getItemId());
        demonstrateTaskInfo.setItemCode(itemInfo.getItemCode());
        demonstrateTaskInfo.setItemName(itemInfo.getItemName());
        demonstrateTaskInfo.setPackSize(itemInfo.getUomList().get(0).getConversionRate());
        demonstrateTaskInfo.setPieceConversionRate(itemInfo.getSpecification());
        demonstrateTaskInfo.setTaskId(StrUtil.uuid());
        if(demonstrateTaskInfo.getPackSize() != null){
            BigDecimal[] results = demonstrateTaskInfo.getQty().divideAndRemainder(demonstrateTaskInfo.getPackSize());
            demonstrateTaskInfo.setPiece(results[0]);
            demonstrateTaskInfo.setScattered(results[1]);
        }
        return demonstrateTaskInfo;
    }

    @Override
    public void demonstrateBack(DemonstrateTaskReqDto demonstrateTaskReqDto) throws Exception {
        ContainerInfoDetail containerInfoDetail = containerInfoDetailService.findByMap(MapUtils.put("containerSubNo",demonstrateTaskReqDto.getContainerSubNo()).getMap()).stream().findFirst().orElseThrow(()->new PrologException("容器详情信息未查询到"));
        ContainerInfo containerInfo = containerInfoService.findByMap(MapUtils.put("containerNo",containerInfoDetail.getContainerNo()).getMap()).stream().findFirst().orElseThrow(()->new PrologException("容器信息未查询到"));

        LocationCfg locationCfg = locationCfgService.findByMap(MapUtils.put("wmsAreaNo", containerInfo.getWarehouseArea()).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("回库点位未配置"));
        AssertUtils.isNotTrue(locationCfg == null,"库区未配置");
        if (containerInfo.getWarehouseArea().equals("AGVL")) {
            if (containerInfoDetail.getContainerNo().equals(containerInfoDetail.getContainerSubNo())) {
                locationCfg = locationCfgService.findByMap(MapUtils.put("wmsAreaNo", containerInfo.getWarehouseArea()).put("type",4).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("回库点位未配置"));
            } else {
                locationCfg = locationCfgService.findByMap(MapUtils.put("wmsAreaNo", containerInfo.getWarehouseArea()).put("type",3).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("回库点位未配置"));
            }
        }

        if (containerInfoDetail.getQty().compareTo(BigDecimal.ZERO) == 0 && StrUtil.equals(containerInfoDetail.getContainerNo(), containerInfoDetail.getContainerSubNo())) {
            //移库成空托并且是托盘 搬到碟盘机
            if (containerInfo.getWarehouseArea().equals(WmsConstants.MJZ)) {
                emptyContainerTaskService.save(containerInfo.getContainerNo(),LayerEnum.ONE,WmsCarryTaskInCode.MJZ);
            } else if (containerInfo.getWarehouseArea().equals(WmsConstants.AGVL)) {
                emptyContainerTaskService.save(containerInfo.getContainerNo(), LayerEnum.TWO, WmsCarryTaskInCode.AGVL);
            } else {
                emptyContainerTaskService.save(containerInfo.getContainerNo(), LayerEnum.TWO, WmsCarryTaskInCode.MJZ);
            }
        } else {
           if(containerInfoDetail.getQty().compareTo(BigDecimal.ZERO) == 0 && !StrUtil.equals(containerInfoDetail.getContainerNo(), containerInfoDetail.getContainerSubNo())){
               containerInfoDetailService.deleteById(containerInfoDetail.getId());
               List<ContainerInfoDetail> containerInfoDetailList = containerInfoDetailService.findByMap(MapUtils.put("containerNo", containerInfo.getContainerNo()).getMap());
               if (CollectionUtil.isEmpty(containerInfoDetailList)) {
                   containerInfoService.deleteById(containerInfo.getId());
               }
           }
            String targetArea = locationCfg.getAreaNo();
            if(containerInfo.getWarehouseArea().equals(WmsConstants.MJZ)){
                ContainerLocation containerLocation = plgFeignRouteService.seachLocationNo(MapUtils.put("containerNo", containerInfo.getContainerNo()).getMap());
                targetArea = bizInboundTaskService.findBestAreaByType(containerInfo.getContainerNo(),containerLocation.getCurrentArea(),containerInfoDetail.getItemId()+"@@"+containerInfoDetail.getLotId(),1);
            }
            //创建搬运任务
            plgFeignRouteService.createCarryTask(containerInfo.getContainerNo(), null, null, null, targetArea, null,
                    String.valueOf(BaseTaskTypeConstants.INBOUND_TYPE), 1, "演示出库回库",null);
        }

    }

    @Override
    public List<Map<String, Object>> wmsCarryTaskTargetList(Integer type) {
        switch (type) {
            case 1:
            case 2:
                List<Map<String, Object>> result = new ArrayList<>();
                result.addAll(WmsCarryTaskInCode.getRkList());
                result.addAll(WmsCarryTaskInCode.getJdList());
                return result;
            case 3:
                Criteria criteria = new Criteria(StationCfg.class);
                criteria.restrictionBuilder().in(StationCfg::getStationType, StationTypeEnum.wmsOutCarryCode()).build();
                List<Map<String, Object>> targetAreaList = stationCfgService.findByCriteria(criteria).stream().map(item -> {
                    return MapUtils.put("code", item.getAreaNo()).put("desc", item.getRemark()).getMap();
                }).collect(Collectors.toList());
                targetAreaList.addAll(Arrays.asList(MapUtils.put("code", "SX01-01").put("desc", "一楼四向库").getMap(),MapUtils.put("code","AGV01-01").put("desc","二楼agv整件托盘库").getMap(),MapUtils.put("code","AGVTP01").put("desc","拆零托盘库").getMap()
                        ,MapUtils.put("code","AGV02-01").put("desc","二楼agv整件食品库").getMap(),MapUtils.put("code","AGV03-01").put("desc","二楼agv整件器械库").getMap(),MapUtils.put("code","AGVHJ01").put("desc","拆零货架库").getMap()));
                return targetAreaList;
            case 4:
            case 6:
                break;
            case 5:
                LocationCfg targetLocation= locationCfgService.findByMap(MapUtils.put("type", LocationCfgConstants.JHQ).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("1F整托出库集货区未配置"));
                return Arrays.asList(MapUtils.put("code", targetLocation.getAreaNo()).put("desc", "一楼整托出库托盘出库区").getMap());
            default:
                throw new PrologException("错误的任务属性");
        }
        return ListUtil.empty();
    }

    @Override
    public ContainerStockRespDto findMoveContainer(String containerSubNo) throws Exception {
        List<ContainerInfoDetail> containerInfoDetails = containerInfoDetailService.findByMap(MapUtils.put("containerSubNo", containerSubNo).getMap());
        ContainerStockRespDto result =  new ContainerStockRespDto();
        if(CollectionUtil.isNotEmpty(containerInfoDetails)){
            ContainerInfoDetail containerInfoDetail = containerInfoDetails.get(0);

            List<String> itemIdsResp = containerInfoDetails.stream().map(ContainerInfoDetail::getItemId).collect(Collectors.toList());
            List<String> lotIdsResp = containerInfoDetails.stream().map(ContainerInfoDetail::getLotId).collect(Collectors.toList());
            List<ItemSyncVO> itemInfoList = feignGoodsService.queryItemMst(itemIdsResp);
            List<BatchNumberSync> batchNumberSync = inventoryService.getBatchNumberSync(lotIdsResp);

            ItemSyncVO itemSyncVO = itemInfoList.stream().filter(inner -> inner.getItemId().equals(containerInfoDetail.getItemId())).findFirst().orElseThrow(() -> new PrologException("为查询到商品信息"));
            BatchNumberSync numberSync = batchNumberSync.stream().filter(inner -> inner.getBatchId().equals(containerInfoDetail.getLotId())).findFirst().orElseThrow(() -> new PrologException("为查询到批次信息"));

            Criteria criteria = Criteria.forClass(ContainerTask.class);
            criteria.restrictionBuilder()
                    .eq(ContainerTask :: getContainerSubNo,containerSubNo)
                    .le(ContainerTask :: getStatus,2)
                    .build();
            List<ContainerTask> containerTasks = containerTaskService.findByCriteria(criteria);
            BigDecimal preQty = containerTasks.stream().map(ContainerTask::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);

            List<ContainerLocationVo> locationByContainerList = routeFeignService.findLocationByContainerList(Collections.singletonList(containerInfoDetail.getContainerNo()));

            result.setContainerNo(containerInfoDetail.getContainerNo());
            result.setSubContainerNo(containerInfoDetail.getContainerSubNo());
            result.setItemName(itemSyncVO.getItemName());
            result.setLotNo(numberSync.getManufacturerLotNum());
            result.setStockQty(containerInfoDetail.getQty());
            result.setPreQty(preQty);
            result.setItemId(containerInfoDetail.getItemId());
            result.setLotId(containerInfoDetail.getLotId());
            result.setPackId(containerInfoDetail.getPackId());
            result.setOwnerId(containerInfoDetail.getOwnerId());
            if(CollectionUtil.isNotEmpty(locationByContainerList)){
                result.setAreaNo(locationByContainerList.get(0).getAreaNo());
            }
        }
        return result;
    }

    @Override
    public List<WMSAreaRespDto> queryArea() throws Exception {
        List<SysParam> sysParamList = sysParamService.findAll();
        SysParam sysParam = sysParamList.stream().filter(item -> item.getParamNo().equals("WMS_AREA_NO")).findFirst().orElseThrow(() -> new PrologException("未配置WMS_AREA_NO参数"));
        String paramValue = sysParam.getParamValue();
        return JsonHelper.getObjectList(paramValue, WMSAreaRespDto.class);
    }

    @Override
    public void confirmMoveContainer(ConfirmMoveContainerReqDto req) throws Exception {
        Criteria c1 = Criteria.forClass(ContainerInfoDetail.class);
        c1.restrictionBuilder()
                .eq(ContainerTask :: getContainerSubNo,req.getContainerSubNo())
                .eq(ContainerTask :: getItemId,req.getItemId())
                .eq(ContainerTask :: getLotId,req.getLotId())
                .eq(ContainerTask :: getPackId,req.getPackId())
               .build();
        List<ContainerInfoDetail> containerInfoDetails = containerInfoDetailService.findByCriteria(c1);
        if(CollectionUtil.isEmpty(containerInfoDetails)){
            throw new BizException("未找到该容器库存信息");
        }
        ContainerInfoDetail containerInfoDetail = containerInfoDetails.get(0);
        if(containerInfoDetail.getQty().compareTo(req.getMoveQty())<0){
            throw new BizException("移库数量大于库存数量");
        }
        Criteria c2 = Criteria.forClass(ContainerTask.class);
        c2.restrictionBuilder()
                .eq(ContainerTask :: getContainerSubNo,req.getContainerSubNo())
                .eq(ContainerTask :: getItemId,req.getItemId())
                .eq(ContainerTask :: getLotId,req.getLotId())
                .eq(ContainerTask :: getPackId,req.getPackId())
                .le(ContainerTask :: getStatus,2)
                .build();
        List<ContainerTask> containerTasks = containerTaskService.findByCriteria(c2);
        if(CollectionUtil.isNotEmpty(containerTasks)){
            BigDecimal preQty = containerTasks.stream().map(ContainerTask::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
            if(containerInfoDetail.getQty().subtract(preQty).subtract(req.getMoveQty()).compareTo(BigDecimal.ZERO)<0){
                throw new BizException("库存数量-预占数量-移库数量小于0");
            }
        }
        // todo 调用wms接口

    }
}
