package com.njcn.quality.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;


import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.tocrhz.mqtt.publisher.MqttPublisher;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.db.constant.DbConstant;
import com.njcn.job.api.JobFeignClient;
import com.njcn.job.model.XxlJobInfo;
import com.njcn.quality.enums.EnergyResponseEnum;
import com.njcn.quality.mapper.AirStrategyMapper;
import com.njcn.quality.mapper.LogicDeviceLineMapper;
import com.njcn.quality.param.AirStrategyParam;
import com.njcn.quality.pojo.dto.AirStrategyDTO;
import com.njcn.quality.pojo.dto.NetAndDevByLineDTO;
import com.njcn.quality.pojo.po.AirSet;
import com.njcn.quality.pojo.po.AirStrategy;
import com.njcn.quality.pojo.vo.AirStrategyVO;
import com.njcn.quality.service.EleAirStrategyService;
import com.njcn.quality.service.IEleSetService;
import com.njcn.web.factory.PageFactory;
import com.njcn.web.utils.RequestUtil;
import com.xxl.job.core.biz.model.ReturnT;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * pqs
 *
 * @author cdf
 * @date 2022/4/21
 */
@Service
@RequiredArgsConstructor
public class EleAirStrategyServiceImpl extends ServiceImpl<AirStrategyMapper,AirStrategy> implements EleAirStrategyService {

    private final IEleSetService iEleSetService;

    private final JobFeignClient jobFeignClient;

    private final LogicDeviceLineMapper logicDeviceLineMapper;


    private final MqttPublisher publisher;

    private final AirStrategyMapper airStrategyMapper;


