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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.codingapi.tx.annotation.TxTransaction;
import com.prolog.eis.constants.base.BaseTaskTypeConstants;
import com.prolog.eis.constants.base.ContainerTaskStatusConstants;
import com.prolog.eis.constants.wms.WmsConstants;
import com.prolog.eis.core.dto.route.CarryTaskCallbackDto;
import com.prolog.eis.dao.carry.WmsCarryTaskHisMapper;
import com.prolog.eis.dao.carry.WmsCarryTaskMapper;
import com.prolog.eis.dto.inbound.WmsCarryTaskBackReqDto;
import com.prolog.eis.dto.inbound.WmsCarryTaskDto;
import com.prolog.eis.enums.base.BaseStatusEnum;
import com.prolog.eis.enums.wms.WmsCarryTaskInCode;
import com.prolog.eis.model.carry.WmsCarryTask;
import com.prolog.eis.model.carry.WmsCarryTaskHis;
import com.prolog.eis.model.container.LocationCfg;
import com.prolog.eis.model.container.StationCfg;
import com.prolog.eis.model.inbound.BizInboundTask;
import com.prolog.eis.service.carry.WmsCarryTaskService;
import com.prolog.eis.service.container.LocationCfgService;
import com.prolog.eis.service.container.StationCfgService;
import com.prolog.eis.service.feign.RouteFeignService;
import com.prolog.eis.service.inbound.impl.BizInboundTaskServiceImpl;
import com.prolog.eis.service.wms.WmsCarryTaskBackService;
import com.prolog.framework.common.message.RestMessage;
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.fx.inf.core.Exception.RetryException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author zmr
 * @description: wms下发搬运任务-服务实现类
 * @date 2023-04-23 17:30
 */
@Service
@Slf4j
public class WmsCarryTaskServiceImpl implements WmsCarryTaskService {

    @Autowired
    private WmsCarryTaskMapper wmsCarryTaskMapper;
    @Autowired
    private WmsCarryTaskHisMapper wmsCarryTaskHisMapper;
    @Autowired
    private WmsCarryTaskBackService wmsCarryTaskBackService;
    @Autowired
    private LocationCfgService locationCfgService;
    @Autowired
    private RouteFeignService plgFeignRouteService;
    @Autowired
    private StationCfgService stationCfgService;
    @Autowired
    private BizInboundTaskServiceImpl bizInboundTaskService;
    /**
     * 新增数据
     *
     * @param wmsCarryTask wms下发搬运任务
     */
    @Override
    public long save(WmsCarryTask wmsCarryTask) {
        return wmsCarryTaskMapper.save(wmsCarryTask);
    }

    /**
     * 新增批量数据
     *
     * @param wmsCarryTaskList wms下发搬运任务
     */
    @Override
    public long saveBatch(List<WmsCarryTask> wmsCarryTaskList) {
        return wmsCarryTaskMapper.saveBatch(wmsCarryTaskList);
    }

    /**
     * 查询多条数据
     *
     * @param paramMap 查询起始位置
     * @return 对象列表
     */
    @Override
    public List<WmsCarryTask> findByMap(Map<String, Object> paramMap) {
        return wmsCarryTaskMapper.findByMap(paramMap, WmsCarryTask.class);
    }

    /**
     * 查询单条数据
     *
     * @param paramMap 查询起始位置
     * @return 对象
     */
    @Override
    public WmsCarryTask findOneByMap(Map<String, Object> paramMap) {
        List<WmsCarryTask> dataList = findByMap(paramMap);
        if(dataList.isEmpty()) {
            return null;
        }
        return dataList.get(0);
    }

    /**
     * 查询多条数据
     *
     * @param criteria 查询起始位置
     * @return 对象列表
     */
    @Override
    public List<WmsCarryTask> findByCriteria(Criteria criteria) {
        return wmsCarryTaskMapper.findByCriteria(criteria);
    }

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public WmsCarryTask findById(int id) {
        return wmsCarryTaskMapper.findById(id, WmsCarryTask.class);
    }

