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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.codingapi.tx.annotation.TxTransaction;
import com.prolog.eis.common.util.location.LocationConstants;
import com.prolog.eis.constants.base.BaseConstant;
import com.prolog.eis.constants.base.BaseTaskTypeConstants;
import com.prolog.eis.constants.wms.WmsConstants;
import com.prolog.eis.core.dto.route.CarryTaskCallbackDto;
import com.prolog.eis.core.dto.route.ContainerLocationRespDto;
import com.prolog.eis.core.dto.route.CreateCarryTaskDto;
import com.prolog.eis.core.model.biz.carry.CarryTask;
import com.prolog.eis.core.model.biz.carry.CarryTaskAngle;
import com.prolog.eis.core.model.biz.carry.CarryTaskCallback;
import com.prolog.eis.dao.shelves.PalletInfoMapper;
import com.prolog.eis.dao.shelves.area.CategoryAreaNoMapper;
import com.prolog.eis.dao.shelves.sys.SysParamMapper;
import com.prolog.eis.feign.PlgFeignRouteClient;
import com.prolog.eis.model.shelves.CategoryAreaNo;
import com.prolog.eis.model.shelves.PalletInfo;
import com.prolog.eis.model.sys.SysParam;
import com.prolog.eis.service.shelves.PalletMoveExecuteService;
import com.prolog.eis.utils.AngleConversionAB;
import com.prolog.eis.utils.MapUtils;
import com.prolog.eis.utils.PrimaryAgvGeneraterUtils;
import com.prolog.framework.common.message.RestMessage;
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.core.restriction.Restrictions;
import com.prolog.fx.inf.core.InterfaceType;
import com.prolog.fx.inf.core.annotation.InterfaceMethod;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author ：cb
 * @date ：Created in 2022/6/16 15:25
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PalletMoveExecuteServiceImpl implements PalletMoveExecuteService {

    private final PalletInfoMapper palletInfoMapper;

    @Value("${cfg.isUseAngle:}")
    private String isUseAngle;
    @Resource
    private PlgFeignRouteClient routeFeignService;

    @Resource
    CategoryAreaNoMapper categoryAreaNoMapper;

    @Resource
    SysParamMapper sysParamMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    @InterfaceMethod(key = "palletArriveIng", name = "货架去往站台", type = InterfaceType.Send)
    public Boolean palletArriveIng(String palletNo, String areaNo, String targetAreaNo, String targetPlane,
                                   int stationDir, int taskType) {
        Criteria criteria = Criteria.forClass(PalletInfo.class);
        criteria.setRestriction(
                Restrictions.and(
                        Restrictions.eq(PalletInfo::getPalletNo, palletNo),
                        Restrictions.eq(PalletInfo::getStatus, BaseConstant.NO)));
        String taskId = PrimaryAgvGeneraterUtils.getInstance().generaterNextNumber();
        // 调用下发搬运任务的接口（带角度）
        int palletDir = AngleConversionAB.getDirectionStr(targetPlane, stationDir);
        long l = palletInfoMapper.updateMapByCriteria(
                MapUtils.put(PalletInfo::getStatus, BaseConstant.YES)
                        .put(PalletInfo::getSubArea, targetAreaNo)
                        .put(PalletInfo::getContainerMoveTaskId, taskId)
                        .put(PalletInfo::getAngle, palletDir)
                        .put(PalletInfo::getUpdateTime, LocalDateTime.now()).getMap(),
                criteria);
        if (l > 0) {
            // 生成搬运任务
            // 任务类型后续统一定
            // 调用下发搬运任务的接口（带角度）
            CreateCarryTaskDto carryTask = this.createCarryTaskWithAngle(taskId, palletNo, areaNo, null, targetAreaNo,
                    null, BaseTaskTypeConstants.HJ_TYPE, "货架去往站台", String.valueOf(BaseTaskTypeConstants.HJ_TYPE), palletDir, LocationConstants.PATH_TASK_TYPE_CARRY, 80, targetPlane);

            // wait code
            // 先调用现有流程
            log.info("调用创建路径任务 开始");
            log.info("调用创建路径任务 入参：" + JSONObject.toJSONString(carryTask));
            RestMessage<String> restMessage = routeFeignService.createTaskWithAngle(carryTask);
            if (!restMessage.isSuccess()) {
                throw new BizException("路径服务报错:" + restMessage.getMessage());
            }
            log.info("调用创建路径任务 结束");

            if (restMessage.isSuccess()) {
                return true;
            } else {
                throw new BizException("路径服务报错:" + restMessage.getMessage());
            }
        } else {
            throw new BizException(String.format("货架%s状态修改失败:", palletNo));
        }
    }

    @Override
    @InterfaceMethod(key = "palletLeaveIng", name = "货架离开站台回库", type = InterfaceType.Send)
    public Boolean palletLeaveIng(String palletNo, String areaNo, int taskType, String itemHealthCategory) {
        Criteria criteria = Criteria.forClass(PalletInfo.class);
        criteria.setRestriction(
                Restrictions.and(Restrictions.eq("palletNo", palletNo), Restrictions.eq("status", BaseConstant.NO)));
        String taskId = PrimaryAgvGeneraterUtils.getInstance().generaterNextNumber();
        // 生成搬运任务
        String targetSubAreaNo = null;
        List<CategoryAreaNo> healthCategory = categoryAreaNoMapper.findByMap(com.prolog.framework.utils.MapUtils.put("itemHealthCategory", itemHealthCategory).getMap(), CategoryAreaNo.class);
        if (!healthCategory.isEmpty() && !Objects.isNull(healthCategory.get(0).getAreaNo())) {
            targetSubAreaNo = healthCategory.get(0).getAreaNo();
        } else {
            targetSubAreaNo = sysParamMapper.findByMap(com.prolog.framework.utils.MapUtils.put("paramNo", WmsConstants.DEFAULT_SUB_AREA_NO).getMap(), SysParam.class)
                    .stream().findFirst().orElse(new SysParam()).getParamValue();
        }

        if (Objects.isNull(targetSubAreaNo)) {
            throw new BizException(String.format("商品大类%s子区域为空", itemHealthCategory));
        }

        String targetAreaNo = sysParamMapper.findByMap(com.prolog.framework.utils.MapUtils.put("paramNo", WmsConstants.DEFAULT_AREA_NO).getMap(), SysParam.class)
                .stream().findFirst().orElse(new SysParam()).getParamValue();

        if (Objects.isNull(targetAreaNo)) {
            throw new BizException(String.format("货位存储区为空"));
        }
        long l = palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils.put("status", BaseConstant.YES)
                .put("containerMoveTaskId", taskId).put("subArea", targetSubAreaNo).getMap(), criteria);
        log.info("货架回库修改货架信息是否成功:" + l);
        if (l > 0) {
            CreateCarryTaskDto carryTask = this.createCarryTask(taskId, palletNo, areaNo, null, targetSubAreaNo, null, taskType,
                    "货架回库", "", targetAreaNo);

            // 先调用现有流程
            RestMessage<String> restMessage = routeFeignService.createTaskWithAngle(carryTask);
            if (!restMessage.isSuccess()) {
                throw new BizException("路径服务报错:" + restMessage.getMessage());
            }
            log.info("调用创建路径任务 结束");
            if (restMessage.isSuccess()) {
                return true;
            } else {
                throw new BizException("路径服务报错:" + restMessage.getMessage());
            }
        } else {
            throw new BizException(String.format("货架%s状态修改失败:", palletNo));
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    @InterfaceMethod(key = "palletRotate", name = "AGV上架货位调整货架旋转", type = InterfaceType.Send)
    public Boolean palletRotate(String palletNo, String areaNo, String targetPlane, int stationDir) {
        Criteria criteria = Criteria.forClass(PalletInfo.class);
        criteria.setRestriction(
                Restrictions.and(Restrictions.eq("palletNo", palletNo)));
        String taskId = PrimaryAgvGeneraterUtils.getInstance().generaterNextNumber();
        // 调用下发搬运任务的接口（带角度）
        int palletDir = AngleConversionAB.getDirectionStr(targetPlane, stationDir);
        long l = palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils.put("status", BaseConstant.YES).put("subArea", areaNo)
                .put("containerMoveTaskId", taskId).put("angle", palletDir).getMap(), criteria);
        if (l > 0) {
            // 生成搬运任务
            // 任务类型后续统一定
            // 调用下发搬运任务的接口（带角度并执行）
            RestMessage<String> restMessage1 = routeFeignService.findContainerLocation(JSON.toJSONString(com.prolog.framework.utils.MapUtils.put("containerNo", palletNo).getMap()));
            if (!restMessage1.isSuccess()) {
                throw new PrologException("托盘点位查询发生异常！");
            }
            String data = restMessage1.getData();
            ContainerLocationRespDto containerLocationRespDto = JSONObject.parseObject(data, ContainerLocationRespDto.class);

            CreateCarryTaskDto carryTask = this.createCarryTaskWithAngle(taskId, palletNo, areaNo, containerLocationRespDto.getLocationNo(), areaNo, containerLocationRespDto.getLocationNo(),
                    LocationConstants.PATH_TASK_TYPE_SPIN_AROUND, "货架原地旋转", "货架原地旋转", palletDir,
                    LocationConstants.PATH_TASK_TYPE_SPIN_AROUND, 99, targetPlane);

            // wait code
            // 先调用现有流程
           /* log.info("调用创建路径任务 开始");
            if (sysModeUtil.getMode().equals(sysModeUtil.INTERFACE_TEST)) {
                return true;
            }*/
            RestMessage<String> restMessage = routeFeignService.creatCarryTaskWithAngleAndExecute(carryTask);
            if (!restMessage.isSuccess()) {
                throw new BizException("路径服务报错:" + restMessage.getMessage());
            }
            log.info("调用创建路径任务 结束");

            if (restMessage.isSuccess()) {
                return true;
            } else {
                throw new BizException("路径服务报错:" + restMessage.getMessage());
            }
        } else {
            throw new BizException(String.format("货架%s状态修改失败:", palletNo));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    @InterfaceMethod(key = "carryTaskCallBack", name = "拆零区货架到位回告", type = InterfaceType.Receive)
    public void palletMoveComplete(CarryTaskCallbackDto carryTask) {

        Criteria criteria = Criteria.forClass(PalletInfo.class);
        criteria.setRestriction(Restrictions.eq("palletNo", carryTask.getPalletNo()));
        palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils.put("status", BaseConstant.NO).put("containerMoveTaskId", null)
                .put("updateTime", new Date()).getMap(), criteria);
        this.carryTaskExecute(carryTask.getId());
    }

    private void carryTaskExecute(String carryTaskId) {

        // 搬运任务转历史
        CarryTaskCallback carryTaskCallback = new CarryTaskCallback();
        carryTaskCallback.setId(carryTaskId);
        log.info("开始 请求搬运任务转历史");
        RestMessage<String> restMessage = routeFeignService.toCallbackHis(carryTaskCallback);
        if (!restMessage.isSuccess()) {
            throw new BizException("搬运任务转历史失败：" + restMessage.getMessage());
        }
        log.info("完成 请求搬运任务转历史");
    }

    private CreateCarryTaskDto createCarryTaskWithAngle(String taskId, String palletNo, String sourceArea,
                                                        String sourceLocation, String targetArea, String targetLocation, int businessType, String remark,
                                                        String businessProperty, Integer angle, int taskType, int priority, String planes) {
        CreateCarryTaskDto createCarryTaskDto = new CreateCarryTaskDto();
        CarryTask carryTask = new CarryTask();
        carryTask.setId(taskId);
        carryTask.setContainerNo(palletNo);
        carryTask.setPalletNo(palletNo);
        carryTask.setTaskType(taskType);
        carryTask.setStartRegion(sourceArea);
        carryTask.setStartLocation(sourceLocation);
        carryTask.setEndRegion(targetArea);
        carryTask.setEndLocation(targetLocation);
        carryTask.setTaskStatus(0);
        carryTask.setPriority(priority);
        carryTask.setBusinessType(String.valueOf(businessType));
        carryTask.setBusinessDescribe(remark);
        carryTask.setBusinessProperty(businessProperty);
        carryTask.setCreateTime(new Date());
        carryTask.setTaskRemark(remark);
        carryTask.setExtend1(planes);
        carryTask.setExtend2(isUseAngle);

        createCarryTaskDto.setCarryTask(carryTask);
        List<CarryTaskAngle> angleList = new ArrayList<>();
        CarryTaskAngle carryTaskAngle = new CarryTaskAngle();
        carryTaskAngle.setAngle(angle);
        carryTaskAngle.setAreaNo(targetArea);
        carryTaskAngle.setCarryTaskId(taskId);
        angleList.add(carryTaskAngle);

        createCarryTaskDto.setAngleList(angleList);

        return createCarryTaskDto;
    }

    private CreateCarryTaskDto createCarryTask(String taskId, String palletNo, String sourceArea, String sourceLocation,
                                               String targetArea, String targetLocation, int taskType, String remark, String businessProperty,
                                               String subAreaNo) {
        CreateCarryTaskDto createCarryTaskDto = new CreateCarryTaskDto();
        CarryTask carryTask = new CarryTask();
        carryTask.setId(taskId);
        carryTask.setContainerNo(palletNo);
        carryTask.setPalletNo(palletNo);
        carryTask.setTaskType(LocationConstants.PATH_TASK_TYPE_CARRY);
        carryTask.setStartRegion(sourceArea);
        carryTask.setStartLocation(sourceLocation);
        carryTask.setEndRegion(targetArea);
        carryTask.setEndLocation(targetLocation);
        carryTask.setTaskStatus(0);
        carryTask.setPriority(80);
        carryTask.setSubAreaNo(subAreaNo);
        carryTask.setBusinessType(String.valueOf(taskType));
        carryTask.setBusinessDescribe(remark);
        carryTask.setBusinessProperty(businessProperty);
        carryTask.setCreateTime(new Date());
        carryTask.setTaskRemark(remark);
        createCarryTaskDto.setCarryTask(carryTask);
        List<CarryTaskAngle> angleList = new ArrayList<>();
        CarryTaskAngle carryTaskAngle = new CarryTaskAngle();
        carryTaskAngle.setAngle(90);
        carryTaskAngle.setAreaNo(targetArea);
        carryTaskAngle.setCarryTaskId(taskId);
        angleList.add(carryTaskAngle);

        createCarryTaskDto.setAngleList(angleList);
        return createCarryTaskDto;
    }

}