package com.ho.filecenter.controller;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.ho.business.entity.PlanCurveOperationRecordReq;
import com.ho.business.vo.req.DeviceReqVO;
import com.ho.business.vo.req.point.PointReq;
import com.ho.business.vo.resp.DeviceRespVO;
import com.ho.business.vo.resp.point.PointRespVO;
import com.ho.common.tools.annotation.TokenIgnore;
import com.ho.common.tools.constant.CommonConstant;
import com.ho.common.tools.constant.ContextConstant;
import com.ho.common.tools.constant.RedisKeyConstant;
import com.ho.common.tools.exception.BaseResponseCode;
import com.ho.common.tools.exception.BusinessException;
import com.ho.common.tools.exception.DataResult;
import com.ho.common.tools.service.RedisService;
import com.ho.common.tools.util.PageResult;
import com.ho.common.tools.util.TranslateUtils;
import com.ho.filecenter.feignclient.BusinessFeignClient;
import com.ho.filecenter.feignclient.UserFeignClient;
import com.ho.filecenter.service.AnotherOrderSendService;
import com.ho.filecenter.service.OrderSendService;
import com.ho.filecenter.util.MqttConfigUtil;
import com.ho.filecenter.vo.mqtt.*;
import com.ho.filecenter.vo.resp.HeartbeatResp;
import com.ho.filecenter.vo.resp.OrderProcessDetailResp;
import com.ho.filecenter.vo.resp.OrderProcessResp;
import com.ho.user.api.vo.req.SysSubDictVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Description 指令下发
 * Author xueweizhi
 * Date 2023/3/15 12:10
 */
@RestController
@RequestMapping(ContextConstant.MEDIA_CONTEXT + "orderSend")
@Api(tags = "指令下发")
@Slf4j
public class OrderSendController {

    @Autowired
    BusinessFeignClient businessFeignClient;

    @Autowired
    RedisService redisService;

    @Autowired
    OrderSendService orderSendService;

    @Autowired
    UserFeignClient userFeignClient;

    @Autowired
    AnotherOrderSendService anotherOrderSendService;

    public static final Long TIME_LIMIT = 90L;

    @PostMapping("orderIssued")
    @ApiOperation(value = "指令下发")
    //@HzPermission(value = {PermissionConstant.REMOTECONTROL_COMMAND_BATCHDISTRIBUTION,PermissionConstant.STRATEGY_PLANCURVEDIS_COMMANDISSUANCE,PermissionConstant.REMOTECONTROL_COMMAND_SINGLEREFRESH})
//    @LogAnnotation(title = "命令下发", action = "指令下发")
    public DataResult<HeartbeatResp> orderIssued(@RequestBody OrderIssuedReqVO vo, HttpServletRequest request) {
//        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
//        UserDetailRespVO userDetailRespVO = redisService.getUserDetailByToken(token);
//        String userName = userDetailRespVO.getUsername();
//        String userNameKey = redisService.getUserNameKey(userDetailRespVO, userName);
//        SimpleUser user = (SimpleUser) redisService.get(userNameKey);
        String lang = request.getHeader(CommonConstant.LANG);
        DataResult result = getDataResult(vo);
        if(CommonConstant.langTemp.EN_US.equals(lang)){
            HeartbeatResp heartbeatResp= (HeartbeatResp)result.getData();
            heartbeatResp.setMsg(TranslateUtils.translate(heartbeatResp.getMsg(),CommonConstant.lang.EN));
        }
        return result;
    }

