package com.shkj.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shkj.common.constant.RedisConstant;
import com.shkj.common.core.domain.Result;
import com.shkj.common.utils.DateUtils;
import com.shkj.plc.sdk.device.PLCReadAndWrite;
import com.shkj.plc.sdk.device.PlcOperate;
import com.shkj.wms.bo.BaseBarcodesOutAddBo;
import com.shkj.wms.bo.BaseBarcodesOutQueryBo;
import com.shkj.wms.bo.BaseBarcodesOutThirdPointBo;
import com.shkj.wms.bo.BaseBarcodesOutThirdSyncBo;
import com.shkj.wms.domain.*;
import com.shkj.wms.mapper.BaseBarcodesOutMapper;
import com.shkj.wms.plc.PlcInit;
import com.shkj.wms.service.*;
import com.shkj.wms.third.ykl.ThirdYklResult;
import com.shkj.wms.utils.JsonUtil;
import com.shkj.wms.vo.BaseBarcodesOutTaskVo;
import com.shkj.wms.vo.BaseBarcodesOutVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 出库条码信息Service业务层处理
 *
 * @author zjx
 * @date 2023-04-06
 */
@Slf4j
@Service
public class BaseBarcodesOutServiceImpl extends ServiceImpl<BaseBarcodesOutMapper, BaseBarcodesOut> implements IBaseBarcodesOutService {
    @Resource
    private BaseBarcodesOutMapper baseBarcodesOutMapper;

    @Resource
    RedisTemplate redisTemplate;

    @Autowired
    IBusinBillheadService iBusinBillheadService;

    @Autowired
    IBusinBillbodyService iBusinBillbodyService;

    @Autowired
    IBusinDataTaskService iBusinDataTaskService;

    @Autowired
    IBaseDeriveService iBaseDeriveService;
    @Autowired
    IBaseBarcodesInService iBaseBarcodesInService;

    @Autowired
    IBaseBarcodesOutService iBaseBarcodesOutService;

    @Autowired
    IBusinDataTaskService businDataTaskService;
    @Resource
    IWcsPlcPropertyService iWcsPlcPropertyService;


