package com.huaheng.api.acs.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaheng.api.acs.domain.AgvPort;
import com.huaheng.api.acs.domain.AgvTask;
import com.huaheng.api.acs.domain.ToAgvTask;
import com.huaheng.api.acs.mapper.AgvTaskCsMapper;
import com.huaheng.common.constant.QuantityConstant;
import com.huaheng.common.exception.service.ServiceException;
import com.huaheng.common.utils.StringUtils;
import com.huaheng.common.utils.http.HttpUtils;
import com.huaheng.common.utils.security.ShiroUtils;
import com.huaheng.framework.web.domain.AjaxResult;
import com.huaheng.framework.web.service.ConfigService;
import com.huaheng.pc.config.address.service.AddressService;
import com.huaheng.pc.config.container.domain.Container;
import com.huaheng.pc.config.container.service.ContainerService;
import com.huaheng.pc.task.taskHeader.domain.TaskHeader;
import com.huaheng.pc.task.taskHeader.service.TaskHeaderService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
public class AgvTaskServiceImpl extends ServiceImpl<AgvTaskCsMapper, AgvTask> implements AgvTaskService {
    @Resource
    private AgvPortService agvPortService;
    @Resource
    private ContainerService containerService;
    @Resource
    private ConfigService configService;
    @Resource
    private AddressService addressService;
    @Resource
    private TaskHeaderService taskHeaderService;

    @Override
    public AjaxResult createAGVTask(AgvTask agvTask) {
        if (StringUtils.isEmpty(agvTask.getPreTaskNo())) {
            //校验请求参数
            checkAgvTaskPosition(agvTask);
            //校验托盘是否存在任务及是否锁定
            checkContainerAndPositionStatus(agvTask);
            //校验自己生成的任务中源点位的托盘和实际托盘一不一致
            checkContainerAndPositionLove(agvTask);
        }
        agvTask.setStatus(QuantityConstant.TASK_STATUS_BUILD);
        agvTask.setCreatedBy(ShiroUtils.getLoginName());
        agvTask.setTaskType(QuantityConstant.STATUS_TASK_CARRY);
        agvTask.setCreatedTime(new Date());
        agvTask.setUpdated(new Date());
        agvTask.setUpdatedBy(ShiroUtils.getLoginName());
        agvTask.setWarehouseCode("CS0001");
        if (save(agvTask)) {
            agvPortService.updateStatus(agvTask.getToPort(), QuantityConstant.STATUS_POSITION_LOCK);
        } else {
            throw new ServiceException("AGV创建任务失败");
        }
        return AjaxResult.success("执行生成任务成功");
    }