    @NotNull
    private DataResult getDataResult(OrderIssuedReqVO vo) {
        HeartbeatResp heartbeatResp = new HeartbeatResp();
        if (vo.getList() == null || vo.getList().isEmpty() ) {
            throw new BusinessException(BaseResponseCode.DATA_NOT_EXISTS);
        }

        //组装计划曲线下发记录参数
        PlanCurveOperationRecordReq planCurveOperationRecordReq = new PlanCurveOperationRecordReq();
        planCurveOperationRecordReq.setUserId(vo.getUserId());
        if(vo.getPlanTemId() != null){
            planCurveOperationRecordReq.setLatestPlanningCurve(String.valueOf(vo.getPlanTemId()));
        }
        planCurveOperationRecordReq.setOperateTime(DateUtil.format(new Date(),CommonConstant.DATE));
        Integer stationId = vo.getList().get(0).getStationId();
        planCurveOperationRecordReq.setStationId(stationId);

        String orderUsingKey = stationId + ":" + RedisKeyConstant.ORDER_USING;
        DeviceReqVO deviceReqVO = new DeviceReqVO();
        deviceReqVO.setStationId(stationId);
        deviceReqVO.setSrcId(vo.getList().get(0).getSrcId());
        List<DeviceRespVO> deviceList = businessFeignClient.getDeviceSN(deviceReqVO);
        if (deviceList.size() == 0) {
            log.info("当前设备没有配置SN");
            heartbeatResp.setHeartbeatStatus(CommonConstant.ZERO);
            heartbeatResp.setMsg(CommonConstant.DEVICE_NO_SN);
            planCurveOperationRecordReq.setOperateResult(CommonConstant.DEVICE_NO_SN);
            planCurveOperationRecordReq.setStatus(0);
            //保存操作记录信息
            DataResult result = businessFeignClient.planCurveOperationRecord(planCurveOperationRecordReq);
            return DataResult.success(heartbeatResp);
        }
        String sn = deviceList.get(0).getSerialNo();
        vo.setSn(sn);
        //检测心跳
        String heartbeatKey = RedisKeyConstant.HEARTBEAT + sn;
        String msg = CommonConstant.Heartbeat.MSG + sn;
        //校验修改值范围
        Boolean checkValueFlag = false;
        List<OrderIssuedVO> list = vo.getList();
        for (OrderIssuedVO orderIssuedVO : list) {
            if (orderIssuedVO.getMaxValue().compareTo(orderIssuedVO.getModifyValue()) < 0 || orderIssuedVO.getMinValue().compareTo(orderIssuedVO.getModifyValue()) > 0) {
                log.info("修改值不符合要求");
                checkValueFlag = true;
                break;
            }
        }
        if (checkValueFlag) {
            //将值校验放在心跳检测中一起返回，如果校验不符合要求，则返回心跳为0，便于前端停止循环调用
            heartbeatResp.setHeartbeatStatus(CommonConstant.ZERO);
            heartbeatResp.setMsg(CommonConstant.CHECK_MODIFY_VALUE);
            planCurveOperationRecordReq.setOperateResult(CommonConstant.CHECK_MODIFY_VALUE);
            planCurveOperationRecordReq.setStatus(0);
            //保存操作记录信息
            DataResult result = businessFeignClient.planCurveOperationRecord(planCurveOperationRecordReq);
            return DataResult.success(heartbeatResp);
        }
        if (redisService.hasKey(heartbeatKey)) {
            Map<Object, Object> hgetall = redisService.hgetall(heartbeatKey);
            Date updateTime = (Date) hgetall.get(CommonConstant.UPDATE_TIME);
            Date date = new Date();
            long between = DateUtil.between(updateTime, date, DateUnit.MINUTE);
            if (between >= 5) {
                heartbeatResp.setHeartbeatStatus(CommonConstant.ZERO);
                log.info("orderIssued 命令下发超过5分钟没有检测到心跳：{}", between);
                heartbeatResp.setMsg(msg + CommonConstant.Heartbeat.FAIL);
                planCurveOperationRecordReq.setStatus(0);
                planCurveOperationRecordReq.setOperateResult(msg + CommonConstant.Heartbeat.FAIL);
                //保存操作记录信息
                DataResult result = businessFeignClient.planCurveOperationRecord(planCurveOperationRecordReq);
                return DataResult.success(heartbeatResp);
            }
            heartbeatResp.setMsg(msg + CommonConstant.Heartbeat.SUCCESS);
            heartbeatResp.setHeartbeatStatus(CommonConstant.ONE);
            if (redisService.hasKey(orderUsingKey)) {
                heartbeatResp.setMsg(BaseResponseCode.ORDER_IS_USING.getMsg());
                planCurveOperationRecordReq.setStatus(0);
                planCurveOperationRecordReq.setOperateResult(BaseResponseCode.ORDER_IS_USING.getMsg());
                //保存操作记录信息
                DataResult result = businessFeignClient.planCurveOperationRecord(planCurveOperationRecordReq);
                return DataResult.success(heartbeatResp);
            }
            log.info("指令下发正常开始下发");
            orderSendService.orderIssued(vo);
            if(vo.getPlanTemId() != null){
                String hourValue ="";
                String minuteValue ="";
                String hourCol ="";
                String minuteCol ="";
                //获取计划曲线执行测点数据
                PointReq pointReq = new PointReq();
                pointReq.setName("计划曲线每日刷新时间");
                pointReq.setStationId(stationId);
                pointReq.setSrcId(vo.getList().get(0).getSrcId());
                DataResult<PageResult<PointRespVO>> timeList = new DataResult<>();
                timeList = businessFeignClient.page(pointReq);
                for(PointRespVO pointRespVO:timeList.getData().getList()){
                    if(pointRespVO.getColName().contains("(时0-23)")){
                        hourValue = String.valueOf(pointRespVO.getValue());
                        hourValue = hourValue.substring(0,hourValue.indexOf("."));
                        hourCol = pointRespVO.getCol();
                    }else{
                        minuteValue = String.valueOf(pointRespVO.getValue());
                        minuteValue = minuteValue.substring(0,minuteValue.indexOf("."));
                        minuteCol = pointRespVO.getCol();
                    }
                }
                if(vo.getList().size()<62){
                    for(OrderIssuedVO orderIssuedVO:vo.getList()){
                        if(orderIssuedVO.getCol().equals(hourCol)){
                            hourValue = orderIssuedVO.getModifyValue().toString();
                        }else if(orderIssuedVO.getCol().equals(minuteCol)){
                            minuteValue = orderIssuedVO.getModifyValue().toString();
                        }
                    }
                }
                minuteValue = "".equals(minuteValue)?"00":minuteValue;
                Calendar calendar = Calendar.getInstance();
                calendar.set(Calendar.HOUR_OF_DAY,"".equals(hourValue)?CommonConstant.ZERO:Integer.valueOf(hourValue));
                calendar.set(Calendar.MINUTE,Integer.valueOf(minuteValue));
                calendar.set(Calendar.SECOND,CommonConstant.ZERO);
                int a =  DateUtil.compare(new Date(),DateUtil.parse(hourValue+":"+minuteValue),CommonConstant.DATE_Hm);
                if(a== 1){
                    calendar.add(Calendar.DATE,1);
                }
                planCurveOperationRecordReq.setEffectiveTime(DateUtil.format(calendar.getTime(),CommonConstant.DATE));
                planCurveOperationRecordReq.setStatus(1);
                planCurveOperationRecordReq.setOperateResult("成功下发");
                //保存操作记录信息
                DataResult result = businessFeignClient.planCurveOperationRecord(planCurveOperationRecordReq);
            }
            return DataResult.success(heartbeatResp);
        } else {
            log.info("orderIssued 命令下发没有检测到心跳{}", heartbeatKey);
            heartbeatResp.setHeartbeatStatus(CommonConstant.ZERO);
            heartbeatResp.setMsg(msg + CommonConstant.Heartbeat.FAIL);
            planCurveOperationRecordReq.setStatus(0);
            planCurveOperationRecordReq.setOperateResult(msg + CommonConstant.Heartbeat.FAIL);
            //保存操作记录信息
            DataResult result = businessFeignClient.planCurveOperationRecord(planCurveOperationRecordReq);
            return DataResult.success(heartbeatResp);
        }
    }