    @Autowired
    PlcInit plcInit;
    /**
     * 出库过点时间同步
     *
     * @param bos 出库过点信息
     * @return 出库条码信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ThirdYklResult thirdSyncBaseBarcodesOutPoint(List<BaseBarcodesOutThirdPointBo> bos) {
        List<BusinDataTask> taskList = new ArrayList<>();
        List<BusinBillhead> headList = new ArrayList<>();
        List<BaseBarcodesOut> barcodesList = new ArrayList<>();
        List<String> dateList = new ArrayList<>();
        HashMap<String, Object> resultMap = new HashMap<>();
        try {
            for (BaseBarcodesOutThirdPointBo bo : bos) {

                //获取所有的过点时间
                List<BaseBarcodesOutVo> traverseDateVos = baseBarcodesOutMapper.getTraverseDateInfoByTraverseDate(bo.getCorrectDate());
                for (BaseBarcodesOutVo traverseDateVo : traverseDateVos) {
                    LambdaQueryWrapper<BaseBarcodesOut> wrapper = new LambdaQueryWrapper<BaseBarcodesOut>()
                            .eq(BaseBarcodesOut::getTraverseDate, traverseDateVo.getTraverseDate())
                            .last("limit 1");
                    BaseBarcodesOut baseBarcodesOut = getOne(wrapper);
                    baseBarcodesOut.setCancel_time(new Date());
                    baseBarcodesOut.setIs_cancel("1");
                    barcodesList.add(baseBarcodesOut);

                    //根据过点时间处理正在执行的出库任务及出库单
                    //根据过点时间查询出库任务；
                    BusinDataTask businDataTask = iBusinDataTaskService.getBusinDataTaskByTraverseDate(DateUtils.parseDate(traverseDateVo.getTraverseDate()));
                    if (null != businDataTask && "0".equals(businDataTask.getTaskStatus())) {
                        //任务状态：修改为已取消
                        businDataTask.setTaskStatus("-4");
                        businDataTask.setUpdateTime(DateUtils.getNowDate());
                        businDataTask.setExceptionMsg("过点时间纠正作废");
                        taskList.add(businDataTask);
                    }

                    BusinBillhead businBillhead = iBusinBillheadService.getBusinBillHeadByTraverseDate(DateUtils.parseDate(traverseDateVo.getTraverseDate()));
                    if (null != businBillhead) {
                        businBillhead.setCancleDate(DateUtils.getNowDate());
                        businBillhead.setIsCancle("1");
                        headList.add(businBillhead);
                    }
                }

                dateList.add(bo.getCorrectDate().toString());
            }

            if (headList.size() > 0) {
                if (!iBusinBillheadService.saveBatch(headList)) {
                    return ThirdYklResult.error("同步出库业务更新失败");
                }
            }

            if (taskList.size() > 0) {
                if (!iBusinDataTaskService.saveBatch(taskList)) {
                    return ThirdYklResult.error("同步任务更新失败");
                }
            }
            if (barcodesList.size() > 0) {
                if (!iBaseBarcodesOutService.saveBatch(barcodesList)) {
                    return ThirdYklResult.error("同步VIN更新失败");
                }
            }
            resultMap.put("correctDate", dateList);
            return ThirdYklResult.ok().put("data", resultMap);

        } catch (Exception e) {
            return ThirdYklResult.error(e.getMessage());
        }
    }

    /**
     * 出库信息同步
     *
     * @param bos 出库信息
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ThirdYklResult thirdSyncBaseBarcodesOut(List<BaseBarcodesOutThirdSyncBo> bos) {
        List<BaseBarcodesOut> barcodesOutList = new ArrayList<>();
        List<String> vinOkList = new ArrayList<>();
        List<String> vinErrList = new ArrayList<>();

        for (BaseBarcodesOutThirdSyncBo bo : bos) {
            vinErrList.add(bo.getVin());
            //出库车辆队列信息
            BaseBarcodesOut baseBarcodesOut = (BaseBarcodesOut) redisTemplate.opsForValue().get(RedisConstant.redisVin + bo.getVin());
            if (baseBarcodesOut == null) {
                LambdaQueryWrapper<BaseBarcodesOut> wrapper = new LambdaQueryWrapper<BaseBarcodesOut>().eq(BaseBarcodesOut::getVin, bo.getVin()).last("limit 1");
                baseBarcodesOut = getOne(wrapper);
            }
            if (baseBarcodesOut == null) {
                vinOkList.add(bo.getVin());
                baseBarcodesOut = BeanUtil.toBean(bo, BaseBarcodesOut.class);
                baseBarcodesOut.setColor(bo.getColor().trim());
                baseBarcodesOut.setCreateTime(DateUtils.getNowDate());
                baseBarcodesOut.setBatch(DateUtils.getDate());
                baseBarcodesOut.setOutStatus("0");
//                //依柯力后面不在传入字段BumperType需要去派生表里拿到车型VehicheModel写入到出库信息表中
                BaseDerive one = iBaseDeriveService.getOne(new LambdaQueryWrapper<BaseDerive>()
                        .eq(BaseDerive::getVehicheCode, baseBarcodesOut.getVehicleCode())
                        .eq(BaseDerive::getColor, baseBarcodesOut.getColor())
                        .eq(BaseDerive::getDerive, baseBarcodesOut.getDerive()));
                if (ObjectUtils.isNotEmpty(one)) {
                    baseBarcodesOut.setBumperType(one.getVehicheModel());
                }
                barcodesOutList.add(baseBarcodesOut);
            } else {
                //是否把已存在的信息返回
            }
        }
        if (barcodesOutList.size() > 0) {
            if (this.saveBatch(barcodesOutList)) {
                for (BaseBarcodesOut baseBarcodesOut : barcodesOutList) {
                    redisTemplate.opsForValue().set(RedisConstant.redisVin + baseBarcodesOut.getVin(), baseBarcodesOut);
                }
                HashMap<String, Object> resultMap = new HashMap<>();
                resultMap.put("arr", vinOkList);
                return ThirdYklResult.ok("同步车辆队列信息").put("data", resultMap);
            } else {
                return ThirdYklResult.error().put("data", vinErrList);
            }
        } else {
            return ThirdYklResult.error("已同步");
        }
    }

    @Override
    public List<BaseBarcodesOutVo> getBarcodesOutData(BaseBarcodesOutQueryBo bo) {
        return this.baseBarcodesOutMapper.getBarcodesOutData(bo);
    }

    @Override
    public List<BaseBarcodesOutVo> getBarcodesnoOutData() {
        return this.baseMapper.getBarcodesnoOutData();
    }

    @Override
    public List<BaseBarcodesOutAddBo> selectVinOutboundList(BaseBarcodesOutQueryBo bo) {
        return baseMapper.selectVinOutboundList(bo);
    }

    @Override
    public BaseBarcodesOutAddBo selectVinOutboundListOne(BaseBarcodesOutQueryBo bo) {
        return baseMapper.selectVinOutboundListOne(bo);
    }

    @Override
    public List<BaseBarcodesOutTaskVo> getBarcodesOutDataTaskInfo(BaseBarcodesOutQueryBo bo) {
         return baseMapper.selectBarcodesOutDataTaskInfo(bo);
    }

    @Override
    public List<BaseBarcodesOutVo> getBarcodesOutDataTaskInfoDetail(BaseBarcodesOutQueryBo bo) {
        return baseMapper.selectBarcodesOutDataTaskInfoDetail(bo);
    }


    /**
     * 手动下发出库任务  --已过过点时间是否还可以下发
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> handMoveOutboundInfoTask(BaseBarcodesOutQueryBo bo){
        //根据条件查询带出的出库队列
        List<BaseBarcodesOutAddBo> barcodesOutList = iBaseBarcodesOutService.selectVinOutboundList(bo);
        return businDataTaskService.insertBusinTask(barcodesOutList);
    }

    /**
     * 切换出库方式
     * @author Comair
     * @date 2023/8/12 15:24
     * @param status
     * @return com.shkj.common.core.domain.Result<java.lang.Boolean>
     */
    @Override
    public Result<Boolean> handOutboundStatus(String status){
        redisTemplate.opsForValue().set(RedisConstant.out_plan_type,status);
        return Result.ok();
    }