    @Override
    @Transactional
    public AjaxResult sendTaskToAGV(Integer[] agvTaskIds) {
        AjaxResult result = null;
        boolean finished = false;
        AgvTask task = null;
        for (Integer taskId : agvTaskIds) {
            task = getById(taskId);

            if (task.getStatus() >= QuantityConstant.TASK_STATUS_RELEASE) {
                result = AjaxResult.error("任务" + taskId + "已经下发,请不要重复下发,操作中止");
                finished = true;
                break;
            }
            if (StringUtils.isEmpty(task.getToPort())) {
                result = AjaxResult.error("任务没有目标点位,不允许下发");
                finished = true;
                break;
            }
            LambdaQueryWrapper<AgvTask> agvTaskLambdaQueryWrapper = new LambdaQueryWrapper();
            agvTaskLambdaQueryWrapper.eq(AgvTask::getToPort, task.getToPort())
                    .eq(AgvTask::getWarehouseCode, task.getWarehouseCode())
                    .ge(AgvTask::getStatus, QuantityConstant.TASK_STATUS_RELEASE)
                    .lt(AgvTask::getStatus, QuantityConstant.TASK_STATUS_COMPLETED);
            List<AgvTask> list = list(agvTaskLambdaQueryWrapper);
            if (list != null && list.size() > 0) {
                result = AjaxResult.error("目标点位存在任务,请更换目标点位");
                finished = true;
                break;
            }
            // 给AGV传递任务
            AjaxResult ajaxResult = agvTaskAssign(task);
            if (ajaxResult != null && ajaxResult.hasErr()) {
                result = AjaxResult.error(ajaxResult.getMsg());
                finished = true;
                break;
            }
            //修改任务头表
            task.setId(taskId);
            task.setStatus(QuantityConstant.TASK_STATUS_RELEASE);
            task.setUpdated(new Date());
            task.setUpdatedBy(ShiroUtils.getLoginName());
            saveOrUpdate(task);
        }
        if (!finished) {
            result = AjaxResult.success("执行下发任务成功", task);
        }else {
            throw new RuntimeException("下发失败");
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public AjaxResult agvTaskAssign(AgvTask agvTask) {
        //1、判断agvHeader是否为空
        if (agvTask == null) {
            return AjaxResult.error("Agv任务为空");
        }
        //2、判断必填字段是否满足
        if (agvTask.getId() == null) {
            return AjaxResult.error("Agv任务号Id为空");
        }
        if (agvTask.getTaskType() == null) {
            return AjaxResult.error("Agv任务类型为空");
        }
        String containerCode = agvTask.getContainerCode();
        if (StringUtils.isEmpty(containerCode)) {
            return AjaxResult.error("Agv任务中容器为空");
        }
        String warehouseCode = agvTask.getWarehouseCode();
        //3、转换实体,初始化Agv任务实体
        ToAgvTask toAgvTask = new ToAgvTask();
        toAgvTask.setTaskNo(String.valueOf(agvTask.getId()));
        toAgvTask.setTaskType(agvTask.getTaskType());
        toAgvTask.setContainerCode(agvTask.getContainerCode());
        toAgvTask.setFromPort(agvTask.getFromPort());
        toAgvTask.setToPort(agvTask.getToPort());
        toAgvTask.setPriority(100);
        //4、发送数据
        return sendDataToAgv(1, warehouseCode, "1", toAgvTask);
    }

    @Override
    public AjaxResult cancelAGVTask(Integer[] agvTaskIds) {
        for (int taskId : agvTaskIds) {
            AgvTask agvTask = getById(taskId);
            if (agvTask == null) {
                return AjaxResult.error("任务" + taskId + "未找到,操作中止");
            }
            if (agvTask.getStatus() > QuantityConstant.TASK_STATUS_RELEASE) {
                return AjaxResult.error("存在任务" + agvTask.getId() + "已下发或执行,操作中止");
            }
            int preTaskNo = taskId;
            LambdaQueryWrapper<AgvTask> agvLambdaQueryWrapper = Wrappers.lambdaQuery();
            agvLambdaQueryWrapper.eq(AgvTask::getPreTaskNo, preTaskNo);
            AgvTask agvTaskHeader = getOne(agvLambdaQueryWrapper);
            if (agvTaskHeader != null) {
                return AjaxResult.error("取消任务失败, 有前置任务" + agvTask.getId());
            }
            //查出任务明细
            //删除子任务
            //删除主任务
            removeById(taskId);
            //盘点取消任务,恢复明细状态为1
            int taskType = agvTask.getTaskType().intValue();
            cancelPositionStatus(agvTask);
            cancelContainerStatus(agvTask);
        }
        return AjaxResult.success("取消任务成功!");
    }

    @Override
    public AjaxResult cancelTask(Integer id, String warehouseCode, String area) {
        //1、判断参数是否为空
        if (id == null) {
            throw new ServiceException("任务号为空");
        }
        HashMap<String, Object> map = new HashMap();
        List<Integer> list = new ArrayList<>();
        list.add(id);
        map.put("taskNo", list);
        //2、发送数据
        return sendDataToAgv(2, warehouseCode, area, map);
    }

    @Override
    public AjaxResult notifyAGVTask(Map map) {
        AgvTask agvTask = new AgvTask();
        if (map.isEmpty()) {
            return AjaxResult.error("请求数据为空");
        }
        Object o1 = map.get("taskNo");
        Object o2 = map.get("carNo");
        Object o3 = map.get("status");
        if (StringUtils.isNull(o1)) {
            return AjaxResult.error("任务号为空");
        }
        Integer taskNo = Integer.valueOf(o1.toString());
        List<AgvTask> list = list(new LambdaQueryWrapper<AgvTask>().eq(AgvTask::getId, taskNo));
        if (CollectionUtils.isNotEmpty(list)) {
            AgvTask agvTask1 = list.get(0);
            if (agvTask1.getStatus().equals(100)) {
                return AjaxResult.success("任务已经是完成了的");
            }
        } else {
            return AjaxResult.success("任务不存在");
        }
        if (StringUtils.isNotNull(o2)) {
            String carNo = o2.toString();
            agvTask.setCarNo(carNo);
        }
        if (StringUtils.isNull(o3)) {
            return AjaxResult.error("任务状态为空");
        }
        Integer status = Integer.valueOf(o3.toString());
        agvTask.setId(taskNo);
        agvTaskStatusNowStart(status, agvTask);
        return AjaxResult.success();
    }

    /**
     * 将参数传输给AGV
     *
     * @param
     * @param warehouseCode
     * @param area
     * @param object
     * @return
     */
    private AjaxResult sendDataToAgv(int i, String warehouseCode, String area, Object object) {
        String value = configService.getKey(QuantityConstant.RULE_CONNECT_AGV);
        int connectAGV = Integer.parseInt(value);
        String url = null;
        if (connectAGV == QuantityConstant.RULE_AGV_CONNECT) {
            if (i == 1) {
                url = addressService.selectAddress(QuantityConstant.ADDRESS_AGV_TASK_ASSIGN, warehouseCode, area);
            } else if (i == 2) {
                url = addressService.selectAddress(QuantityConstant.ADDRESS_AGV_TASK_CANCEL, warehouseCode, area);
            } else {

            }
            String JsonParam = JSON.toJSONString(object);
            System.out.println(JsonParam);
            String result = HttpUtils.bodypost(url, JsonParam, "CS0001");
            if (result == null) {
                throw new ServiceException("调用失败");
            } else {
                return AjaxResult.success(result);
            }
        }
        return AjaxResult.success("下发成功");
    }

    //根据agv的任务状态来判断
    private AjaxResult agvTaskStatusNowStart(Integer o3, AgvTask agvTask) {
        AgvTask task = getById(agvTask.getId());
        if (task == null) {
            return AjaxResult.error("任务号" + agvTask.getId() + "不存在");
        }
        if (task.getStatus()==QuantityConstant.TASK_STATUS_COMPLETED) {
            return AjaxResult.error("任务" + agvTask.getId() + "已经完成");
        }
        if (o3.equals(QuantityConstant.STATUS_TASK_AGV_START)) {
            agvTask.setStatus(20);
            updateById(agvTask);
        }
        if (o3.equals(QuantityConstant.STATUS_TASK_AGV_TASKOVER)) {
            agvTask.setStatus(50);
            updateById(agvTask);
        }
        if (o3.equals(QuantityConstant.STATUS_TASK_FINISH)) {
            task.setStatus(100);
            updateById(task);
            agvPortService.updateStatus(task.getToPort(), QuantityConstant.STATUS_POSITION_EMPTY);
            return AjaxResult.success();
        }
        return AjaxResult.success();
    }

    //根据任务类型检验参数
    private void checkAgvTaskPosition(AgvTask agvTask) {
        if (StringUtils.isNull(agvTask)) {
            throw new ServiceException("任务数据为空,请重新下发");
        }
        if (StringUtils.isEmpty(agvTask.getContainerCode())) {
            throw new ServiceException("托盘为空");
        }

        AgvPort sourcePosition = agvPortService.getAgvportByCode(agvTask.getFromPort());
        AgvPort desPosition = agvPortService.getAgvportByCode(agvTask.getToPort());

        if (StringUtils.isEmpty(agvTask.getFromPort())) {
            throw new ServiceException("源点位为空");
        }
        if (StringUtils.isNull(sourcePosition)) {
            throw new ServiceException("源点位:" + sourcePosition.getName() + "未找到");
        }
//        if(sourcePosition.getStatus().equals(QuantityConstant.STATUS_POSITION_LOCK)){
//            throw new ServiceException("源点位:" + sourcePosition.getName() + "禁用");
//        }

        if (StringUtils.isEmpty(agvTask.getToPort())) {
            throw new ServiceException("目标点位为空");
        }
        if (StringUtils.isNull(desPosition)) {
            throw new ServiceException("目标点位:" + desPosition.getName() + "未找到");
        }
        if (!desPosition.getUserDef1()) {
            return;
        }
        if (desPosition.getStatus().equals(QuantityConstant.STATUS_POSITION_LOCK)) {
            throw new ServiceException("目标点位:" + desPosition.getName() + "禁用");
        }
//        if (StringUtils.isNotEmpty(desPosition.getContainerCode())) {
//            throw new ServiceException("目标点位:" + desPosition.getName() + "存在托盘:" + desPosition.getContainerCode());
//        }
        if (QuantityConstant.STATUS_CONTAINER_FULL.equals(desPosition.getStatus())) {
            throw new ServiceException("目标点位:" + desPosition.getName() + "已满");
        }

    }


    /**
     * 检查托盘和点位是否存在未完成的任务
     *
     * @param agvTask
     */
    private void checkContainerAndPositionStatus(AgvTask agvTask) {

        TaskHeader containerLKTaskStatus = taskHeaderService.getOne(new LambdaQueryWrapper<TaskHeader>()
                .eq(TaskHeader::getContainerCode, agvTask.getContainerCode())
                .lt(TaskHeader::getStatus, QuantityConstant.TASK_STATUS_COMPLETED));
        AgvTask containerAgvTaskStatus = getOne(new LambdaQueryWrapper<AgvTask>()
                .eq(AgvTask::getContainerCode, agvTask.getContainerCode())
                .lt(AgvTask::getStatus, QuantityConstant.TASK_STATUS_COMPLETED));
        if (StringUtils.isNotNull(containerLKTaskStatus) || StringUtils.isNotNull(containerAgvTaskStatus)) {
            throw new ServiceException("托盘" + agvTask.getContainerCode() + "存在未完成的任务");
        }

        Container containerStatus = containerService.getContainerByCode(agvTask.getContainerCode(),"CS0001");
        if (StringUtils.isNull(containerStatus)) {
            throw new ServiceException("托盘" + agvTask.getContainerCode() + "不存在");
        }
        if (QuantityConstant.STATUS_CONTAINER_LOCK.equals(containerStatus.getStatus())) {
            throw new ServiceException("托盘" + agvTask.getContainerCode() + "已锁定");
        }

        AgvPort pointPosition = agvPortService.getOne(new LambdaQueryWrapper<AgvPort>()
                .eq(AgvPort::getContainerCode, agvTask.getContainerCode())
                .eq(AgvPort::getStatus, QuantityConstant.STATUS_CONTAINER_LOCK)
                .orderByAsc(AgvPort::getType).last("limit 1"));
        if (pointPosition != null) {
            throw new ServiceException("点位" + pointPosition.getCode() + "已锁定,托盘在此位置不能生成任务");
        }
    }

    //校验自己生成的任务中源点位的托盘和实际托盘一不一致
    @SuppressWarnings("AlibabaCommentsMustBeJavadocFormat")
    private void checkContainerAndPositionLove(AgvTask agvTask) {
        AgvPort agvPort = agvPortService.getAgvportByCode(agvTask.getFromPort());
        if (agvPort != null && StringUtils.isNotEmpty(agvPort.getContainerCode())) {
            if (!agvTask.getContainerCode().equals(agvPort.getContainerCode())) {
                throw new ServiceException("源点位上托盘数据和分配的托盘不一致,请核对");
            }
        }

    }

    //更新点位状态
    @SuppressWarnings("AlibabaCommentsMustBeJavadocFormat")
    private void cancelPositionStatus(AgvTask agvTask) {
        if (agvTask.getFromPort() != null) {
            //更新点位状态
            AgvPort agvPort = agvPortService.getAgvportByCode(agvTask.getFromPort());
            if (agvPort != null && StringUtils.isNotEmpty(agvPort.getContainerCode())) {
                agvPortService.updateStatus(agvTask.getFromPort(), QuantityConstant.STATUS_POSITION_EMPTY);
            } else {
                agvPortService.updateStatus(agvTask.getFromPort(), QuantityConstant.STATUS_POSITION_EMPTY);
            }
        }
        if (agvTask.getToPort() != null) {
            //更新点位状态
            AgvPort agvPort = agvPortService.getAgvportByCode(agvTask.getToPort());
            if (agvPort != null && StringUtils.isNotEmpty(agvPort.getContainerCode())) {
                agvPortService.updateStatus(agvTask.getToPort(), QuantityConstant.STATUS_POSITION_EMPTY);
            } else {
                agvPortService.updateStatus(agvTask.getToPort(), QuantityConstant.STATUS_POSITION_EMPTY);

            }
        }

    }

    //更新容器状态
    @SuppressWarnings("AlibabaCommentsMustBeJavadocFormat")
    private void cancelContainerStatus(AgvTask agvTask) {
        Container container = new Container();
        container.setStatus(QuantityConstant.STATUS_CONTAINER_EMPTY);
        LambdaUpdateWrapper<Container> containerUpdateWrapper = Wrappers.lambdaUpdate();
        containerUpdateWrapper.eq(Container::getCode, agvTask.getContainerCode());
        containerService.update(container, containerUpdateWrapper);
    }


}