    @PostMapping("progressBar")
    @ApiOperation(value = "指令下发进度")
    @TokenIgnore
    public DataResult<OrderProcessResp> progressBar(@RequestBody OrderProgressReqVO vo, HttpServletRequest request) {
        String lang = request.getHeader(CommonConstant.LANG);
        String key = vo.getStationId() + ":" + vo.getSrcId();
        log.info("指令下发进度 key:{}", key);
        OrderProcessResp orderProcessResp = new OrderProcessResp();
        List<OrderProcessDetailResp> processDetailRespList = new ArrayList<>();
        if (!redisService.hasKey(key)) {
            orderProcessResp.setIsEnd(CommonConstant.TWO);
            orderProcessResp.setMsg(BaseResponseCode.COMMAND_IS_EMPTY.getMsg());
            orderProcessResp.setProcessList(processDetailRespList);
            return DataResult.success(orderProcessResp);
        }
        Long expireTime = redisService.getExpire(key, TimeUnit.SECONDS);
        Map<Object, Object> dataMap = redisService.hgetall(key);
        log.info("redis dataMap {}", dataMap);
        if (CommonConstant.ZERO.equals(dataMap.get(RedisKeyConstant.IS_END))) {
            if (expireTime <= TIME_LIMIT) {
                redisService.delete(vo.getStationId() + ":" + RedisKeyConstant.ORDER_USING);
                orderProcessResp.setIsEnd(CommonConstant.TWO);
                orderProcessResp.setMsg(CommonConstant.IssuedFlag.TIMEOUT_FAIL);
            } else {
                orderProcessResp.setIsEnd(CommonConstant.ZERO);
                orderProcessResp.setMsg(CommonConstant.IssuedFlag.ORDER_PROCESS);
                orderProcessResp.setProcessList(processDetailRespList);
                return DataResult.success(orderProcessResp);
            }
        } else {
            StringBuffer strSuccess = new StringBuffer();
            StringBuffer strFail = new StringBuffer();
            OrderProcessDetailResp orderProcessDetailResp = null;
            for (Map.Entry<Object, Object> s : dataMap.entrySet()) {
                if (!RedisKeyConstant.IS_END.equals(s.getKey())) {
                    //只给前端返回下发失败的列表
                    if (CommonConstant.IssuedFlag.UPDATE_FAIL.equals(String.valueOf(s.getValue()))) {
                        orderProcessDetailResp = new OrderProcessDetailResp();
                        orderProcessDetailResp.setCol(String.valueOf(s.getKey()));
                        orderProcessDetailResp.setMsg(String.valueOf(s.getValue()));
                        processDetailRespList.add(orderProcessDetailResp);
                        strFail.append(s.getKey() + ",");
                    } else {
                        strSuccess.append(s.getKey() + ",");
                    }
                }
            }
            //缩短提示,只要有一个失败,那么isEnd就给2，否则给1
            if (strFail.length() > 0) {
                orderProcessResp.setIsEnd(CommonConstant.TWO);
                orderProcessResp.setMsg(strFail.toString() + CommonConstant.IssuedFlag.UPDATE_FAIL);
            } else {
                orderProcessResp.setIsEnd(CommonConstant.ONE);
                orderProcessResp.setMsg(strSuccess.toString() + CommonConstant.IssuedFlag.SUCCESS);
            }
        }
        orderProcessResp.setProcessList(processDetailRespList);
        if(CommonConstant.langTemp.EN_US.equals(lang)){
            orderProcessResp.setMsg(TranslateUtils.translate(orderProcessResp.getMsg(),CommonConstant.lang.EN));
        }
        return DataResult.success(orderProcessResp);
    }