    /**
     * 修改数据
     *
     * @param wmsCarryTask 实例对象
     */
    @Override
    public long update(WmsCarryTask wmsCarryTask) {
        return wmsCarryTaskMapper.update(wmsCarryTask);
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     */
    @Override
    public long deleteById(int id) {
        return wmsCarryTaskMapper.deleteById(id, WmsCarryTask.class);
    }

    /**
     * 通过参数删除数据
     *
     * @param paramMap 参数
     */
    @Override
    public long deleteByMap(Map<String, Object> paramMap) {
        return wmsCarryTaskMapper.deleteByMap(paramMap, WmsCarryTask.class);
    }

    /**
     * 通过参数查询总条数
     *
     * @param paramMap 参数
     */
    @Override
    public long findCountByMap(Map<String, Object> paramMap) {
        return wmsCarryTaskMapper.findCountByMap(paramMap, WmsCarryTask.class);
    }

    @Override
    public void doJdTaskCallBack(CarryTaskCallbackDto carryTaskCallbackDto) {
        WmsCarryTask wmsCarryTask = this.findByMap(MapUtils.put("containerNo", carryTaskCallbackDto.getContainerNo()).getMap()).stream().findFirst().orElseThrow(() -> new PrologException(String.format("借道任务到位回告未找到容器%s的借道任务", carryTaskCallbackDto.getContainerNo())));
        wmsCarryTask.setUpdateTime(new Date());
        wmsCarryTask.setStatus(BaseStatusEnum.STATUS_FINISH.getCode());
        this.update(wmsCarryTask);
    }

    @Override
    public void wmsTaskCbWms() throws Exception{
        List<WmsCarryTask> wmsCarryTaskList = this.findByMap(MapUtils.put("status", BaseStatusEnum.STATUS_FINISH.getCode()).getMap());
        if (CollectionUtil.isEmpty(wmsCarryTaskList)) {
            return;
        }
        for (WmsCarryTask carryTask : wmsCarryTaskList) {
            wmsCarryTaskCallBack(carryTask);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void wmsCarryTaskCallBack(WmsCarryTask carryTask)throws Exception {

        //转历史
        carryTask.setStatus(BaseStatusEnum.CALLBACK_FINISH.getCode());
        carryTask.setUpdateTime(new Date());
        this.update(carryTask);
        WmsCarryTaskHis carryTaskHis = new WmsCarryTaskHis();
        BeanUtils.copyProperties(carryTask, carryTaskHis);
        wmsCarryTaskHisMapper.save(carryTaskHis);
        this.deleteById(carryTask.getId());

        if (StrUtil.equals(carryTask.getWmsLocationCode(), WmsCarryTaskInCode.ZJK01.getCode()) && StrUtil.equals(carryTask.getTaskType(), WmsConstants.WMS_CARRY_TASK_TYPE_OUT)) {
            return;
        }
        try {
            //回告wms
            WmsCarryTaskBackReqDto wmsCarryTaskBackReqDto = new WmsCarryTaskBackReqDto();
            wmsCarryTaskBackReqDto.setWarehouseId(carryTask.getWarehouseId());
            wmsCarryTaskBackReqDto.setEnterpriseId(carryTask.getEnterpriseId());
            wmsCarryTaskBackReqDto.setTaskId(carryTask.getTaskId());
            wmsCarryTaskBackReqDto.setMsgId(carryTask.getMsgId());
            wmsCarryTaskBackReqDto.setContainerNo(carryTask.getContainerNo());
            RestMessage wmsResult =  wmsCarryTaskBackService.execute(wmsCarryTaskBackReqDto);;
            log.info("入库完成回告wms" + wmsResult);
        } catch (RetryException e) {
            log.warn("入库完成回告wms失败，进入重试：" + e.getMessage());
        }
    }

    //借道任务搬运
    @Override
    public void wmsCarryTask() throws Exception{
        Criteria criteria = new Criteria(WmsCarryTask.class);
        criteria.restrictionBuilder().eq(WmsCarryTask::getTaskType, WmsConstants.WMS_CARRY_TASK_TYPE_IN).eq(WmsCarryTask::getStatus, ContainerTaskStatusConstants.INIT_STATUS).isNotNull(WmsCarryTask::getOriginalLocation).build();
        List<WmsCarryTask> wmsCarryTaskList = this.findByCriteria(criteria);
        if (CollectionUtil.isEmpty(wmsCarryTaskList)) {
            return;
        }
        for (WmsCarryTask wmsCarryTask : wmsCarryTaskList) {
            wmsCarryTask(wmsCarryTask);
        }
    }
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    public void wmsCarryTask(WmsCarryTask wmsCarryTask) throws Exception{
        final WmsCarryTaskInCode targetCode = WmsCarryTaskInCode.of(wmsCarryTask.getTargetArea());
        switch (targetCode) {
            case ZJK01:
                //地堆库 发送到四项库bcr口
                carryToDDTask(wmsCarryTask);
                break;
            default:
                //二楼 中药饮片库区，物料库区，不合格库区 统一处理
                carryToTwoLayerTask(wmsCarryTask);
        }
    }

    //二楼 中药饮片库区，物料库区，不合格库区 统一处理
    private void carryToTwoLayerTask(WmsCarryTask wmsCarryTask) throws Exception {
        //1 查询站台
        StationCfg stationCfg = stationCfgService.findByMap(MapUtils.put("wmsAreaNo", wmsCarryTask.getTargetArea()).put("isLock", 0).getMap()).stream().findFirst().orElse(null);
        if (Objects.isNull(stationCfg)) {
            log.warn("托盘{}入库任务发送失败 无空闲站台", wmsCarryTask.getContainerNo());
            return;
        }
        //2 校验站台是否空闲
        if (!plgFeignRouteService.checkAreaIn(stationCfg.getAreaNo())) {
            log.warn("托盘{}入库任务发送失败 无空闲站台", wmsCarryTask.getContainerNo());
            return;
        }
        //3 修改入库单状态为已开始
        wmsCarryTask.setStatus(BaseStatusEnum.STATUS_STARTED.getCode());
        wmsCarryTask.setUpdateTime(new Date());
        wmsCarryTaskMapper.update(wmsCarryTask);
        //4创建点位
        plgFeignRouteService.createItemContainer(wmsCarryTask.getOriginalLocation(), wmsCarryTask.getContainerNo(), "0", "0");
        //4 发送搬运
        plgFeignRouteService.createCarryTask(wmsCarryTask.getContainerNo(), null, wmsCarryTask.getOriginalArea(), wmsCarryTask.getOriginalLocation(), stationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.JD_TASK_TYPE), 1, "agv搬运到入库站台", null);
    }

    //地堆库入库
    private void carryToDDTask(WmsCarryTask wmsCarryTask)throws Exception {
        //1 查询四向库所有空闲并且入库方向的bcr
        LocationCfg locationCfg = locationCfgService.getLocationCfgOccupy(wmsCarryTask.getContainerNo());
        if (Objects.isNull(locationCfg)) {
            log.warn("托盘{}入库任务发送失败 无空闲bcr", wmsCarryTask.getContainerNo());
            return;
        }
        //2 修改入库单状态为已开始
        wmsCarryTask.setStatus(BaseStatusEnum.STATUS_STARTED.getCode());
        wmsCarryTask.setUpdateTime(new Date());
        wmsCarryTaskMapper.update(wmsCarryTask);
        //3 创建点位
        plgFeignRouteService.createItemContainer(wmsCarryTask.getOriginalLocation(), wmsCarryTask.getContainerNo(), "0", "0");
        //4 发送搬运
        plgFeignRouteService.createCarryTask(wmsCarryTask.getContainerNo(), null, wmsCarryTask.getOriginalArea(), wmsCarryTask.getOriginalLocation(), locationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.MOVE_TYPE), 1, "搬运到bcr口", null);
    }

    @Override
    public void saveCarryTask(List<WmsCarryTaskDto> req) {
        List<WmsCarryTask> insertList = new ArrayList<>();
        for (WmsCarryTaskDto wmsCarryTaskDto : req) {
            List<WmsCarryTask> wmsCarryTaskList = this.findByMap(MapUtils.put("containerNo", wmsCarryTaskDto.getContainerNo()).getMap());
            AssertUtils.isNotTrue(CollectionUtil.isNotEmpty(wmsCarryTaskList), String.format("容器%s任务已存在", wmsCarryTaskDto.getContainerNo()));
            List<BizInboundTask> inboundTaskList = bizInboundTaskService.findByMap(MapUtils.put("containerNo", wmsCarryTaskDto.getContainerNo()).getMap());
            if (CollectionUtil.isNotEmpty(inboundTaskList)) {
                throw new PrologException("载具【" + wmsCarryTaskDto.getContainerNo() + "】已经存在入库任务");
            }
            if (wmsCarryTaskDto.getWorkType().equals(WmsConstants.WMS_CARRY_WORK_TYPE_OUT + "") && !wmsCarryTaskDto.getWmsLocationCode().equals(WmsCarryTaskInCode.ZJK01.getCode())) {
                throw new PrologException("借道出库只支持地堆库区");
            }
            WmsCarryTask wmsCarryTask = new WmsCarryTask();
            BeanUtils.copyProperties(wmsCarryTaskDto, wmsCarryTask);
            wmsCarryTask.setTaskType(wmsCarryTaskDto.getWorkType().equals(WmsConstants.WMS_CARRY_WORK_TYPE_IN + "") ? WmsConstants.WMS_CARRY_TASK_TYPE_IN : WmsConstants.WMS_CARRY_TASK_TYPE_OUT);
            wmsCarryTask.setCreateTime(new Date());
            wmsCarryTask.setPriority(10);
            wmsCarryTask.setOriginalLocation(null);
            wmsCarryTask.setStatus(ContainerTaskStatusConstants.INIT_STATUS);
            insertList.add(wmsCarryTask);
        }
        if (!insertList.isEmpty()) {
            this.saveBatch(insertList);
        }
    }
}