    @Override
    public Page<AirStrategy> listAirStrategy(AirStrategyParam.AirStrategyQueryParam queryParam) {
        QueryWrapper<AirStrategy> queryWrapper = new QueryWrapper<>();
        if(Objects.nonNull(queryParam)){
            //查询参数不为空，进行条件填充
            if(StrUtil.isNotBlank(queryParam.getSearchValue())){
                //字典类型表，仅提供名称、编码模糊查询
                queryWrapper
                        .and(param -> param.like("ele_air_strategy.name",queryParam.getSearchValue()));
            }

            //排序
            if (ObjectUtil.isAllNotEmpty(queryParam.getSortBy(), queryParam.getOrderBy())) {
                queryWrapper.orderBy(true, queryParam.getOrderBy().equals(DbConstant.ASC), StrUtil.toUnderlineCase(queryParam.getSortBy()));
            }else{
                //没有排序参数，默认根据sort字段排序，没有排序字段的，根据updateTime更新时间排序
                queryWrapper.orderBy(true, true, "ele_air_strategy.sort");
            }

        }
        queryWrapper.eq("ele_air_strategy.state", DataStateEnum.ENABLE.getCode());
        return this.baseMapper.selectPage(new Page<>(PageFactory.getPageNum(queryParam),PageFactory.getPageSize(queryParam)),queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addAirStrategy(AirStrategyParam airStrategyParam) {
        checkDicTypeName(airStrategyParam,false);
        AirStrategy airStrategy = new AirStrategy();
        BeanUtils.copyProperties(airStrategyParam, airStrategy);
        airStrategy.setState(DataStateEnum.ENABLE.getCode());
        airStrategy.setStatus(0);
        airStrategy.setCreateBy(RequestUtil.getUserIndex());
        airStrategy.setCreateTime(LocalDateTime.now());
        airStrategy.setUpdateTime(LocalDateTime.now());
        this.save(airStrategy);




        List<AirSet> list = new ArrayList<>();
        airStrategyParam.getLineIds().forEach((item)->{
            AirSet airSet = new AirSet(airStrategy.getId(),item);
            list.add(airSet);
        });
        iEleSetService.saveBatch(list);



        /*
         * 此处做示例，手动指定
         */
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        //执行器ID，手动指定，此处设置为3，对应xxl_job_group中的executor--测试执行器
        xxlJobInfo.setJobGroup(5);
        //任务描述
        xxlJobInfo.setJobDesc("开启空调");
        xxlJobInfo.setAuthor("cdf");
        xxlJobInfo.setScheduleType("CRON");
        //时间表达式需要处理成 秒 分 时 日 月 ？ 年，标志指定时间执行一次
        LocalDateTime startTime = LocalDateTimeUtil.parse(airStrategy.getStartTime(), DatePattern.NORM_DATETIME_PATTERN);
        xxlJobInfo.setScheduleConf("" + startTime.getSecond() + CharUtil.SPACE + startTime.getMinute() + CharUtil.SPACE + startTime.getHour() + CharUtil.SPACE + startTime.getDayOfMonth() + CharUtil.SPACE + startTime.getMonthValue() + CharUtil.SPACE + "?" + CharUtil.SPACE + startTime.getYear());
        xxlJobInfo.setMisfireStrategy("DO_NOTHING");
        xxlJobInfo.setExecutorRouteStrategy("FIRST");
        xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
        //指定处理器
        xxlJobInfo.setExecutorHandler("airStrategyJob");
        //传递的参数
        xxlJobInfo.setExecutorParam("open"+StrUtil.C_COMMA+airStrategy.getId());
        xxlJobInfo.setGlueType("BEAN");
        xxlJobInfo.setGlueRemark("GLUE代码初始化");
        HttpResult result = jobFeignClient.addJob(xxlJobInfo);
        if(result.getCode().equals(ReturnT.FAIL_CODE)){
            throw new BusinessException(EnergyResponseEnum.TASK_CREATE_ERROR);
        }

        /*
         * 此处做示例，手动指定
         */
        XxlJobInfo xxlJobInfoEnd = new XxlJobInfo();
        //执行器ID，手动指定，此处设置为3，对应xxl_job_group中的executor--测试执行器
        xxlJobInfoEnd.setJobGroup(5);
        //任务描述
        xxlJobInfoEnd.setJobDesc("关闭空调");
        xxlJobInfoEnd.setAuthor("cdf");
        xxlJobInfoEnd.setScheduleType("CRON");
        //时间表达式需要处理成 秒 分 时 日 月 ？ 年，标志指定时间执行一次
        LocalDateTime startTimeEnd = LocalDateTimeUtil.parse(airStrategy.getEndTime(), DatePattern.NORM_DATETIME_PATTERN);
        xxlJobInfoEnd.setScheduleConf("" + startTimeEnd.getSecond() + CharUtil.SPACE + startTimeEnd.getMinute() + CharUtil.SPACE + startTimeEnd.getHour() + CharUtil.SPACE + startTimeEnd.getDayOfMonth() + CharUtil.SPACE + startTimeEnd.getMonthValue() + CharUtil.SPACE + "?" + CharUtil.SPACE + startTimeEnd.getYear());
        xxlJobInfoEnd.setMisfireStrategy("DO_NOTHING");
        xxlJobInfoEnd.setExecutorRouteStrategy("FIRST");
        xxlJobInfoEnd.setExecutorBlockStrategy("SERIAL_EXECUTION");
        //指定处理器
        xxlJobInfoEnd.setExecutorHandler("airStrategyJob");
        //传递的参数
        xxlJobInfoEnd.setExecutorParam("close"+StrUtil.C_COMMA+airStrategy.getId());
        xxlJobInfoEnd.setGlueType("BEAN");
        xxlJobInfoEnd.setGlueRemark("GLUE代码初始化");
        HttpResult result2 = jobFeignClient.addJob(xxlJobInfoEnd);

        if(result2.getCode().equals(ReturnT.FAIL_CODE)){
            throw new BusinessException(EnergyResponseEnum.TASK_CREATE_ERROR);
        }



        String ids = result.getData().toString()+StrUtil.COMMA+result2.getData().toString();
        airStrategy.setXxlId(ids);
        this.updateById(airStrategy);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateAirStrategy(AirStrategyParam.AirUpdateParam updateParam) {
        AirStrategy airStrategyRes = this.getById(updateParam.getId());
        if(Objects.isNull(airStrategyRes)){
            throw new BusinessException(CommonResponseEnum.FAIL);
        }
        checkDicTypeName(updateParam,true);
        AirStrategy airStrategy = new AirStrategy();
        BeanUtils.copyProperties(updateParam, airStrategy);
        airStrategy.setUpdateBy(RequestUtil.getUserIndex());
        airStrategy.setUpdateTime(LocalDateTime.now());
        this.updateById(airStrategy);


        iEleSetService.removeById(airStrategy.getId());

        List<AirSet> list = new ArrayList<>();
        updateParam.getLineIds().forEach((item)->{
            AirSet airSet = new AirSet(airStrategy.getId(),item);
            list.add(airSet);
        });
        iEleSetService.saveBatch(list);
        /*
         * 此处做示例，手动指定
         */
       String[] jobIds = airStrategyRes.getXxlId().split(StrUtil.COMMA);
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        //执行器ID，手动指定，此处设置为3，对应xxl_job_group中的executor--测试执行器
        xxlJobInfo.setId(Integer.parseInt(jobIds[0]));
        xxlJobInfo.setJobGroup(5);
        //任务描述
        xxlJobInfo.setJobDesc("开启空调");
        xxlJobInfo.setAuthor("cdf");
        xxlJobInfo.setScheduleType("CRON");
        //时间表达式需要处理成 秒 分 时 日 月 ？ 年，标志指定时间执行一次
        LocalDateTime startTime = LocalDateTimeUtil.parse(airStrategy.getStartTime(), DatePattern.NORM_DATETIME_PATTERN);
        xxlJobInfo.setScheduleConf("" + startTime.getSecond() + CharUtil.SPACE + startTime.getMinute() + CharUtil.SPACE + startTime.getHour() + CharUtil.SPACE + startTime.getDayOfMonth() + CharUtil.SPACE + startTime.getMonthValue() + CharUtil.SPACE + "?" + CharUtil.SPACE + startTime.getYear());
        xxlJobInfo.setMisfireStrategy("DO_NOTHING");
        xxlJobInfo.setExecutorRouteStrategy("FIRST");
        xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
        //指定处理器
        xxlJobInfo.setExecutorHandler("airStrategyJob");
        //传递的参数
        xxlJobInfo.setExecutorParam("open"+StrUtil.C_COMMA+airStrategy.getId());
        xxlJobInfo.setGlueType("BEAN");
        xxlJobInfo.setGlueRemark("GLUE代码初始化");
        HttpResult result = jobFeignClient.updateJob(xxlJobInfo);
        if(result.getCode().equals(ReturnT.FAIL_CODE)){
            throw new BusinessException(EnergyResponseEnum.TASK_CREATE_ERROR);
        }

        /*
         * 此处做示例，手动指定
         */
        XxlJobInfo xxlJobInfoEnd = new XxlJobInfo();
        xxlJobInfoEnd.setId(Integer.parseInt(jobIds[1]));
        //执行器ID，手动指定，此处设置为3，对应xxl_job_group中的executor--测试执行器
        xxlJobInfoEnd.setJobGroup(5);
        //任务描述
        xxlJobInfoEnd.setJobDesc("关闭空调");
        xxlJobInfoEnd.setAuthor("cdf");
        xxlJobInfoEnd.setScheduleType("CRON");
        //时间表达式需要处理成 秒 分 时 日 月 ？ 年，标志指定时间执行一次
        LocalDateTime startTimeEnd = LocalDateTimeUtil.parse(airStrategy.getEndTime(), DatePattern.NORM_DATETIME_PATTERN);
        xxlJobInfoEnd.setScheduleConf("" + startTimeEnd.getSecond() + CharUtil.SPACE + startTimeEnd.getMinute() + CharUtil.SPACE + startTimeEnd.getHour() + CharUtil.SPACE + startTimeEnd.getDayOfMonth() + CharUtil.SPACE + startTimeEnd.getMonthValue() + CharUtil.SPACE + "?" + CharUtil.SPACE + startTimeEnd.getYear());
        xxlJobInfoEnd.setMisfireStrategy("DO_NOTHING");
        xxlJobInfoEnd.setExecutorRouteStrategy("FIRST");
        xxlJobInfoEnd.setExecutorBlockStrategy("SERIAL_EXECUTION");
        //指定处理器
        xxlJobInfoEnd.setExecutorHandler("airStrategyJob");
        //传递的参数
        xxlJobInfoEnd.setExecutorParam("close"+StrUtil.C_COMMA+airStrategy.getId());
        xxlJobInfoEnd.setGlueType("BEAN");
        xxlJobInfoEnd.setGlueRemark("GLUE代码初始化");
        HttpResult result2 = jobFeignClient.updateJob(xxlJobInfoEnd);

        if(result2.getCode().equals(ReturnT.FAIL_CODE)){
            throw new BusinessException(EnergyResponseEnum.TASK_CREATE_ERROR);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteAirStrategy(String id) {
        AirStrategy airStrategy = this.getById(id);
        if(Objects.isNull(airStrategy)){
            return true;
        }

        if(airStrategy.getStatus() == 1){
            throw new BusinessException(EnergyResponseEnum.TASK_RUNING);
        }

         this.lambdaUpdate()
                .set(AirStrategy::getState, DataStateEnum.DELETED.getCode())
                .eq(AirStrategy::getId,id)
                .update();

         LambdaQueryWrapper<AirSet> lambdaQueryWrapper = new LambdaQueryWrapper<>();
         lambdaQueryWrapper.eq(AirSet::getId,id);
         iEleSetService.remove(lambdaQueryWrapper);

         String[] arr = airStrategy.getXxlId().split(StrUtil.COMMA);

         for(String xxlId : arr){
            HttpResult<String> result = jobFeignClient.removeJob(Integer.parseInt(xxlId));
             if(result.getCode().equals(StrUtil.toString(ReturnT.FAIL_CODE))){
                 throw new BusinessException(EnergyResponseEnum.TASK_DEL_ERROR);
             }
         }

         return true;
    }



    @Override
    public AirStrategyVO findById(String id) {
        AirStrategy airStrategy =  this.lambdaQuery().eq(AirStrategy::getId,id).one();
        if(Objects.isNull(airStrategy)){
            throw new BusinessException(CommonResponseEnum.NO_DATA);
        }
        List<AirSet> list = iEleSetService.lambdaQuery().eq(AirSet::getId,id).list();
        List<String> lineIds = list.stream().map(AirSet::getLineId).collect(Collectors.toList());

        AirStrategyVO airStrategyVO = new AirStrategyVO();
        BeanUtils.copyProperties(airStrategy,airStrategyVO);
        airStrategyVO.setLineIds(lineIds);
        return airStrategyVO;
    }

    @Override
    public boolean startAirStrategy(String id){
       AirStrategy airStrategy = getById(id);
       if(Objects.isNull(airStrategy)){
           throw new BusinessException(CommonResponseEnum.FAIL);
       }
        String[] ids = airStrategy.getXxlId().split(StrUtil.COMMA);
       if(airStrategy.getStatus() == 0){
           //可以启动

           for(String xxlId : ids){
               HttpResult<String> result =jobFeignClient.startTask(Integer.parseInt(xxlId));
               if(result.getCode().equals(StrUtil.toString(ReturnT.FAIL_CODE))){
                   throw new BusinessException(EnergyResponseEnum.TASK_RUNING);
               }
           }


           this.lambdaUpdate().set(AirStrategy::getStatus,1).eq(AirStrategy::getId,id).update();

       }else if(airStrategy.getStatus() == 1){
           //已经执行中

           for(String xxlId : ids){
               HttpResult<String> result =jobFeignClient.stopJob(Integer.parseInt(xxlId));
               if(result.getCode().equals(StrUtil.toString(ReturnT.FAIL_CODE))){
                   throw new BusinessException(EnergyResponseEnum.TASK_DEL_ERROR);
               }
           }
           this.lambdaUpdate().set(AirStrategy::getStatus,0).eq(AirStrategy::getId,id).update();
       }else {
           //已经完成
           throw new BusinessException(EnergyResponseEnum.TASK_HAS_START);
       }

       return true;
    }


    @Override
    public boolean dealAirStrategyId(String id,String operation){
        AirStrategy airStrategy = this.getById(id);
        if(Objects.isNull(airStrategy)){
            throw new BusinessException(CommonResponseEnum.FAIL);
        }
        LambdaQueryWrapper<AirSet> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(AirSet::getId,id);
        List<AirSet> list = iEleSetService.list(lambdaQueryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
          List<String> lineIds =  list.stream().map(AirSet::getLineId).collect(Collectors.toList());
           List<NetAndDevByLineDTO> netDevList = logicDeviceLineMapper.getNetAndDevByLineIds(lineIds);


           if(CollectionUtil.isNotEmpty(netDevList)){
               for(NetAndDevByLineDTO netAndDevByLineDTO: netDevList){

                   Gson gson = new Gson();
                   String array = "ACInStat";
                   String power ="";
                   if("open".equals(operation)){
                       //开启空调
                       for(int i=0;i<4;i++){
                           if(i== 0){
                               power = "On";
                               array = "ACInStat";
                           }else if(i==1){
                               power = airStrategy.getTemperature().toString();
                               array = "ACInSetTmp";
                           }else if(i== 2){
                               power = airStrategy.getMode();
                               array = "ACInMode";
                           }else {
                               power = airStrategy.getWind();
                               array = "ACInSpeed";
                           }
                           AirStrategyDTO airStrategyDTO = new AirStrategyDTO();
                           airStrategyDTO.setMid(1);
                           airStrategyDTO.setDeviceId(netAndDevByLineDTO.getDevId());
                           airStrategyDTO.setTimestamp(Calendar.getInstance().getTimeInMillis());
                           airStrategyDTO.setExpire(-1);
                           airStrategyDTO.setType("CMD_DEV_CTRL");
                           AirStrategyDTO.Param param = new AirStrategyDTO.Param();
                           param.setLineId(netAndDevByLineDTO.getLineId());
                           param.setAction(array);
                           param.setParm(power);
                           airStrategyDTO.setParam(param);
                           String json = gson.toJson(airStrategyDTO);
                           System.out.println(json);
                           String topic = "/platform/devcmd/v1/"+netAndDevByLineDTO.getNdid();
                           publisher.send(topic,json,1,false);
                           try {
                               Thread.sleep(8000);
                               System.out.println("睡了8s");
                           } catch (InterruptedException e) {
                               e.printStackTrace();
                           }
                       }
                   }else {
                       //关闭空调
                       power = "Off";
                       AirStrategyDTO airStrategyDTO = new AirStrategyDTO();
                       airStrategyDTO.setMid(1);
                       airStrategyDTO.setDeviceId(netAndDevByLineDTO.getDevId());
                       airStrategyDTO.setTimestamp(Calendar.getInstance().getTimeInMillis());
                       airStrategyDTO.setExpire(-1);
                       airStrategyDTO.setType("CMD_DEV_CTRL");
                       AirStrategyDTO.Param param = new AirStrategyDTO.Param();
                       param.setLineId(netAndDevByLineDTO.getLineId());
                       param.setAction(array);
                       param.setParm(power);
                       airStrategyDTO.setParam(param);
                       String json = gson.toJson(airStrategyDTO);
                       System.out.println(json);
                       String topic = "/platform/devcmd/v1/"+netAndDevByLineDTO.getNdid();
                       publisher.send(topic,json,1,false);


                   }



                   try {
                       Thread.sleep(8000);
                       System.out.println("切换监测点睡了5s");
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }

               System.out.println(operation);
               if(operation.equals("close")){
                   AirStrategy air = new AirStrategy();
                   air.setId(airStrategy.getId());
                   air.setStatus(2);
                   airStrategyMapper.updateById(air);
               }
           }

        }


        return true;
    }



    /**
     * 校验参数，检查是否存在相同名称的字典类型
     */
    private void checkDicTypeName(AirStrategyParam airStrategyParam, boolean isExcludeSelf) {
        LambdaQueryWrapper<AirStrategy> netDevLambdaQueryWrapper = new LambdaQueryWrapper<>();
        netDevLambdaQueryWrapper
                .eq(AirStrategy::getName,airStrategyParam.getName())
                .eq(AirStrategy::getState,DataStateEnum.ENABLE.getCode());
        //更新的时候，需排除当前记录
        if(isExcludeSelf){
            if(airStrategyParam instanceof AirStrategyParam.AirUpdateParam){
                netDevLambdaQueryWrapper.ne(AirStrategy::getId,((AirStrategyParam.AirUpdateParam) airStrategyParam).getId());
            }
        }
        int countByAccount = this.count(netDevLambdaQueryWrapper);
        //大于等于1个则表示重复
        if (countByAccount >= 1) {
            throw new BusinessException(EnergyResponseEnum.NET_DEV_NAME_REPEAT);
        }
    }

}