    @PostMapping("apiOrderIssued")
    @ApiOperation(value = "指令下发(对外提供)")
    @TokenIgnore
    public DataResult<HeartbeatResp> apiOrderIssued(@RequestBody ApiOrderIssuedReqVO vo, HttpServletRequest request) {
        SysSubDictVO sysSubDictVO = new SysSubDictVO();
        sysSubDictVO.setType(CommonConstant.PUSH_DATA);
        Map<String, String> sysSubDict = userFeignClient.getSysSubDict(sysSubDictVO);
        String stationId = sysSubDict.get(vo.getApiSecret());
        HeartbeatResp heartbeatResp = new HeartbeatResp();
        if (stationId != null) {
            List<OrderIssuedVO> list = vo.getList();
            for (OrderIssuedVO orderIssuedVO : list) {
                orderIssuedVO.setStationId(Integer.valueOf(stationId));
            }
            DataResult<HeartbeatResp> heartbeatRespDataResult = orderIssued(vo,request);
            heartbeatResp = heartbeatRespDataResult.getData();
        }
        return DataResult.success(heartbeatResp);
    }

    @PostMapping("apiProgressBar")
    @ApiOperation(value = "指令下发进度(对外提供)")
    @TokenIgnore
    public DataResult<OrderProcessResp> apiProgressBar(@RequestBody ApiOrderProgressReqVO apiVo, HttpServletRequest request) {
        SysSubDictVO sysSubDictVO = new SysSubDictVO();
        sysSubDictVO.setType(CommonConstant.PUSH_DATA);
        Map<String, String> sysSubDict = userFeignClient.getSysSubDict(sysSubDictVO);
        String stationId = sysSubDict.get(apiVo.getApiSecret());
        OrderProcessResp orderProcessResp = new OrderProcessResp();
        if (stationId != null) {
            OrderProgressReqVO vo = new OrderProgressReqVO();
            vo.setStationId(Integer.valueOf(stationId));
            vo.setSrcId(apiVo.getSrcId());
            DataResult<OrderProcessResp> orderProcessRespDataResult = progressBar(vo,request);
            orderProcessResp = orderProcessRespDataResult.getData();
        }
        return DataResult.success(orderProcessResp);
    }

