package com.youchain.businessdata.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.youchain.RequestData.ItemDate;
import com.youchain.RequestData.TransTask;
import com.youchain.RequestData.Yclbl;
import com.youchain.basicdata.domain.Item;
import com.youchain.basicdata.domain.Point;
import com.youchain.basicdata.domain.Stock;
import com.youchain.basicdata.repository.ItemRepository;
import com.youchain.basicdata.repository.PointRepository;
import com.youchain.basicdata.service.ItemService;
import com.youchain.basicdata.service.PointService;
import com.youchain.basicdata.service.StockService;
import com.youchain.businessdata.domain.AgvTask;
import com.youchain.businessdata.domain.Pick;
import com.youchain.businessdata.domain.PickDetail;
import com.youchain.businessdata.domain.Task;
import com.youchain.businessdata.repository.PickDetailRepository;
import com.youchain.businessdata.repository.PickRepository;
import com.youchain.businessdata.service.AgvTaskService;
import com.youchain.businessdata.service.MesService;
import com.youchain.businessdata.service.TaskService;
import com.youchain.exception.BadRequestException;
import com.youchain.modules.system.domain.Dict;
import com.youchain.modules.system.repository.DictRepository;
import com.youchain.modules.system.service.DeptService;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class MesServiceImpl implements MesService {
    private final PointRepository pointRepository;
    private final PickRepository pickRepository;
    private final PickDetailRepository pickDetailRepository;
    private final ItemRepository itemRepository;
    private final ItemService itemService;
    private final StockService stockService;
    private final PointService pointService;
    private final TaskService taskService;
    private final AgvTaskService agvTaskService;
    private final KMReServiceImpl kmReService;
    private final DeptService deptService;
    private final GtLineMap gtLineMap;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void materialBl(Yclbl yclbl) {
        //验证参数有效性
        validatePick(yclbl);

        //验证出库单是否存在
        checkIfGdExists(yclbl);

        List<Pick> createPicks = new ArrayList<>();
        List<PickDetail> createPickDetails = new ArrayList<>();

        String orderNo = yclbl.getOrderNo();
        String taskCode = yclbl.getTaskCode();

        //遍历成品集合
        yclbl.getBlzc().forEach(zcData -> {
            Pick pick = createPick(orderNo, taskCode, zcData.getLineNo(), zcData.getCompleteCode(), zcData.getStation(), BaseStatus.GD_TYPE_CT);
            createPicks.add(pick);
            zcData.getBlzcmx().forEach(itemDate -> {
                //如果物料长度大于11说明是MES拆分了订单；物料编号改变了处理00
                String itemCode = itemDate.getItemCode().length() > 11
                        ? itemDate.getItemCode().substring(0, 11)
                        : itemDate.getItemCode();
                String splitItemCode = itemDate.getItemCode().length() > 11
                        ? itemDate.getItemCode()
                        : null;
                Item item = itemRepository.findByCode(itemCode);
                if (item == null) {
                    item = itemService.createItem(itemCode, itemDate.getItemName(), itemDate.getItemQty(), BizStatus.XJ);
                } else {
                    item.setExtendD1(itemDate.getItemQty());
                    itemRepository.save(item);
                }
                PickDetail pickDetail = createPickDetail(pick, item, BaseStatus.GD_TYPE_CT, itemDate.getItemQty(), zcData.getCompleteQty(), splitItemCode);
                createPickDetails.add(pickDetail);
            });
        });

        //遍历单品品集合
        yclbl.getBlzcmx().forEach(itemDate -> {
            Pick pick = createPick(orderNo, taskCode, itemDate.getLineNo(), itemDate.getItemCode(), itemDate.getStation(), BaseStatus.GD_TYPE_DP);
            createPicks.add(pick);
            //如果物料长度大于11说明是MES拆分了订单；物料编号改变了处理00
            String itemCode = itemDate.getItemCode().length() > 11
                    ? itemDate.getItemCode().substring(0, 11)
                    : itemDate.getItemCode();
            String splitItemCode = itemDate.getItemCode().length() > 11
                    ? itemDate.getItemCode()
                    : null;
            Item item = itemRepository.findByCode(itemCode);
            if (item == null) {
                item = itemService.createItem(itemDate.getItemCode(), itemDate.getItemName(), itemDate.getItemQty(), BizStatus.DJ);
            } else {
                item.setExtendD1(itemDate.getItemQty());
                itemRepository.save(item);
            }
            PickDetail pickDetail = createPickDetail(pick, item, BaseStatus.GD_TYPE_DP, itemDate.getItemQty(), null, splitItemCode);
            createPickDetails.add(pickDetail);
        });

        // 批量插入
        if (!createPicks.isEmpty()) {
            pickRepository.saveAll(createPicks);
        }

        if (!createPickDetails.isEmpty()) {
            pickDetailRepository.saveAll(createPickDetails);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String itemCall(String gdNo, String itemCode, String station, String pointCode) {
        Pick pick = pickRepository.findByPick(gdNo, itemCode, station);
        if (pick == null) {
            return gdNo + ":" + itemCode + ":" + station + "工单WMS不存在，叫料失败!";
        }
        if (pick.getCallPoint() == null || pick.getCallPoint().length() <= 0) {
            pick.setCallPoint(pointCode);
        } else {
            pick.setCallPoint(pick.getCallPoint() + "," + pointCode);
        }
        pick.setIsCall(true);
        pickRepository.save(pick);
        return "叫料成功!";
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String bigItemCall(String gdNo, String completeCode, String station, String pointCode) {
        Pick pick = pickRepository.findByPick(gdNo, completeCode, station);
        if (pick == null) {
            return gdNo + ":" + completeCode + ":" + station + "工单WMS不存在，叫料失败!";
        }
        if (pick.getCallPoint() == null || pick.getCallPoint().length() <= 0) {
            pick.setCallPoint(pointCode);
        } else {
            pick.setCallPoint(pick.getCallPoint() + "," + pointCode);
        }
        pick.setIsCall(true);
        pickRepository.save(pick);
        return "叫料成功!";
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String performTransportTask(TransTask transTask) {
        switch (transTask.getTaskType()) {
            case BizStatus.Cp_Off_Up:
                return moveCpOffUp(transTask.getPointCode());//呼叫空货架
            case BizStatus.Cp_Off_Line:
                return moveCpOffLine(transTask);//送满货架
            case BizStatus.Fx_Off_Line:
                return moveFxOffLine(transTask);//返修呼叫空托盘、返修下线
            case BizStatus.Fx_Back:
                return moveFxBack(transTask);//返修载具送回
            case BizStatus.JL_Back:
                return moveJLBack(transTask);//叫料返空
            default:
                return "任务类型错误!";
        }
    }


    /**
     * 验证参数有效性
     *
     * @param yclbl 备料参数
     */
    private void validatePick(Yclbl yclbl) {
        if (StringUtils.isEmpty(yclbl.getOrderNo())) {
            throw new IllegalArgumentException("工单号必填!");
        }
        if (StringUtils.isEmpty(yclbl.getTaskCode())) {
            throw new IllegalArgumentException("任务号必填!");
        }

        if (yclbl.getBlzc().isEmpty() && yclbl.getBlzcmx().isEmpty()) {
            throw new IllegalArgumentException("成品明细和单品明细至少一项必填!");
        }
    }

    /**
     * 验证出库单是否存在
     *
     * @param yclbl -> 备料参数
     */
    private void checkIfGdExists(Yclbl yclbl) {
        List<Pick> pick = pickRepository.findByPickGdCode(yclbl.getOrderNo());
        if (!pick.isEmpty()) {
            throw new IllegalArgumentException(yclbl.getOrderNo() + "出库单已存在!");
        }
    }

    public Pick createPick(String gdCode, String taskCode, int lineNo, String cpCodeOrpCode, String station, String orderType) {
        Pick pick = new Pick();
        pick.setTaskCode(taskCode);
        pick.setLineNo(lineNo);
        pick.setCode(gdCode + "_" + lineNo);
        pick.setGdCode(gdCode);
        pick.setStation(station);
        pick.setCpCodeOrDpCode(cpCodeOrpCode);
        pick.setStatus(BizStatus.OPEN);
        pick.setIsCall(false);
        pick.setDept(deptService.getDefaultDept());
        pick.setOrderType(orderType);
        return pick;
    }

    public PickDetail createPickDetail(Pick pick, Item item, String orderType, Double itemQty, Double bigItemQty, String splitItemCode) {
        AtomicInteger lineNo = new AtomicInteger(1);
        PickDetail pickDetail = new PickDetail();
        pickDetail.setPick(pick);
        pickDetail.setItem(item);
        pickDetail.setLineNo(lineNo.getAndIncrement());
        pickDetail.setStatus(BizStatus.OPEN);
        if (BaseStatus.GD_TYPE_CT.equals(orderType)) {
            pickDetail.setOrderQty(itemQty * bigItemQty);
        } else {
            pickDetail.setOrderQty(itemQty);
        }
        pickDetail.setPropC3(splitItemCode);
        pickDetail.setDept(pick.getDept());
        return pickDetail;
    }

    private String moveCpOffUp(String pointCode) {
        //终点
        Point endPoint = pointRepository.findByCode(pointCode);
        // 查询空车
        List<Stock> emptyStockList = getEmptyStockList();
        if (emptyStockList.isEmpty()) {
            // 没有空车的处理逻辑
            if (!agvTaskService.isEndPointAvailable(endPoint.getCode(), BizStatus.Cp_Off_Up, "RACK_MOVE")) {
                return pointCode + "点位有任务，请稍后再试!";
            }
            // 生成agv任务进行等待
            agvTaskService.createAgvTask(BizStatus.Cp_Off_Up, null, null, endPoint.getCode(), "RACK_MOVE");
            pointService.usedPoint(endPoint);
            return "成品入库区、成品入库缓存区都没有空车,请稍后再试!";
        }

        //选择空车
        Stock emptyStock = emptyStockList.get(0);
        Point srcPoint = emptyStock.getPoint();

        // 验证终点是否有任务
        if (!agvTaskService.isEndPointAvailable(endPoint.getCode(), BizStatus.Cp_Off_Up, "RACK_MOVE")) {
            return pointCode + "点位有任务，请稍后再试!";
        }

        //创建Agv任务
        AgvTask agvTask = agvTaskService.createAgvTask(BizStatus.Cp_Off_Up, emptyStock, srcPoint.getCode(), endPoint.getCode(), "RACK_MOVE");

        // 更新点位状态
        pointService.usedPoint(endPoint);

        return "呼叫成功";

    }

    /**
     * 从成品入库缓存区或成品入库区查询空车
     *
     * @return 空车列表
     */
    private List<Stock> getEmptyStockList() {
        List<Stock> emptyStockList = stockService.findByFreeOrUsedStock(AreaNameDic.CPRKQ, BaseStatus.FREE);
        return emptyStockList;
    }


    private String moveCpOffLine(TransTask transTask) {
        Point srcPoint = pointRepository.findByCode(transTask.getPointCode());
        if (srcPoint == null) {
            return transTask.getPointCode() + "点位不存在!";
        }

        //容器
        Stock stock = stockService.findByPointCode(srcPoint.getCode());

        // 查找可用的终点点位
        Point endPoint = findAvailableEndPoint();
        if (endPoint == null) {
            // 没有可用终点点位的处理逻辑
            if (!agvTaskService.isSrcPointAvailable(srcPoint.getCode(), BizStatus.Cp_Off_Line, "RACK_MOVE")) {
                return srcPoint.getCode() + "点位有任务，请稍后再试!";
            }
            // 生成等待任务
            agvTaskService.createAgvTask(BizStatus.Cp_Off_Line, stock, srcPoint.getCode(), null, "RACK_MOVE");

            // 更新点位状态
            pointService.usedPoint(srcPoint);

            // 占用容器
            stockService.usedStock(stock, srcPoint, BaseStatus.USED);
            return "成品入库区和成品下线缓存区都没有空闲点位,请稍后再试!";
        }

        // 验证终点是否有任务
        if (!agvTaskService.isEndPointAvailable(endPoint.getCode(), BizStatus.Cp_Off_Line, "RACK_MOVE")) {
            return transTask.getPointCode() + "点位有任务，请稍后再试!";
        }

        // 创建Agv任务
        AgvTask agvTask = agvTaskService.createAgvTask(BizStatus.Cp_Off_Line, stock, srcPoint.getCode(), endPoint.getCode(), "RACK_MOVE");

        // 更新点位状态
        pointService.usedPoint(endPoint);
        // 占用容器
        stockService.usedStock(stock, srcPoint, BaseStatus.USED);

        return "呼叫成功";

    }

    /**
     * 查找可用的终点点位，优先从成品入库区查找，若没有则从成品下线缓存区查找
     *
     * @return 可用的终点点位，如果没有则返回null
     */
    private Point findAvailableEndPoint() {
        List<Point> endPointList = pointService.queryPoints(null, BaseStatus.FREE, BaseStatus.BOX, AreaNameDic.CPRKQ);
        return endPointList.isEmpty() ? null : endPointList.get(0);
    }

    private String moveFxOffLine(TransTask transTask) {
        //返修上线起点
        String srcPointCode = transTask.getPointCode();
        //终点
        String dstPointCode;
        //验证点位是否为上线点
        if (gtLineMap.isOnlinePoint(srcPointCode)) {
            if ("BYDGT002".equals(srcPointCode)) {
                dstPointCode = "BYDGT006";
            } else {
                dstPointCode = gtLineMap.getKeyByValue(srcPointCode);
            }
        } else if (gtLineMap.isOfflinePoint(srcPointCode)) {
            dstPointCode = gtLineMap.getValueByKey(srcPointCode);
        } else {
            return srcPointCode + "点位不存在,请核实!";
        }


        // 生成任务
        AgvTask agvTask = agvTaskService.createAgvTask(BizStatus.Fx_Off_Line, null, srcPointCode, dstPointCode, "ROLLER_MOVE");

        return "呼叫成功";

    }

    private String moveFxBack(TransTask transTask) {
        String srcPointCode = transTask.getPointCode();
        if (!"FX001".equals(srcPointCode)) {
            return "返修点位不正确,请核实";
        }

        //根据状态查询任务
        List<AgvTask> agvTaskList = agvTaskService.findByStatus(BizStatus.ARRIVED);
        if (agvTaskList.isEmpty()) {
            return "AGV还未达到FX001返修点，请稍后再试!";
        }
        AgvTask agvTask = agvTaskList.get(0);

        //任务放行
        kmReService.sendAgvTaskToContainer(UrlApi.operationFeedback(), kmReService.operationFeedbackJson(agvTask));

        return "放行成功";
    }

    private String moveJLBack(TransTask transTask) {
        //起点
        Point srcPoint = pointRepository.findByCode(transTask.getPointCode());
        if (srcPoint == null) {
            return transTask.getPointCode() + "点位不存在!";
        }

        //容器
        Stock stock = stockService.findByPointCode(srcPoint.getCode());

        String dstAreaCode = AreaNameDic.XJJLQ.equals(srcPoint.getArea().getName()) ? AreaNameDic.XJFBCQ : AreaNameDic.DJFBCQ;
        List<Point> endPointList = pointService.queryPoints(null, BaseStatus.FREE, BaseStatus.BOX, dstAreaCode);
        if (endPointList.isEmpty()) {
            // 没有空车的处理逻辑
            if (!agvTaskService.isSrcPointAvailable(srcPoint.getCode(), BizStatus.JL_Back, "RACK_MOVE")) {
                return srcPoint.getCode() + "点位有任务，请稍后再试!";
            }
            //生成agv任务进行等待
            agvTaskService.createAgvTask(BizStatus.JL_Back, stock, srcPoint.getCode(), null, "RACK_MOVE");
            // 更新点位状态
            pointService.usedPoint(srcPoint);

            // 占用容器
            stockService.usedStock(stock, srcPoint, BaseStatus.USED);
            return dstAreaCode.equals(AreaNameDic.XJFBCQ) ? "小件翻包存储区" : "大件翻包存储区" + "没有空闲点位!";
        }

        Point endPoint = endPointList.get(0);

        if (!agvTaskService.isEndPointAvailable(endPoint.getCode(), BizStatus.JL_Back, "RACK_MOVE")) {
            return endPoint.getCode() + "点位有任务，请稍后再试!";
        }

        // 生成任务
        AgvTask agvTask = agvTaskService.createAgvTask(BizStatus.JL_Back, stock, srcPoint.getCode(), endPoint.getCode(), "RACK_MOVE");
        synchronized (endPoint) {
            // 更新点位状态
            pointService.usedPoint(endPoint);
            //占用容器
            stockService.usedStock(stock, srcPoint, BaseStatus.USED);
        }

        return "呼叫成功";

    }
}
