package com.ho.flow.controller;


import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.PageInfo;
import com.ho.business.vo.req.deviceModel.SynchronousReqVo;
import com.ho.common.tools.annotation.HzPermission;
import com.ho.common.tools.annotation.LogAnnotation;
import com.ho.common.tools.constant.ContextConstant;
import com.ho.common.tools.constant.PermissionConstant;
import com.ho.common.tools.constant.RedisKeyConstant;
import com.ho.common.tools.entity.SimpleUser;
import com.ho.common.tools.exception.BaseResponseCode;
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.PageUtils;
import com.ho.flow.constant.FlowConstant;
import com.ho.flow.service.AlarmConfigService;
import com.ho.flow.service.DeviceColDefineService;
import com.ho.flow.vo.AlarmConfig;
import com.ho.flow.vo.DeviceColDefine;
import com.ho.flow.vo.req.AlarmConfig.*;
import com.ho.flow.vo.resp.alarm.AlarmMeasureRepVo;
import com.ho.flow.vo.resp.alarm.AlarmSignalRepVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @author gyan
 * @desc: 电站告警配置表
 * @DateTime: 2023/2/1 17:21
 */
@RestController
@RequestMapping(ContextConstant.FLOW_CONTEXT + "alarmConfig")
@Api(tags = "电站告警配置")
public class AlarmConfigController {

    @Autowired
    AlarmConfigService alarmConfigService;

    @Autowired
    DeviceColDefineService deviceColDefineService;

    @Autowired
    RedisService redisService;

    @Autowired
    RedissonClient redissonClient;


    @PostMapping("/signalPage")
    @ApiOperation(value = "分页查询遥信告警配置接口")
    public DataResult<PageResult<AlarmSignalRepVo>> signalPage(@RequestBody AlarmConfigPageReqVo vo, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        vo.setGroupId(user.getGroupId());
        //按照设备类型查全部字段定义表中的字段
        //这个分页需要内存分页
        DeviceColDefineReqVo defineReqVo = new DeviceColDefineReqVo();
        defineReqVo.setDeviceType(vo.getDeviceType());
        defineReqVo.setSensType(vo.getSensType());
//        defineReqVo.setColName(vo.getColName());
        defineReqVo.setColNameList(vo.getColNameList());
        List<DeviceColDefine> deviceColDefines = deviceColDefineService.selectList(defineReqVo);
        AlarmConfigPageReqVo thisLevelQuery = new AlarmConfigPageReqVo();
        Integer scope = FlowConstant.AlarmConfig.SCOPE_GROUP;
        ;
        //如果集团级别,就查集团,电站的就查电站
        thisLevelQuery.setGroupId(vo.getGroupId());
        thisLevelQuery.setDeviceType(vo.getDeviceType());
        thisLevelQuery.setScope(vo.getScope());
        thisLevelQuery.setSensType(vo.getSensType());
        thisLevelQuery.setAlarmLevel(vo.getAlarmLevel());
        //新增字段名匹配
//        thisLevelQuery.setColName(vo.getColName());
        thisLevelQuery.setColNameList(vo.getColNameList());
        if (FlowConstant.AlarmConfig.SCOPE_STATION.equals(vo.getScope())) {
            scope = FlowConstant.AlarmConfig.SCOPE_STATION;
            thisLevelQuery.setStationId(vo.getStationId());
        }
        //查告警等级是这个类型的数据,进行选中控制
        List<AlarmConfig> thisLevelList = alarmConfigService.selectList(thisLevelQuery);
        //查告警等级不是这个的数据,把这些字段排除
        AlarmConfigPageReqVo otherLevelQuery = new AlarmConfigPageReqVo();
        BeanUtil.copyProperties(thisLevelQuery, otherLevelQuery);
        otherLevelQuery.setAlarmLevel(null);
        otherLevelQuery.setOtherAlarmLevel(vo.getAlarmLevel());
//        otherLevelQuery.setColName(vo.getColName());
        thisLevelQuery.setColNameList(vo.getColNameList());
        List<AlarmConfig> otherLevelList = alarmConfigService.selectList(otherLevelQuery);
        //把两个alarmconfig集合按col分组
        Map<String, AlarmConfig> otherLevelMap = otherLevelList.stream().collect(Collectors.toMap(AlarmConfig::getCol, alarmConfig -> alarmConfig));
        Map<String, AlarmConfig> thisLevelMap = thisLevelList.stream().collect(Collectors.toMap(AlarmConfig::getCol, alarmConfig -> alarmConfig));
        //
        List<AlarmSignalRepVo> alarmList = new ArrayList<>();
        for (DeviceColDefine deviceColDefine : deviceColDefines) {
            //其他等级已经使用的,就剔除了,没有的才保留这个数据
            if (!otherLevelMap.containsKey(deviceColDefine.getCol())) {
                AlarmSignalRepVo alarmSignalRepVo = new AlarmSignalRepVo();
                alarmSignalRepVo.setId(deviceColDefine.getId());
                alarmSignalRepVo.setColName(deviceColDefine.getColName());
                alarmSignalRepVo.setScope(scope);
                if (thisLevelMap.containsKey(deviceColDefine.getCol())) {
                    alarmSignalRepVo.setChecked(FlowConstant.AlarmConfig.CHECKED);
                } else {
                    alarmSignalRepVo.setChecked(FlowConstant.AlarmConfig.NOT_CHECKED);
                }
                alarmList.add(alarmSignalRepVo);
            }
        }
        //java内存分页
        PageResult pageResult = new PageResult<>();
        if (!alarmList.isEmpty()) {
            List list = PageUtils.dealList(alarmList, vo.getPageNum(), vo.getPageSize());
            pageResult = PageUtils.getPageResult(new PageInfo<>(list));
            pageResult.setTotalRows(alarmList.size());
            pageResult.setTotalPages(alarmList.size() / vo.getPageSize() + 1);
        } else {
            pageResult = PageUtils.getPageResult(new PageInfo<>(new ArrayList<>()));
        }
        return DataResult.success(pageResult);
    }