    @PostMapping("sendPlanPowerOrder")
    @ApiOperation(value = "命令下发曲线")
//    @LogAnnotation(title = "命令下发曲线", action = "命令下发曲线")
    @TokenIgnore
    public DataResult<HeartbeatResp> sendPlanPowerOrder(@RequestBody OrderPlanPowerReq vo, HttpServletRequest request) {
        String lang = request.getHeader(CommonConstant.LANG);
        HeartbeatResp heartbeatResp = orderSendService.sendPlanPowerOrder(vo);
        if(CommonConstant.langTemp.EN_US.equals(lang)){
            heartbeatResp.setMsg(TranslateUtils.translate(heartbeatResp.getMsg(),CommonConstant.lang.EN));
        }
        return DataResult.success(heartbeatResp);
    }

    @PostMapping("planPowerProgressBar")
    @ApiOperation(value = "指令下发进度")
    @TokenIgnore
    public DataResult<OrderProcessResp> planPowerProgressBar(@RequestBody OrderPlanPowerReq vo, HttpServletRequest request) {
        String lang = request.getHeader(CommonConstant.LANG);
        OrderProcessResp orderProcessResp = orderSendService.planPowerProgressBar(vo);
        if(CommonConstant.langTemp.EN_US.equals(lang)){
            orderProcessResp.setMsg(TranslateUtils.translate(orderProcessResp.getMsg(),CommonConstant.lang.EN));
        }
        return DataResult.success(orderProcessResp);
    }


    @PostMapping("orderIssued4plan")
    @ApiOperation(value = "指令下发")
    @TokenIgnore
    public DataResult<HeartbeatResp> orderIssued4plan(@RequestBody OrderIssuedReqVO vo, HttpServletRequest request) {
        String lang = request.getHeader(CommonConstant.LANG);
        DataResult result = getDataResult(vo);
        if(CommonConstant.langTemp.EN_US.equals(lang)){
            HeartbeatResp heartbeatResp= (HeartbeatResp)result.getData();
            heartbeatResp.setMsg(TranslateUtils.translate(heartbeatResp.getMsg(),CommonConstant.lang.EN));
        }
        return result;
    }
}
