package com.njcn.process.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.device.pms.api.MonitorClient;
import com.njcn.device.pms.enums.PmsDeviceResponseEnum;
import com.njcn.device.pms.pojo.dto.PmsMonitorDTO;
import com.njcn.device.pms.pojo.param.PmsMonitorParam;
import com.njcn.process.enums.ProcessResponseEnum;
import com.njcn.process.pojo.param.MonitorParam;
import com.njcn.process.pojo.param.StrategyParam;
import com.njcn.process.pojo.po.ThsDeptAlarm;
import com.njcn.process.pojo.po.ThsWarnStrategy;
import com.njcn.process.mapper.ThsWarnStrategyMapper;
import com.njcn.process.pojo.po.ThsWarnStrategyAss;
import com.njcn.process.service.ThsDeptAlarmService;
import com.njcn.process.service.ThsWarnStrategyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.pojo.dto.DeptDTO;
import com.njcn.web.utils.RequestUtil;
import com.njcn.web.utils.WebUtil;
import liquibase.pro.packaged.S;
import lombok.RequiredArgsConstructor;
import org.apache.commons.math3.random.RandomDataGenerator;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author wr
 * @since 2023-03-10
 */
@Service
@RequiredArgsConstructor
public class ThsWarnStrategyServiceImpl extends ServiceImpl<ThsWarnStrategyMapper, ThsWarnStrategy> implements ThsWarnStrategyService {

    private final ThsWarnStrategyAssServiceImpl thsWarnStrategyAssService;

    private final ThsWarnStrategyMapper thsWarnStrategyMapper;
    private final MonitorClient monitorClient;
    private final DeptFeignClient deptFeignClient;
    private final ThsDeptAlarmService thsDeptAlarmService;

    @Override
    public Page<ThsWarnStrategy> strategyPage(StrategyParam.StrategyPageParam param) {
        return this.page(new Page<>(param.getPageNum(), param.getPageSize())
                , new LambdaQueryWrapper<ThsWarnStrategy>()
                        .like(StrUtil.isNotBlank(param.getName()), ThsWarnStrategy::getName, param.getName())
                        .eq(param.getGrade() != null, ThsWarnStrategy::getGrade, param.getGrade())
                        .eq(param.getType() != null, ThsWarnStrategy::getType, param.getType())
                        .ne(ThsWarnStrategy::getState, DataStateEnum.DELETED.getCode())

        );
    }