    @PostMapping("/measurePage")
    @ApiOperation(value = "分页查询遥测告警配置接口")
    public DataResult<PageResult<AlarmMeasureRepVo>> measurePage(@RequestBody AlarmConfigPageReqVo vo, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        vo.setGroupId(user.getGroupId());
        //按照设备类型查全部字段定义表中的字段
        //这个分页需要内存分页
        DeviceColDefineReqVo defineReqVo = new DeviceColDefineReqVo();
        defineReqVo.setDeviceType(vo.getDeviceType());
        defineReqVo.setSensType(vo.getSensType());
        defineReqVo.setColName(vo.getColName());
        List<DeviceColDefine> deviceColDefines = deviceColDefineService.selectList(defineReqVo);
        AlarmConfigPageReqVo thisLevelQuery = new AlarmConfigPageReqVo();
        thisLevelQuery.setGroupId(vo.getGroupId());
        thisLevelQuery.setDeviceType(vo.getDeviceType());
        thisLevelQuery.setScope(vo.getScope());
        thisLevelQuery.setSensType(vo.getSensType());
        thisLevelQuery.setColName(vo.getColName());
        Integer scope = FlowConstant.AlarmConfig.SCOPE_GROUP;
        //如果集团级别,就查集团,电站的就查电站
        if (FlowConstant.AlarmConfig.SCOPE_STATION.equals(vo.getScope())) {
            scope = FlowConstant.AlarmConfig.SCOPE_STATION;
            thisLevelQuery.setStationId(vo.getStationId());
        }
        //查告警等级是这个类型的数据,进行选中控制
        List<AlarmConfig> thisLevelList = alarmConfigService.selectList(thisLevelQuery);
        //把两个alarmconfig集合按col分组
        Map<String, AlarmConfig> thisLevelMap = thisLevelList.stream().collect(Collectors.toMap(AlarmConfig::getCol, alarmConfig -> alarmConfig));
        //
        List<AlarmMeasureRepVo> alarmList = new ArrayList<>();
        for (DeviceColDefine deviceColDefine : deviceColDefines) {
            //其他等级已经使用的,就剔除了,没有的才保留这个数据
            AlarmMeasureRepVo measure = new AlarmMeasureRepVo();
            measure.setId(deviceColDefine.getId());
            measure.setColName(deviceColDefine.getColName());
            measure.setScope(scope);
            String key = deviceColDefine.getCol();
            if (thisLevelMap.containsKey(key)) {
                measure.setChecked(FlowConstant.AlarmConfig.CHECKED);
                measure.setUpperLimit(thisLevelMap.get(key).getUpperLimit());
                measure.setLowerLimit(thisLevelMap.get(key).getLowerLimit());
            } else {
                measure.setChecked(FlowConstant.AlarmConfig.NOT_CHECKED);
            }
            alarmList.add(measure);
        }
        //java内存分页
        PageResult pageResult = new PageResult<>();
        if (!alarmList.isEmpty()) {
            List list = PageUtils.dealList(alarmList, vo.getPageNum(), vo.getPageSize());
            pageResult = PageUtils.getPageResult(new PageInfo<>(list));
            pageResult.setTotalRows(alarmList.size());
            pageResult.setTotalPages(alarmList.size() / vo.getPageSize() + 1);
        } else {
            pageResult = PageUtils.getPageResult(new PageInfo<>(new ArrayList<>()));
        }
        return DataResult.success(pageResult);
    }


