/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.youchain.businessdata.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.youchain.basicdata.domain.Point;
import com.youchain.basicdata.domain.Stock;
import com.youchain.basicdata.repository.StockRepository;
import com.youchain.basicdata.service.PointService;
import com.youchain.basicdata.service.StockService;
import com.youchain.businessdata.domain.*;
import com.youchain.businessdata.service.*;
import com.youchain.modules.quartz.utils.TimeNumberUtils;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import com.youchain.businessdata.repository.AgvTaskRepository;
import com.youchain.businessdata.service.dto.AgvTaskDto;
import com.youchain.businessdata.service.dto.AgvTaskQueryCriteria;
import com.youchain.businessdata.service.mapstruct.AgvTaskMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.sql.Timestamp;
import java.util.*;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;


/**
 * @author baobinglin
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2023-08-18
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class AgvTaskServiceImpl implements AgvTaskService {

    private final AgvTaskRepository agvTaskRepository;
    private final AgvTaskMapper agvTaskMapper;
    private final TaskService taskService;
    private final InventoryService inventoryService;
    private final InventoryLogService inventoryLogService;
    private final PointService pointService;
    private final AsnDetailService asnDetailService;
    private final StockRepository stockRepository;
    private final EntityManager entityMapper;

    @Override
    public Map<String, Object> queryAll(AgvTaskQueryCriteria criteria, Pageable pageable) {
        Page<AgvTask> page = agvTaskRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        return PageUtil.toPage(page.map(agvTaskMapper::toDto));
    }

    @Override
    public List<AgvTaskDto> queryAll(AgvTaskQueryCriteria criteria) {
        return agvTaskMapper.toDto(agvTaskRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public AgvTaskDto findById(Integer id) {
        AgvTask agvTask = agvTaskRepository.findById(id).orElseGet(AgvTask::new);
        ValidationUtil.isNull(agvTask.getId(), "AgvTask", "id", id);
        return agvTaskMapper.toDto(agvTask);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AgvTaskDto create(AgvTask resources) {
        return agvTaskMapper.toDto(agvTaskRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(AgvTask resources) {
        AgvTask agvTask = agvTaskRepository.findById(resources.getId()).orElseGet(AgvTask::new);
        ValidationUtil.isNull(agvTask.getId(), "AgvTask", "id", resources.getId());
        agvTask.copy(resources);
        agvTaskRepository.save(agvTask);
    }

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            agvTaskRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<AgvTaskDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (AgvTaskDto agvTask : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("容器码", agvTask.getStockCode());
            map.put("容器类型", agvTask.getStockTypeCode());
            map.put("起点位置", agvTask.getStartSlotCode());
            map.put("终点位置", agvTask.getEndSlotCode());
            map.put("容器当前位置", agvTask.getSlotCode());
            map.put("任务状态", agvTask.getStatus());
            map.put("任务类型", agvTask.getType());
            map.put("下游任务号", agvTask.getJobId());
            map.put("工作类型", agvTask.getJobType());
            map.put("优先级", agvTask.getJobPriority());
            map.put("强制优先级", agvTask.getJobPriorityType());
            map.put("任务组", agvTask.getJobForce());
            map.put("任务组执行顺序", agvTask.getJobForceAsc());
            map.put("返回报文", agvTask.getJobMessage());
            map.put("变动时间", agvTask.getJobMessageTime());
            map.put("创建时间", agvTask.getCreateTime());
            map.put("开始时间", agvTask.getStartTime());
            map.put("完成时间", agvTask.getEndTime());
            map.put("创建人", agvTask.getCreateBy());
            map.put("修改人", agvTask.getUpdateBy());
            map.put("修改时间", agvTask.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    /**
     * @param agvTasks
     * @return
     */
    @Override
    public synchronized String sendAgvTaskImpl(AgvTask agvTasks) {

        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());

        Map<String, Object> objMap = new LinkedHashMap<>();
        objMap.put("orgId", agvTasks.getId());//库存组织 ID
        objMap.put("requestId", agvTasks.getId());//请求 id
        objMap.put("missionCode", agvTasks.getId());//任务编号

        objMap.put("missionType", agvTasks.getJobType());//货 架 ( 托 盘 ) 移动 RACK_MOVE
        String viewBoardType = "";
        Point point = pointService.findByCode(agvTasks.getStartSlotCode(), null, null, null, null,null);
        //到达上视自动识别
        if (AreaNameDic.CPRKQ.equals(point.getArea().getName())) {
            viewBoardType = "IDENTIFY_REQUIRE";
        }
        objMap.put("viewBoardType", viewBoardType);//上视识别类型；需要 IDENTIFY_REQUIRE 不需要NORMAL
        objMap.put("robotType", "LIFT");//机器人功能类型
        JSONArray robotModels = new JSONArray();
        objMap.put("robotModels", robotModels);//机器人具体型号
        JSONArray robotIds = new JSONArray();
        objMap.put("robotIds", robotIds);//机器人编号
        objMap.put("priority", "1");//数值越小，优先级越高，默认是 1
        objMap.put("containerModelCode", "");//容器模型编码
        objMap.put("containerCode", agvTasks.getStockCode() == null ? "" : agvTasks.getStockCode());//容器编号
        objMap.put("templateCode", "");//作业流程模板编号
        objMap.put("lockRobotAfterFinish", false);//是否需要流程结束后机器人保持任务锁定状态
        objMap.put("unlockRobotId", "");//解锁当前小车的在上个任务的锁定状态
        objMap.put("unlockMissionCode", "");//当前小车的上一个任务
        objMap.put("idleNode", "");//作业流程完成后，指定机器人停放区域/点
        JSONArray missionDataArray = new JSONArray();
        JSONObject missionDataObj = new JSONObject(new LinkedHashMap<>());
        Map<String, Object> missionDataMap = new LinkedHashMap<>();
        missionDataMap.put("sequence", 1);//序号
        missionDataMap.put("position", agvTasks.getStartSlotCode());//起始点
        missionDataMap.put("type", "NODE_POINT");//作业位置类型：点位：NODE_POINT
        missionDataMap.put("putDown", false);//作业点位是否需要放下货架
        missionDataMap.put("passStrategy", "AUTO");//当前任务点结束后放行策略
        missionDataMap.put("waitingMillis", "0");//自动触发离开当前任务节点的时间，默认单位:毫秒
        missionDataObj.putAll(missionDataMap);
        missionDataArray.add(missionDataObj);

        JSONObject missionDataObj2 = new JSONObject(new LinkedHashMap<>());
        Map<String, Object> missionDataMap2 = new LinkedHashMap<>();
        missionDataMap2.put("sequence", 2);//序号
        missionDataMap2.put("position", agvTasks.getEndSlotCode());//目标点
        missionDataMap2.put("type", "NODE_POINT");//作业位置类型：点位：NODE_POINT
        missionDataMap2.put("putDown", true);//作业点位是否需要放下货架
        missionDataMap2.put("passStrategy", "AUTO");//当前任务点结束后放行策略
        missionDataMap2.put("waitingMillis", "0");//自动触发离开当前任务节点的时间，默认单位:毫秒
        missionDataObj2.putAll(missionDataMap2);
        missionDataArray.add(missionDataObj2);


        objMap.put("missionData", missionDataArray);
        jsonObject.putAll(objMap);
        String resultJson = "";