    @Override
    public Result<Boolean> handOutEmptyStatus(String status){
        redisTemplate.opsForValue().set(RedisConstant.out_empty_type,status);

        //根据plcId获取plc信息
        WcsPlcConnect wcsplc = BeanUtil.toBean(redisTemplate.opsForValue().get(RedisConstant.redisPlcConnect + 30L),WcsPlcConnect.class);

        List<WcsPlcProperty> propertyList = iWcsPlcPropertyService.getWcsPlcPropertyByPlcId(30L);
        String writeTaskId = "";
        String valueType = "";
        for (WcsPlcProperty wcsPlcProperty : propertyList) {
            //AGV取走完成
            if (wcsPlcProperty.getPointType().equals("13")) {
                writeTaskId = wcsPlcProperty.getAddress();
                valueType = wcsPlcProperty.getValueType();
            }
        }
        Map<String, Object> writeMap = new HashMap<>(1);
        writeMap.put(valueType, "开启".equals(status) ? true : false);
        Map<String, Object> allMap = new HashMap<>(1);
        allMap.put(writeTaskId, writeMap);

        PlcOperate plcOperate = plcInit.getPlcOperateByIp(wcsplc.getPlcIp());

        PLCReadAndWrite plcReadAndWrite = new PLCReadAndWrite();

        plcReadAndWrite.execWrite(plcOperate, JsonUtil.toJSONString(allMap));

        return Result.ok();
    }

    @Override
    public Result<Boolean> handOutboundInfoTask(String vin,String status){
        // 添加手动下发任务的开始任务  并且从该任务起定时生成任务
        if("start".equals(status)){
            if (ObjectUtils.isEmpty(redisTemplate.opsForValue().get(RedisConstant.startTaskVin))) {
                redisTemplate.opsForValue().set(RedisConstant.startTaskVin,vin);
                BaseBarcodesOutQueryBo baseBarcodesOutQueryBo = new BaseBarcodesOutQueryBo();
                baseBarcodesOutQueryBo.setVin(vin);
                BaseBarcodesOut baseBarcodesOut = iBaseBarcodesOutService.getOne(new LambdaQueryWrapper<BaseBarcodesOut>().eq(BaseBarcodesOut::getVin,vin));
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String temp = sdf.format(baseBarcodesOut.getTraverseDate());
                this.baseBarcodesOutMapper.updateBeforeBytraverseDate(temp);
                //TODO 出库一个任务的时候启用。其余情况都注释掉
//                redisTemplate.opsForValue().set(RedisConstant.endTaskVin,vin);
            }
        }else if("end".equals(status)){
            redisTemplate.opsForValue().set(RedisConstant.endTaskVin,vin);
        }
        return Result.ok();
    }
    /**
     * 手动下发出库任务 -暂停
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> handMoveOutboundInfoTaskForPause(BaseBarcodesOutQueryBo bo) {
        //查询需暂停的出库队列（状态为：待出库）
        bo.setOutStatus("1");
        List<BaseBarcodesOutAddBo> barcodesOutList = iBaseBarcodesOutService.selectVinOutboundList(bo);

        return null;
    }

    /**
     * 手动下发出库任务-取消
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> handMoveOutboundInfoTaskForCancel(BaseBarcodesOutQueryBo bo) {
        //查询需暂停的出库队列（状态为：待出库） 取消：暂停的是否可以取消
        bo.setOutStatus("1");
        List<BaseBarcodesOutAddBo> barcodesOutList = iBaseBarcodesOutService.selectVinOutboundList(bo);
        return null;
    }

    @Override
    public List<Map<String,String>> getOutEmptyInfo(){
        return this.baseMapper.getOutEmptyInfo();
    }


    /**
     * 手动下发出库任务-恢复 ：暂停 ，已取消是否是作废，不可恢复 ； 2出库中 给堆垛机下发命令成功，更改状态
     * @param bo
     * @return
     */


    /**
     * 筛选订单为一个整体的货位信息
     *
     * @param AllLocation
     * @return
     */
    public List<String> getGlobalityData(List<String> AllLocation) {
        Map<String, Long> collect = AllLocation.stream().collect(Collectors.groupingBy(p -> p, Collectors.counting()));
        List<String> list = collect.entrySet().stream().filter(e -> e.getValue() >= 3).map(Map.Entry::getKey).collect(Collectors.toList());
        return list;
    }

    /**
     * 修改出货表状态
     *
     * @param vo
     * @return
     */
    public Result<Boolean> updateStatus(BaseBarcodesOutVo vo) {
        BaseBarcodesOut baseBarcodesOut = BeanUtil.toBean(vo, BaseBarcodesOut.class);
        this.baseMapper.updateById(baseBarcodesOut);
        return Result.ok();
    }



}