    @PostMapping("/signalCheckListPage")
    @ApiOperation(value = "分页查询遥信告警配置已经选中的接口")
    public DataResult<PageResult<AlarmSignalRepVo>> signalCheckListPage(@RequestBody AlarmConfigPageReqVo vo, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        vo.setGroupId(user.getGroupId());
        AlarmConfigPageReqVo thisLevelQuery = new AlarmConfigPageReqVo();
        Integer scope = FlowConstant.AlarmConfig.SCOPE_GROUP;
        //如果集团级别,就查集团,电站的就查电站
        thisLevelQuery.setGroupId(vo.getGroupId());
        thisLevelQuery.setDeviceType(vo.getDeviceType());
        thisLevelQuery.setScope(vo.getScope());
        thisLevelQuery.setSensType(vo.getSensType());
        thisLevelQuery.setAlarmLevel(vo.getAlarmLevel());
        if (FlowConstant.AlarmConfig.SCOPE_STATION.equals(vo.getScope())) {
            scope = FlowConstant.AlarmConfig.SCOPE_STATION;
            thisLevelQuery.setStationId(vo.getStationId());
        }
        //查告警等级是这个类型的数据,进行选中控制
        List<AlarmConfig> thisLevelList = alarmConfigService.selectList(thisLevelQuery);
        List<AlarmSignalRepVo> alarmList = new ArrayList<>();
        for (AlarmConfig alarm : thisLevelList) {
            AlarmSignalRepVo alarmSignalRepVo = new AlarmSignalRepVo();
            alarmSignalRepVo.setId(alarm.getColDefineId());
            alarmSignalRepVo.setColName(alarm.getColName());
            alarmSignalRepVo.setScope(scope);
            alarmSignalRepVo.setChecked(FlowConstant.AlarmConfig.CHECKED);
            alarmList.add(alarmSignalRepVo);
        }
        //java内存分页
        PageResult pageResult = new PageResult<>();
        if (!alarmList.isEmpty()) {
            List list = PageUtils.dealList(alarmList, vo.getPageNum(), vo.getPageSize());
            pageResult = PageUtils.getPageResult(new PageInfo<>(list));
            pageResult.setTotalRows(alarmList.size());
            pageResult.setTotalPages(alarmList.size() / vo.getPageSize() + 1);
        } else {
            pageResult = PageUtils.getPageResult(new PageInfo<>(new ArrayList<>()));
        }
        return DataResult.success(pageResult);
    }