    @Override
    public List<ThsWarnStrategy> strategyList(StrategyParam.StrategyPageParam param) {
        return this.list(new LambdaQueryWrapper<ThsWarnStrategy>()
                .like(StrUtil.isNotBlank(param.getName()), ThsWarnStrategy::getName, param.getName())
                .eq(param.getGrade() != null, ThsWarnStrategy::getGrade, param.getGrade())
                .eq(param.getType() != null, ThsWarnStrategy::getType, param.getType())
                        .eq(ThsWarnStrategy::getDeptId,param.getDeptId())
                .ne(ThsWarnStrategy::getState, DataStateEnum.DELETED.getCode())

        );
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Boolean insertStrategy(StrategyParam.StrategyInsertParam param) {
        List<ThsWarnStrategy> one = this.list(new LambdaQueryWrapper<ThsWarnStrategy>()
                .ne(ThsWarnStrategy::getState, DataStateEnum.DELETED.getCode())
                .eq(ThsWarnStrategy::getName, param.getName())
                .eq(ThsWarnStrategy::getType, param.getType())
                .or(param.getBigType() == 0, wrapper ->
                        wrapper.eq(ThsWarnStrategy::getGrade, param.getGrade())
                                .eq(ThsWarnStrategy::getBigType, 0)
                                .eq(ThsWarnStrategy::getType, param.getType())
                                .ne(ThsWarnStrategy::getState, DataStateEnum.DELETED.getCode())
                )
        );
        if (CollectionUtil.isNotEmpty(one)) {
            if (one.size() > 1 || one.get(0).getName().equals(param.getName())) {
                throw new BusinessException(PmsDeviceResponseEnum.MODEL_NAME_REPEAT);
            }
            throw new BusinessException(ProcessResponseEnum.THERE_IS_ONLY_ONE_STRATEGY);
        }
        ThsWarnStrategy thsWarnStrategy = BeanUtil.copyProperties(param, ThsWarnStrategy.class);
        thsWarnStrategy.setCreateBy(RequestUtil.getUserNickname());
        thsWarnStrategy.setState(2);
        thsWarnStrategy.setBigType(param.getBigType());
        return this.save(thsWarnStrategy);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Boolean bindStrategy(StrategyParam.BindParam param) {
        checkBind(param);

        List<ThsWarnStrategyAss> assList = new ArrayList<>();

        ThsWarnStrategy thsWarnStrategy = new ThsWarnStrategy();
        thsWarnStrategy.setOperation(param.getOperation());
        thsWarnStrategy.setName(param.getStrategyName());
        thsWarnStrategy.setDeptId(param.getDeptId());
        thsWarnStrategy.setGrade(param.getGrade());
        thsWarnStrategy.setType(param.getStrategyType());
        thsWarnStrategy.setState(DataStateEnum.ENABLE.getCode());
        if (StrUtil.isBlank(param.getId())) {
            //新增
            thsWarnStrategy.setId(IdUtil.simpleUUID());
            this.save(thsWarnStrategy);
        } else {
            //修改
            //删除之前绑定信息
            thsWarnStrategy.setId(param.getId());
            thsWarnStrategyAssService.removeById(param.getId());
            this.updateById(thsWarnStrategy);
        }
        //监测点标签绑定
        if (CollectionUtil.isNotEmpty(param.getMonitorTag())) {
            add(assList, thsWarnStrategy.getId(), 0, param.getMonitorTag());
        }
        //监测点
        if (CollectionUtil.isNotEmpty(param.getMonitorIds())) {
            add(assList, thsWarnStrategy.getId(), 2, param.getMonitorIds());
        }
        //指标类型绑定
        add(assList,thsWarnStrategy.getId(), 1, param.getIndicatorTypes());
        thsWarnStrategyAssService.saveBatch(assList);
        return true;
    }

    /**
     * 校验
     */
    private boolean checkBind(StrategyParam.BindParam param){

        LambdaQueryWrapper<ThsWarnStrategy> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(ThsWarnStrategy::getId).eq(ThsWarnStrategy::getDeptId,param.getDeptId())
                .eq(ThsWarnStrategy::getType,param.getStrategyType()).eq(ThsWarnStrategy::getGrade,param.getGrade());

        if (StrUtil.isNotBlank(param.getId())) {
            lambdaQueryWrapper.ne(ThsWarnStrategy::getId,param.getId());
        }

        List<ThsWarnStrategy> thsWarnStrategyList = thsWarnStrategyMapper.selectList(lambdaQueryWrapper);
        List<String> strategyIds = thsWarnStrategyList.stream().map(ThsWarnStrategy::getId).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(strategyIds)){
            return true;
        }

        //判断标签和监测点是否已经存在
        List<ThsWarnStrategyAss> thsWarnStrategyAssList = thsWarnStrategyAssService.lambdaQuery().select(ThsWarnStrategyAss::getAssId).in(ThsWarnStrategyAss::getWarnId,strategyIds).list();
        long tagCount = thsWarnStrategyAssList.stream().filter(item->param.getMonitorTag().contains(item.getAssId())).count();
        if(tagCount>0){
            throw new BusinessException("所选干扰源已经存在策略！");
        }
        long monitorCount = thsWarnStrategyAssList.stream().filter(item->param.getMonitorIds().contains(item.getAssId())).count();
        if(monitorCount>0){
            throw new BusinessException("所选监测点已经存在策略！");
        }
        return true;
    }

    @Override
    public StrategyParam.StrategyUpdateParam getUpdateStrategy(String id) {
        return this.baseMapper.selectUpdateStrategy(id);
    }

    @Override
    public Boolean updateStrategy(StrategyParam.StrategyUpParam param) {
        List<ThsWarnStrategy> one = this.list(new LambdaQueryWrapper<ThsWarnStrategy>()
                .ne(ThsWarnStrategy::getState, DataStateEnum.DELETED.getCode())
                .ne(ThsWarnStrategy::getId, param.getId())
                .and(wrapper ->
                        wrapper.eq(ThsWarnStrategy::getName, param.getName())
                                .eq(ThsWarnStrategy::getType, param.getType())
                )
                .or(param.getBigType() == 0, wrapper ->
                        wrapper.eq(ThsWarnStrategy::getGrade, param.getGrade())
                                .eq(ThsWarnStrategy::getBigType, 0)
                                .eq(ThsWarnStrategy::getType, param.getType())
                                .ne(ThsWarnStrategy::getId, param.getId())
                                .ne(ThsWarnStrategy::getState, DataStateEnum.DELETED.getCode())

                )

        );
        if (CollectionUtil.isNotEmpty(one)) {
            if (one.size() > 1 || one.get(0).getName().equals(param.getName())) {
                throw new BusinessException(PmsDeviceResponseEnum.MODEL_NAME_REPEAT);
            }
            throw new BusinessException(ProcessResponseEnum.THERE_IS_ONLY_ONE_STRATEGY);
        }
        ThsWarnStrategy thsWarnStrategy = BeanUtil.copyProperties(param, ThsWarnStrategy.class);
        thsWarnStrategy.setUpdateBy(RequestUtil.getUserNickname());
        thsWarnStrategy.setBigType(param.getBigType());
        return this.updateById(thsWarnStrategy);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Boolean updateStrategyState(StrategyParam.StrategyStateParam param) {
        ThsWarnStrategy thsWarnStrategy = new ThsWarnStrategy();
        thsWarnStrategy.setId(param.getId());
        thsWarnStrategy.setState(param.getState());
        return this.updateById(thsWarnStrategy);
    }

    @Override
    public List<StrategyParam.MonitorTree> getMonitor(String orgId) {
        PmsMonitorParam param = new PmsMonitorParam();
        List<PmsMonitorDTO> data = monitorClient.getMonitorInfoListByCond(param).getData();
        //获取部门结构
        List<DeptDTO> deptInfos = deptFeignClient.getDeptDescendantIndexes(orgId, WebUtil.filterDeptType()).getData();

        List<DeptDTO> deptDTOS = deptInfos.stream().filter(org -> org.getId().equals(orgId)).collect(Collectors.toList());
        //递归监测点信息
        List<StrategyParam.MonitorTree> monitorTrees = new ArrayList<>();
        StrategyParam.MonitorTree tree = new StrategyParam.MonitorTree();
        tree.setId(deptDTOS.get(0).getId());
        tree.setName(deptDTOS.get(0).getName());
        List<StrategyParam.MonitorTree> powers = getPowers(deptDTOS.get(0).getCode(), data);
        powers.addAll(recursionSelectList(orgId, deptInfos, data));
        tree.setChildren(powers);
        monitorTrees.add(tree);
        return monitorTrees;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Boolean bindMonitor(MonitorParam param) {
        //删除之前数据(根据部门和策略类型)
        LambdaQueryWrapper<ThsDeptAlarm> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ThsDeptAlarm::getDeptId, param.getDeptId());
        lambdaQueryWrapper.eq(ThsDeptAlarm::getType, param.getType());
        lambdaQueryWrapper.eq(ThsDeptAlarm::getGrade, param.getGrade());
        thsDeptAlarmService.remove(lambdaQueryWrapper);

        //信息添加
        List<ThsDeptAlarm> info = new ArrayList();
        List<String> alarmIds = param.getAlarmId();
        List<String> monitorIds = param.getMonitorId();
        String deptId = param.getDeptId();
        Integer type = param.getType();
        //便利信息
        ThsDeptAlarm alarm;
        for (String s : alarmIds) {
            for (String monitorId : monitorIds) {
                alarm = new ThsDeptAlarm();
                alarm.setDeptId(deptId);
                alarm.setType(type);
                alarm.setAlarmId(s);
                alarm.setGrade(param.getGrade());
                alarm.setMonitorId(monitorId);
                info.add(alarm);
            }
        }
        return thsDeptAlarmService.saveBatch(info);
    }

    @Override
    public StrategyParam.MonitorTree echoMonitor(String org, Integer type, Integer grade) {
        List<ThsDeptAlarm> list = thsDeptAlarmService.list(new LambdaQueryWrapper<ThsDeptAlarm>()
                .eq(ThsDeptAlarm::getDeptId, org)
                .eq(ThsDeptAlarm::getType, type)
                .eq(ThsDeptAlarm::getGrade, grade)
        );
        StrategyParam.MonitorTree tree = new StrategyParam.MonitorTree();
        List<String> collect = list.stream().map(ThsDeptAlarm::getAlarmId).distinct().collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(collect)) {
            tree.setId(collect.get(0));
        }
        tree.setChildren(list.stream().map(ThsDeptAlarm::getMonitorId).distinct().collect(Collectors.toList()));
        return tree;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Boolean delStrategy(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "id为空,不能删除");
        ThsWarnStrategy byId = this.getById(ids);
        if (ObjectUtil.isNull(byId)) {
            throw new BusinessException(ProcessResponseEnum.QUERY_IS_EMPTY);
        }
        if (byId.getState() == 1) {
            throw new BusinessException(ProcessResponseEnum.ENABLED_CANNOT_BE_DELETED);
        }
        thsWarnStrategyAssService.removeById(ids);
        ThsWarnStrategy thsWarnStrategy = new ThsWarnStrategy();
        thsWarnStrategy.setId(ids);
        thsWarnStrategy.setState(0);
        return this.updateById(thsWarnStrategy);
    }

    /***
     * 告警单 监测点标签或指标类型绑定
     * @author wr
     * @date 2023-03-20 18:57
     * @param assList 绑定信息
     * @param id 告警单id
     * @param type 0:监测点标签 1：指标类型
     * @param ids 监测点标签集合 或 指标类型集合
     */
    private void add(List<ThsWarnStrategyAss> assList, String id, Integer type, List<String> ids) {
        ThsWarnStrategyAss ass;
        for (String indicatorType : ids) {
            ass = new ThsWarnStrategyAss();
            ass.setWarnId(id);
            ass.setAssId(indicatorType);
            ass.setType(type);
            assList.add(ass);
        }
    }

    /**
     * 递归生成监测点树
     *
     * @param orgId
     * @param deptInfos
     * @param data
     * @return
     */
    private static List<StrategyParam.MonitorTree> recursionSelectList(String orgId, List<DeptDTO> deptInfos, List<PmsMonitorDTO> data) {
        List<StrategyParam.MonitorTree> menuSelectList = new ArrayList<>();
        Optional.ofNullable(deptInfos).ifPresent(customers -> customers.stream()
                .filter(org -> org.getPid().equals(orgId))
                .forEach(customer -> {
                    StrategyParam.MonitorTree tree = new StrategyParam.MonitorTree();
                    tree.setId(customer.getId());
                    tree.setName(customer.getName());
                    List<StrategyParam.MonitorTree> children = new ArrayList<>();
                    children.addAll(getPowers(customer.getCode(), data));
                    children.addAll(recursionSelectList(customer.getId(), deptInfos, data));
                    tree.setChildren(children);
                    menuSelectList.add(tree);
                }));
        return menuSelectList;
    }

    /***
     * 生成变电站包含监测点集合
     * @author wr
     * @date 2023-03-10 16:19
     * @param orgCode
     * @param data
     * @return List<Power>
     */
    private static List<StrategyParam.MonitorTree> getPowers(String orgCode, List<PmsMonitorDTO> data) {
        //变电站信息初始化
        List<StrategyParam.MonitorTree> powers = new ArrayList<>();
        //获取监测点信息
        List<PmsMonitorDTO> monitorDTOS = data.stream().filter(dept -> dept.getOrgId().equals(orgCode)).collect(Collectors.toList());
        Map<String, List<PmsMonitorDTO>> collect = monitorDTOS.stream().collect(
                Collectors.groupingBy(c -> c.getPowerrId() + "_" + c.getPowerrName()));
        //获取变电站和监测点信息
        collect.forEach((key, value) -> {
            String[] split = key.split("_");
            StrategyParam.MonitorTree power = new StrategyParam.MonitorTree();
            //生成随机数
            RandomDataGenerator randomDataGenerator = new RandomDataGenerator();
            power.setId(split[0] + randomDataGenerator.nextInt(1, 9));
            power.setName("变电站名称: " + split[1]);
            //监测点信息
            List<StrategyParam.Monitor> monitors = new ArrayList();
            for (PmsMonitorDTO dto : value) {
                StrategyParam.Monitor childMonitor = new StrategyParam.Monitor();
                childMonitor.setId(dto.getId());
                childMonitor.setName("监测点名称: " + dto.getName());
                monitors.add(childMonitor);
            }
            power.setChildren(monitors);
            powers.add(power);
        });
        return powers;
    }

}