//        String resultJson = HttpPostUtil.sendPostReq(UrlApi.submitMission(), jsonObject.toString());//返回ResponseJson*/
//        if (StringUtils.isEmpty(resultJson)) {
//            throw new RuntimeException("AGV返回信息:下发任务接口调用失败!");
//        }
//        JSONObject resulObject = JSON.parseObject(resultJson);
//        if (resulObject == null) {
//            throw new RuntimeException("AGV返回信息:下发任务接口返回为空!");
//        }
//
//        String code = resulObject.getString("code");
//        String message = resulObject.getString("message");
        String code = "0";
        String message = "";
        if (!"0".equals(code)) {
            throw new RuntimeException("AGV返回消息:" + message);
        }
        agvTasks.setJobForce(agvTasks.getId().toString());//任务组
        agvTasks.setJobForceAsc((1));
        agvTasks.setStatus(BizStatus.ATCALL);
        agvTasks.setJobMessage(resultJson);
        agvTasks.setReqMessage(jsonObject.toString());
        agvTasks.setStartTime(new Timestamp(new Date().getTime()));
        update(agvTasks);

        return resultJson;
    }

    @Override
    public synchronized String sendAgvTaskLXImpl(List<AgvTask> agvTasks) {
        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
        String agvCode = TimeNumberUtils.getXJTaskCode();
        Map<String, Object> objMap = new LinkedHashMap<>();
        objMap.put("orgId", agvCode);//库存组织 ID(或工厂代码，供应商代码)
        objMap.put("requestId", agvCode);//请求 id
        objMap.put("missionCode", agvCode);//任务编号
        objMap.put("missionType", "PICKER_MOVE");//任务类型 ：料箱
        objMap.put("viewBoardType", "");//上视识别类型:
        objMap.put("robotType", "PICKER");//机器人功能类型
        JSONArray robotModels = new JSONArray();
        objMap.put("robotModels", robotModels);//机器人具体型号
        JSONArray robotIds = new JSONArray();
        objMap.put("robotIds", robotIds);//机器人编号
        objMap.put("priority", "1");//数值越小，优先级越高，默认是 1
        objMap.put("templateCode", "");//作业流程模板编号
        objMap.put("lockRobotAfterFinish", false);//是否需要流程结束后机器人保持任务锁定状态
        objMap.put("unlockRobotId", "");//解锁当前小车的在上个任务的锁定状态
        objMap.put("unlockMissionCode", "");//当前小车的上一个任务
        objMap.put("idleNode", "");//作业流程完成后，指定机器人停放区域/点

        JSONArray missionDataArray = new JSONArray();
        for (int i = 0; i < agvTasks.size(); i++) {
            AgvTask agvTask = agvTasks.get(i);
            JSONObject missionDataObj = new JSONObject(new LinkedHashMap<>());
            Map<String, Object> missionDataMap = new LinkedHashMap<>();
            missionDataMap.put("sequence", (i + 1));//序号
            missionDataMap.put("binCode", agvTask.getStockCode());//料箱号
            missionDataMap.put("startPosition", "");//料箱所在的起始点位
            missionDataMap.put("startSlotCode", agvTask.getStartSlotCode());//料箱所在的起始槽位
            missionDataMap.put("takeActionConfirm", false);//取料箱时之前是否需确认
            missionDataMap.put("endPosition", "");//料箱所在的目标点位
            missionDataMap.put("endSlotCode", agvTask.getEndSlotCode());//料箱所在的目标槽位
            missionDataMap.put("putActionConfirm", false);//放料箱时之前是否需要确认
            missionDataObj.putAll(missionDataMap);
            missionDataArray.add(missionDataObj);
        }

        objMap.put("missionData", missionDataArray);
        jsonObject.putAll(objMap);
        System.out.println(jsonObject.toString());
        String resultJson = HttpPostUtil.sendPostReq(UrlApi.submitMission(), jsonObject.toString());
        JSONObject resulObject = JSON.parseObject(resultJson);
        String code = resulObject.getString("code") == null ? "" : resulObject.getString("code");
        if (code.equals("0")) {
            for (int i = 0; i < agvTasks.size(); i++) {
                AgvTask agvTask = agvTasks.get(i);
                agvTask.setJobForce(agvCode);//任务组
                agvTask.setJobForceAsc((i + 1));
                agvTask.setStatus(BizStatus.ATCALL);
                agvTask.setJobMessage(resultJson);
                agvTask.setReqMessage(jsonObject.toString());
                agvTask.setStartTime(new Timestamp(new Date().getTime()));
                update(agvTask);
            }
        } else {
            for (int i = 0; i < agvTasks.size(); i++) {
                AgvTask agvTask = agvTasks.get(i);
                agvTask.setJobMessage(resultJson);
                agvTask.setReqMessage(jsonObject.toString());
                update(agvTask);
            }
        }
        return resultJson;
    }

    @Override
    public synchronized String sendAgvTaskGTImpl(List<AgvTask> agvTasks1, List<AgvTask> agvTasks2) {
        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
        String agvCode = TimeNumberUtils.getGTTaskCode();
        Map<String, Object> objMap = new LinkedHashMap<>();
        objMap.put("orgId", agvCode);//库存组织 ID(或工厂代码，供应商代码)
        objMap.put("requestId", agvCode);//请求 id
        objMap.put("missionCode", agvCode);//任务编号
        objMap.put("missionType", "ROLLER_MOVE");//任务类型 ：滚筒
        objMap.put("viewBoardType", "");//上视识别类型:
        JSONArray missionDataArray = new JSONArray();
        for (int i = 0; i < agvTasks1.size(); i++) {
            AgvTask agvTask = agvTasks1.get(i);
            JSONObject missionDataObj = new JSONObject(new LinkedHashMap<>());
            Map<String, Object> missionDataMap = new LinkedHashMap<>();
            missionDataMap.put("sequence", (i + 1));//序号
            missionDataMap.put("binCode", agvTask.getStockCode());//料箱号
            missionDataMap.put("startDeviceCode", agvTask.getStartSlotCode());//料箱所在的起始槽位
            missionDataMap.put("endDeviceCode", agvTask.getEndSlotCode());//料箱所在的目标槽位
            missionDataMap.put("rollerLevel", 2);//层
            missionDataMap.put("rollerColumn", (i + 1));//列
            missionDataObj.putAll(missionDataMap);
            missionDataArray.add(missionDataObj);
        }
        int sum = agvTasks1.size();
        if (agvTasks2.size() > 0) {
            for (int i = 0; i < agvTasks2.size(); i++) {
                AgvTask agvTask = agvTasks2.get(i);
                JSONObject missionDataObj = new JSONObject(new LinkedHashMap<>());
                Map<String, Object> missionDataMap = new LinkedHashMap<>();
                missionDataMap.put("sequence", (sum + (i + 1)));//序号
                missionDataMap.put("binCode", agvTask.getStockCode());//料箱号
                missionDataMap.put("startDeviceCode", agvTask.getStartSlotCode());//料箱所在的起始槽位
                missionDataMap.put("endDeviceCode", agvTask.getEndSlotCode());//料箱所在的目标槽位
                missionDataMap.put("rollerLevel", 1);//层
                missionDataMap.put("rollerColumn", (i + 1));//列
                missionDataObj.putAll(missionDataMap);
                missionDataArray.add(missionDataObj);
            }
        }


        objMap.put("missionData", missionDataArray);
        jsonObject.putAll(objMap);
        System.out.println(jsonObject.toString());
        String resultJson = HttpPostUtil.sendPostReq(UrlApi.submitMission(), jsonObject.toString());//返回ResponseJson*/
        JSONObject resulObject = JSON.parseObject(resultJson);
        String code = resulObject.getString("code") == null ? "" : resulObject.getString("code");
        if (code.equals("0")) {
            for (int i = 0; i < agvTasks1.size(); i++) {
                AgvTask agvTask = agvTasks1.get(i);
                agvTask.setJobForce(agvCode);//任务组
                agvTask.setJobForceAsc((i + 1));
                agvTask.setStatus(BizStatus.ATCALL);
                agvTask.setJobMessage(resultJson);
                agvTask.setReqMessage(jsonObject.toString());
                agvTask.setStartTime(new Timestamp(new Date().getTime()));
                update(agvTask);
            }
            for (int i = 0; i < agvTasks2.size(); i++) {
                AgvTask agvTask = agvTasks2.get(i);
                agvTask.setJobForce(agvCode);//任务组
                agvTask.setJobForceAsc((i + 1));
                agvTask.setStatus(BizStatus.ATCALL);
                agvTask.setJobMessage(resultJson);
                agvTask.setReqMessage(jsonObject.toString());
                agvTask.setStartTime(new Timestamp(new Date().getTime()));
                update(agvTask);
            }
        } else {
            for (int i = 0; i < agvTasks1.size(); i++) {
                AgvTask agvTask = agvTasks1.get(i);
                agvTask.setJobMessage(resultJson);
                agvTask.setReqMessage(jsonObject.toString());
                update(agvTask);
            }
            for (int i = 0; i < agvTasks2.size(); i++) {
                AgvTask agvTask = agvTasks2.get(i);
                agvTask.setJobMessage(resultJson);
                agvTask.setReqMessage(jsonObject.toString());
                update(agvTask);
            }
        }
        return resultJson;
    }

    @Override
    public String containerQuery(String containerCode) {
        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
        jsonObject.put("nodeCode", "");//点位编码
        jsonObject.put("containerModelCode", "");//容器模型编码
        jsonObject.put("containerCode", containerCode);//容器编号
        jsonObject.put("areaCode", "");//区域编码
        jsonObject.put("emptyFullStatus", 2);//容器的空满状态 空 0  满 1  全部 2
        return jsonObject.toJSONString();
    }

    @Override
    public int QueryCount(String taskCode) {

        String jsonObject = "{\"taskCode\":\"" + taskCode + "\"}";//查询出库缓存输送线上满料箱总数
        String resultJson = HttpPostUtil.sendPostReq(UrlApi.QueryCount(), jsonObject);
        JSONObject json = JSON.parseObject(resultJson);
        String queryCount = json.getString("queryCount");

        return Integer.parseInt(queryCount);
    }

    public AgvTask toEntity(AgvTaskDto agvTaskDto) {
        return agvTaskMapper.toEntity(agvTaskDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void agvTaskCallback(AgvTask agvTask, String status, String containerCode) {
        switch (status) {
            case "ARRIVED":
                break;
            case "UP_CONTAINER":
                handleUpContainer(agvTask, containerCode);//容器顶升
                break;
            case "COMPLETED":
                handleComContainer(agvTask, containerCode);//容器完成
                break;
            case "CANCELED":
                handleCanceledTask(agvTask, containerCode);//容器取消
                break;
        }

    }

    private void handleUpContainer(AgvTask agvTask, String containerCode) {
        //顶升释放起点位置状态及容器绑定的起点位置
        Point startPoint = pointService.findByCode(agvTask.getStartSlotCode(), null, null, null, null,null);
        startPoint.setStatus(BaseStatus.FREE);
        pointService.update(startPoint);

        agvTask.setStockCode(containerCode);
        agvTask.setStatus(BizStatus.UP_CONTAINER);
        agvTask.setStartTime(new Timestamp(new Date().getTime()));
        this.update(agvTask);
    }

    private void handleComContainer(AgvTask agvTask, String containerCode) {
        //任务完成；根据AGV任务的目标点位走对应流程
        Point endPoint = pointService.findByCode(agvTask.getEndSlotCode(), null, null, null, null,null);
        String endAreaName = endPoint.getArea().getName();
        Stock stock = stockRepository.findByCode(containerCode, null);
        if (stock == null) {
            throw new RuntimeException(containerCode + "容器不存在! 请维护");
        }
        List<Task> taskList = taskService.getAgvTaskList(agvTask.getId());
        switch (endAreaName) {
            case AreaNameDic.JLQ:
                handleJL(taskList, endPoint, stock);//满车出库
                break;
            case AreaNameDic.XJQ:
            case AreaNameDic.DJQ:
                handleFBFC(taskList, stock);//满车入库
                break;
        }
        agvTask.setStatus(BizStatus.FINISH);
        agvTask.setStockCode(containerCode);
        agvTask.setEndTime(new Timestamp(new Date().getTime()));
        update(agvTask);
    }


    /**
     * 容器出场
     *
     * @param containerCode
     */
    @Transactional(rollbackFor = Exception.class)
    public void containerOut(String containerCode) {
        Stock stock = validateStock(containerCode);//验证容器
        validateAgvResponse(UrlApi.containerOut(), containerOutJson(stock.getCode()));//验证AGV返回信息
        clearInventory(stock);//清空库存
        Point point = stock.getPoint();
        point.setStatus(BaseStatus.FREE);
        pointService.update(point);
        stock.setStatus(BaseStatus.FREE);
        stock.setPoint(null);
        stockRepository.save(stock);
    }

    /**
     * 验证容器
     *
     * @param stockCode
     */
    private Stock validateStock(String stockCode) {
        Stock stock = stockRepository.findByCode(stockCode, null);
        if (stock == null) {
            throw new RuntimeException("请扫描正确的容器!");
        }
        return stock;
    }

    /**
     * 验证AGV返回信息
     *
     * @param jsonObject
     */
    private void validateAgvResponse(String url, String jsonObject) {
        /*String resultJson = HttpPostUtil.sendPostReq(url, jsonObject);
        if (StringUtils.isEmpty(resultJson)) {
            throw new RuntimeException("AGV返回信息:容器入场接口调用失败!");
        }
        JSONObject resultObject = JSON.parseObject(resultJson);
        if (resultObject == null) {
            throw new RuntimeException("AGV返回信息:容器入场接口数据返回为空!");
        }
        String code = resultObject.getString("code");
        String message = resultObject.getString("message");
        if (!"0".equals(code)) {
            throw new RuntimeException("AGV返回信息:容器入场接口调用失败!" + message);
        }*/
    }

    public synchronized String containerOutJson(String containerCode) {
        JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
        jsonObject.put("requestId", String.valueOf(new Date().getTime()));//请求 id
        jsonObject.put("containerType", "");//容器类型
        jsonObject.put("containerCode", containerCode);//容器编号
        jsonObject.put("position", "");//容器当前位置
        return jsonObject.toJSONString();
    }

    /**
     * 清空库存
     *
     * @param stock
     */
    private void clearInventory(Stock stock) {
        List<Inventory> inventoryList = inventoryService.queryInventory(stock);
        Long[] ids = inventoryList.stream().map(Inventory::getId).toArray(Long[]::new);
        if (ids.length > 0) {
            inventoryService.deleteAll(ids);
        }
    }

    /**
     * 满车入库
     *
     * @param taskList
     * @param stock
     */
    private void handleFBFC(List<Task> taskList, Stock stock) {
        //容器回存储区，新增库存、更新点位状态
        for (Task task : taskList) {
            AsnDetail ad = task.getAsnDetail();
            ad.setReceivedQty(ad.getOrderQty());
            ad.setStatus(BizStatus.RECEIVED);
            ad.setStock(stock);
            asnDetailService.update(ad);

            task.setTaskStatus(BizStatus.FINISH);
            task.setMoveQty(task.getPlanQty());
            task.setSrcStock(stock);
            task.setDstStock(stock);
            taskService.update(task);

            updateInventory(stock, task, ad);
        }
    }

    /**
     * 满车出库
     *
     * @param taskList
     * @param stock
     */
    private void handleJL(List<Task> taskList, Point endPoint, Stock stock) {
        //容器到达叫料线边扣减库存,容器自动出场
        for (Task task : taskList) {
            try {
                taskService.pickConfirm(task.getId(), task.getPlanQty());
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        }
        containerOut(stock.getCode());
        endPoint.setStatus(BaseStatus.FREE);
        pointService.update(endPoint);

    }

    /**
     * 更新库存
     *
     * @param stock
     * @param task
     * @param ad
     */
    private void updateInventory(Stock stock, Task task, AsnDetail ad) {
        List<Inventory> inventoryList = inventoryService.queryInventory(stock);
        if (inventoryList.size() > 0) {
            Long[] ids = new Long[inventoryList.size()];
            for (int i = 0; i < inventoryList.size(); i++) {
                ids[i] = inventoryList.get(i).getId();
            }
            if (ids.length > 0) {
                inventoryService.deleteAll(ids);
            }
        }

        Inventory inventory = inventoryService.getInventory(task.getItemKey(), task.getDstPoint(), stock, task.getDept(), BizStatus.RECEIVING_UP);
        inventory.setQuantity(inventory.getQuantity() + task.getPlanQty());
        inventoryService.update(inventory);

        stock.setStatus(BaseStatus.USED);
        stock.setPoint(inventory.getPoint());
        stockRepository.save(stock);

        Point point = inventory.getPoint();
        point.setStatus(BaseStatus.USED);
        pointService.update(point);

        inventoryLogService.storeInventoryLog(BizStatus.RECEIVING_UP, BizStatus.ADD, null, task.getItemKey(), task.getSrcPoint(), task.getDstPoint(), task.getSrcStock(), task.getSrcStock(), 0d, task.getPlanQty(), BizStatus.ASN, ad.getId(), inventory.getId(), ad.getRemark());
    }

    /**
     * 任务取消完成
     *
     * @param agvTask
     * @param containerCode
     */
    private void handleCanceledTask(AgvTask agvTask, String containerCode) {
        //任务取消完成
        Point endPoint = pointService.findByCode(agvTask.getEndSlotCode(), null, null, null, null,null);
        String endAreaName = endPoint.getArea().getName();
        Stock stock = stockRepository.findByCode(containerCode, null);
        if (stock == null) {
            throw new RuntimeException(containerCode + "容器不存在! 请维护");
        }
        switch (endAreaName) {
            case AreaNameDic.JLQ:
                handleJLCancel(agvTask, containerCode, endPoint);//满车到2F达产线取消
                break;
            case AreaNameDic.XJQ:
            case AreaNameDic.DJQ:
                handleFBFCCancel(agvTask, endPoint, stock);//入库取消
                break;
        }

        agvTask.setStatus(BizStatus.CANCEL);
        agvTask.setEndTime(new Timestamp(new Date().getTime()));
        this.update(agvTask);

    }

    private void handleFKCancel(AgvTask agvTask, Point endPoint, Stock stock) {
        //回空车取消
        Point srcPoint = pointService.findByCode(agvTask.getStartSlotCode(), null, null, null, null,null);
        //起点点位释放
        releasePoint(srcPoint);
        stock.setPoint(null);
        stock.setStatus(BaseStatus.FREE);
        stockRepository.save(stock);

        //终点点位释放
        releasePoint(endPoint);
    }


    /**
     * 空车到达1F产线取消
     */
    private void handleFKCCancel(AgvTask agvTask, String containerCode, Point endPoint) {
        /*String jsonObject = this.containerQuery(containerCode);
        String resultJson = HttpPostUtil.sendPostReq(UrlApi.containerQuery(), jsonObject);
        if (StringUtils.isEmpty(resultJson)) {
            throw new RuntimeException("AGV返回信息:容器查询接口调用失败!");
        }
        JSONObject resulObject = JSON.parseObject(resultJson);
        if (resulObject == null) {
            throw new RuntimeException("AGV返回信息:容器查询接口数据返回为空!");
        }
        String code = resulObject.getString("code") == null ? "" : resulObject.getString("code");
        if (!"0".equals(code)) {
            throw new RuntimeException("AGV返回信息:" + resulObject.getString("message"));
        }
        String data1 = resulObject.getString("data") == null ? "" : resulObject.getString("data");
        JSONArray jsonArray = JSON.parseArray(data1);
        if (jsonArray.isEmpty()) {
            throw new RuntimeException("AGV返回信息:容器查询接口数据格式错误!");
        }
        JSONObject dataObject = JSON.parseObject(jsonArray.get(0).toString());
        if (dataObject == null) {
            throw new RuntimeException("AGV返回信息:容器查询接口数据格式错误!");
        }
        String isCarry = dataObject.getString("isCarry") == null ? "" : dataObject.getString("isCarry");*/
        String isCarry = "0";
        if (isCarry.equals("0")) {
            //容器未移动，容器点位回原点
            log.info(agvTask.getId() + "任务" + containerCode + "容器未移动!");
            Stock stock = stockRepository.findByCode(containerCode, null);
            if (stock != null) {
                Point srcPoint = pointService.findByCode(agvTask.getStartSlotCode(), null, null, null, null,null);
                stock.setPoint(srcPoint);
                stockRepository.save(stock);
            }
        } else {
            //容器已经移动，则人工处理容器出场
        }
        //线边点位释放
        releasePoint(endPoint);
    }

    private void handleJLCancel(AgvTask agvTask, String containerCode, Point endPoint) {
        /*String jsonObject = this.containerQuery(containerCode);
        String resultJson = HttpPostUtil.sendPostReq(UrlApi.containerQuery(), jsonObject);
        if (StringUtils.isEmpty(resultJson)) {
            throw new RuntimeException("AGV返回信息:容器查询接口调用失败!");
        }
        JSONObject resulObject = JSON.parseObject(resultJson);
        if (resulObject == null) {
            throw new RuntimeException("AGV返回信息:容器查询接口数据返回为空!");
        }
        String code = resulObject.getString("code") == null ? "" : resulObject.getString("code");
        if (!"0".equals(code)) {
            throw new RuntimeException("AGV返回信息:" + resulObject.getString("message"));
        }
        String data1 = resulObject.getString("data") == null ? "" : resulObject.getString("data");
        JSONArray jsonArray = JSON.parseArray(data1);
        if (jsonArray.isEmpty()) {
            throw new RuntimeException("AGV返回信息:容器查询接口数据格式错误!");
        }
        JSONObject dataObject = JSON.parseObject(jsonArray.get(0).toString());
        if (dataObject == null) {
            throw new RuntimeException("AGV返回信息:容器查询接口数据格式错误!");
        }
        String isCarry = dataObject.getString("isCarry") == null ? "" : dataObject.getString("isCarry");*/
        String isCarry = "1";
        if (isCarry.equals("0")) {
            //容器未移动，则还原库存
            Stock stock = stockRepository.findByCode(containerCode, null);
            if (stock != null) {
                List<Inventory> inventoryList = inventoryService.queryInventory(stock);
                for (Inventory inventory : inventoryList) {
                    inventory.setQueuedQty(0d);
                    inventoryService.update(inventory);
                }
            }
            log.info(agvTask.getId() + "任务的容器未移动,还原库存信息!");
        } else {
            //容器已经移动，则直接出库
            List<Task> taskList = taskService.getAgvTaskList(agvTask.getId());
            for (Task task : taskList) {
                try {
                    taskService.pickConfirm(task.getId(), task.getPlanQty());
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage());
                }
            }

        }

        //终点点位释放
        releasePoint(endPoint);
    }

    private void handleFBFCCancel(AgvTask agvTask, Point endPoint, Stock stock) {
        //回存储区取消任务，不生成库存 入库任务取消即可
        List<Task> taskList = taskService.getAgvTaskList(agvTask.getId());
        for (Task task : taskList) {
            AsnDetail ad = task.getAsnDetail();
            ad.setStatus(BizStatus.CANCEL);
            ad.setStock(stock);
            asnDetailService.update(ad);

            task.setTaskStatus(BizStatus.CANCEL);
            task.setSrcStock(stock);
            task.setDstStock(stock);
            taskService.update(task);
        }
        //起点点位释放
        Point srcPoint = pointService.findByCode(agvTask.getStartSlotCode(), null, null, null, null,null);
        releasePoint(srcPoint);
        stock.setPoint(null);
        stock.setStatus(BaseStatus.FREE);
        stockRepository.save(stock);
        //线边点位释放
        releasePoint(endPoint);
    }

    /**
     * 释放点位
     *
     * @param point
     */
    private void releasePoint(Point point) {
        if (point != null) {
            point.setStatus(BaseStatus.FREE);
            pointService.update(point);
        }
    }


    @Override
    public boolean findByendSlotCode(String endSlotCode, String type, String jobType) {
        String hql = " from AgvTask agv " + " where  agv.endSlotCode='" + endSlotCode + "' " + " and agv.type='" + type + "' " + " and agv.jobType='" + jobType + "' " + " and agv.status in ('ATCALL','UP_CONTAINER') ";

        Query query = entityMapper.createQuery(hql);
        List<AgvTask> agvTaskList = query.getResultList();
        if (agvTaskList.size() > 0) {
            return false;
        }
        return true;
    }

    @Override
    public List<AgvTask> findById(List<Integer> ids) {
        String agvTaskIds = StringUtils.strip(ids.toString(), "[]");
        String hql = " from AgvTask agv where  agv.id in (" + agvTaskIds + ") ";
        Query query = entityMapper.createQuery(hql);
        List<AgvTask> agvTaskList = query.getResultList();
        return agvTaskList;
    }

}