    //这个方法用不到了
    @Deprecated
    @PostMapping("/levelList")
    @ApiOperation(value = "批量新增遥信时查询电站告警配置列表,不分页")
    @ApiIgnore
    public DataResult<List<DeviceColDefine>> levelList(@RequestBody LevelReqVo levelReqVo, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        //先查全量字段定义
        DeviceColDefineReqVo defineReqVo = new DeviceColDefineReqVo();
        defineReqVo.setDeviceType(levelReqVo.getDeviceType());
        defineReqVo.setSensType(levelReqVo.getSensType());
        //List<DeviceColDefine> deviceColDefines = deviceColDefineService.selectByIdList(defineReqVo);
        List<DeviceColDefine> deviceColDefines = null;
        //再查电站在该等级下的已配置字段
        AlarmConfigPageReqVo alarmConfigPageReqVo = new AlarmConfigPageReqVo();
        alarmConfigPageReqVo.setGroupId(user.getGroupId());
        alarmConfigPageReqVo.setStationId(levelReqVo.getStationId());
        alarmConfigPageReqVo.setDeviceType(levelReqVo.getDeviceType());
        alarmConfigPageReqVo.setSensType(levelReqVo.getSensType());
        alarmConfigPageReqVo.setAlarmLevel(levelReqVo.getAlarmLevel());
        //设置为电站级别数据
        alarmConfigPageReqVo.setScope(FlowConstant.AlarmConfig.SCOPE_STATION);
        List<AlarmConfig> stationAlarmConfigs = alarmConfigService.selectList(alarmConfigPageReqVo);
        //将这个已配置集合转为map,按照 col分组
        Map<String, AlarmConfig> stationAlarmConfigMap = stationAlarmConfigs.stream().collect(Collectors.toMap(AlarmConfig::getCol, alarmConfig -> alarmConfig));
        //查集团级
        alarmConfigPageReqVo = new AlarmConfigPageReqVo();
        alarmConfigPageReqVo.setGroupId(user.getGroupId());
        alarmConfigPageReqVo.setDeviceType(levelReqVo.getDeviceType());
        alarmConfigPageReqVo.setSensType(levelReqVo.getSensType());
        alarmConfigPageReqVo.setAlarmLevel(levelReqVo.getAlarmLevel());
        //设置为集团级别
        alarmConfigPageReqVo.setScope(FlowConstant.AlarmConfig.SCOPE_GROUP);
        List<AlarmConfig> groupAlarmConfigs = alarmConfigService.selectList(alarmConfigPageReqVo);
        //将这个已配置集合转为map,按照 col分组
        Map<String, AlarmConfig> groupAlarmConfigMap = groupAlarmConfigs.stream().collect(Collectors.toMap(AlarmConfig::getCol, alarmConfig -> alarmConfig));

        //默认先设置为未选择
        for (DeviceColDefine deviceColDefine : deviceColDefines) {
            //同时包含了这个值才checked =1
            if (stationAlarmConfigMap.containsKey(deviceColDefine.getCol())
                    && groupAlarmConfigMap.containsKey(deviceColDefine.getCol())) {
                deviceColDefine.setChecked(1);
            } else {
                deviceColDefine.setChecked(0);
            }
        }
        //将 alarmConfigs存在数据的(已配置的) 修改为
        return DataResult.success(deviceColDefines);
    }


    @PostMapping("add")
    @ApiOperation(value = "新增电站告警配置接口")
    @LogAnnotation(title = "电站告警配置", action = "新增电站告警配置")
    public DataResult<AlarmConfig> add(@RequestBody @Valid AlarmConfigAddReqVo vo, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        alarmConfigService.add(vo, user);
        return DataResult.success();
    }

    @PostMapping("addSignalBatch")
    @ApiOperation(value = "批量新增告警遥信配置接口")
    @LogAnnotation(title = "电站告警配置", action = "批量新增电站告警遥信配置")
    @HzPermission(PermissionConstant.EVENT_CONFIGURE_YXSAVE)
    public DataResult<AlarmConfig> addSignalBatch(@RequestBody @Valid AlarmSignalBatchAddReq addReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        addReq.setGroupId(user.getGroupId());
        //分布式锁
        //定义锁
        RLock lock = null;
        try {
            lock = redissonClient.getLock(RedisKeyConstant.LOCK_KEY_ALARM_CONFIG);
            //获取锁,没有获取到锁的阻塞在lock.lock() 这行
            lock.lock();
            alarmConfigService.addSignalBatch(addReq);
        } finally {
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return DataResult.success();
    }

    @PostMapping("addMeasureBatch")
    @ApiOperation(value = "批量新增告警遥测配置接口")
    @LogAnnotation(title = "电站告警配置", action = "批量新增电站告警遥测配置")
    @HzPermission(PermissionConstant.EVENT_CONFIGURE_YCSAVE)
    public DataResult<AlarmConfig> addMeasureBatch(@RequestBody @Valid AlarmMeasureBatchAddReq addReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        addReq.setGroupId(user.getGroupId());
        //分布式锁
        //定义锁
        RLock lock = null;
        BigDecimal max = new BigDecimal(1000000000);
        BigDecimal min = new BigDecimal(-1000000000);
        try {
            lock = redissonClient.getLock(RedisKeyConstant.LOCK_KEY_ALARM_CONFIG);
            //获取锁,没有获取到锁的阻塞在lock.lock() 这行
            lock.lock();
            List<MeasureVo> measureList = new ArrayList<>();
            for (MeasureVo measureVo : addReq.getMeasureList()) {
                if (measureVo.getLowerLimit() != null && measureVo.getUpperLimit() != null) {
                    if (measureVo.getUpperLimit().compareTo(measureVo.getLowerLimit()) < 0) {
                        return DataResult.getResult(BaseResponseCode.EXISTS_UPPER_LESS_LOWER);
                    }
                    if (measureVo.getUpperLimit().compareTo(max) > 0 || measureVo.getLowerLimit().compareTo(min) < 0) {
                        return DataResult.getResult(BaseResponseCode.EXCEEDING_VALUE_RANGE);
                    }
                    measureList.add(measureVo);
                }else if((measureVo.getLowerLimit() != null && measureVo.getUpperLimit() == null) || (measureVo.getLowerLimit() == null && measureVo.getUpperLimit() != null)){
                    return DataResult.getResult(BaseResponseCode.TELEMETRY_VALUE_NOT_LIMIT);
                }
            }
            //addReq.setMeasureList(measureList);
            alarmConfigService.addMeasureBatch(addReq);
        } finally {
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return DataResult.success();
    }


    //不需要单个删除了，单个删除也调用多个删除方法
    @GetMapping("deleteById/{id}")
    @ApiOperation(value = "删除告警配置接口")
    @LogAnnotation(title = "电站告警配置", action = "删除电站告警配置")
    @ApiIgnore
    public DataResult deleteById(@PathVariable @Valid Integer id) {
        alarmConfigService.deletedById(id);
        return DataResult.success();
    }

    @PostMapping("deleteSignalBatch")
    @ApiOperation(value = "批量删除告警遥信配置")
    @LogAnnotation(title = "电站告警配置", action = "批量删除告警遥信配置")
    @HzPermission(PermissionConstant.EVENT_CONFIGURE_YXBATCHDELETE)
    public DataResult deleteSignalBatch(@RequestBody @Valid AlarmBatchDeleteReq batchDeleteReq, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        batchDeleteReq.setGroupId(user.getGroupId());
        //批量alarm表删除,传过来的是deviceColId集合,需要根据这个条件找到alarmConfig表中对应的记录
        alarmConfigService.deleteSignalBatch(batchDeleteReq);
        return DataResult.success();
    }


    @PostMapping("update")
    @ApiOperation(value = "更新告警配置接口")
    @LogAnnotation(title = "电站告警配置", action = "更新电站告警配置")
    public DataResult update(@RequestBody @Valid AlarmConfigUpdateReqVo vo) {
        alarmConfigService.update(vo);
        return DataResult.success();
    }

    @PostMapping("modifyLevel")
    @ApiOperation(value = "更改电站告警等级接口")
    @LogAnnotation(title = "电站告警配置", action = "更改电站告警等级")
    @HzPermission(PermissionConstant.EVENT_CONFIGURE_YXEDIT)
    public DataResult modifyLevel(@RequestBody @Valid AlarmUpdateLevelReq vo) {
        AlarmConfigUpdateReqVo updateReqVo = new AlarmConfigUpdateReqVo();
        BeanUtils.copyProperties(vo, updateReqVo);
        alarmConfigService.update(updateReqVo);
        return DataResult.success();
    }


    @PostMapping("/syAlarmConfig")
    @ApiOperation(value = "同步告警配置数据")
    @LogAnnotation(title = "告警配置", action = "一键同步告警配置")
    public DataResult syAlarmConfig(@RequestBody SynchronousReqVo vo) {
        alarmConfigService.syAlarmConfig(vo);
        return DataResult.success();
    }
}
