package com.yuchen.saas.park.service.fault.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.thinkunion.park.service.common.cache.CacheNames;
import com.yuchen.saas.park.api.entity.fault.EquipmentBreakdownRule;
import com.yuchen.saas.park.api.entity.fault.EquipmentBreakdownType;
import com.yuchen.saas.park.api.vo.fault.DeviceProperty;
import com.yuchen.saas.park.api.vo.fault.EquipmentBreakdownRuleVo;
import com.yuchen.saas.park.service.fault.mapper.EquipmentBreakdownRuleMapper;
import com.yuchen.saas.park.service.fault.service.EquipmentBreakdownRuleService;
import com.yuchen.saas.park.service.fault.service.EquipmentBreakdownTypeService;
import org.apache.commons.collections4.MapUtils;
import org.nest.springwrap.core.mp.base.BaseServiceImpl;
import org.nest.springwrap.core.mp.support.Condition;
import org.nest.springwrap.core.redis.cache.NestRedis;
import org.nest.springwrap.core.tool.api.R;
import org.nest.springwrap.core.tool.utils.BeanUtil;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: 肖润飞
 * @CreateTime: 2022/10/18 15:41
 * @Description: 设备故障规则
 * @Version: 1.0
 */
@Service
public class EquipmentBreakdownRuleServiceImpl extends BaseServiceImpl<EquipmentBreakdownRuleMapper, EquipmentBreakdownRule> implements EquipmentBreakdownRuleService {


    @Resource
    private NestRedis nestRedis;

    @Resource
    @Lazy
    EquipmentBreakdownTypeService typeService;


    /**
     * 判断设备属性是否是异常状态
     *
     * @param deviceProperty IOT传递的设备属性
     * @return EquipmentBreakdownRule
     */
    @Override
    public EquipmentBreakdownRule checkEquipmentStatus(DeviceProperty deviceProperty) {
        Map<String, EquipmentBreakdownRule> map = this.getEquipmentBreakdownRuleMap();
        for (String mapKey : map.keySet()) { // identify:standard:productKey
            if (mapKey.startsWith(deviceProperty.getIdentify())) {// 如果存在该设备指定属性的故障规则
                EquipmentBreakdownRule rule = map.get(mapKey);//获得规则
                String productKey = rule.getProductKey();
                if (StrUtil.isBlank(productKey) || mapKey.contains(productKey)) {
                    // 定义一个用于返回正常状态的breakdownCode
                    EquipmentBreakdownRule updateRule = new EquipmentBreakdownRule();
                    updateRule.setBreakdownCode(rule.getBreakdownCode());
                    String standard = rule.getStandard();
                    Float value = Float.valueOf(deviceProperty.getValue() + "");
                    int compare = Float.compare(value, rule.getValue());
                    switch (standard) {
                        case "lt":
                            return compare < 0 ? rule : updateRule;
                        case "gt":
                            return compare > 0 ? rule : updateRule;
                        case "eq":
                            return compare == 0 ? rule : updateRule;
                    }
                }
            }
        }
        return null;
    }


    /**
     * 修改规则,并更新规则缓存
     *
     * @param rule
     * @return
     */
    @Override
    public R updateRule(EquipmentBreakdownRule rule) {
        String filed = new StringBuilder(rule.getIdentify())
                .append(":")
                .append(rule.getStandard())
                .append(":")
                .append(rule.getProductKey() != null ? rule.getProductKey() : "")
                .toString();
        // 更新缓存
        nestRedis.hSet(CacheNames.EQ_BREAKDOWN_RULE_KEY, filed, rule);
        this.updateById(rule);
        return R.data(true);
    }


    /**
     * 修改规则,并更新规则缓存
     *
     * @param rule
     * @return
     */
    @Override
    public R pageVo(Page page, EquipmentBreakdownRule rule) {
        Page result = this.page(page, Condition.getQueryWrapper(rule));
        List<EquipmentBreakdownRule> records = result.getRecords();
        List<EquipmentBreakdownRuleVo> list = new ArrayList<>();
        for (EquipmentBreakdownRule record : records) {
            EquipmentBreakdownRuleVo vo = new EquipmentBreakdownRuleVo();
            BeanUtil.copyProperties(record, vo);
            list.add(vo);
            LambdaQueryWrapper<EquipmentBreakdownType> query = Wrappers.lambdaQuery();
            query.eq(EquipmentBreakdownType::getBreakdownCode, record.getBreakdownCode()).last(" limit 1");
            EquipmentBreakdownType type = typeService.getOne(query);
            vo.setBreakdownName(type.getBreakdownName());
        }
        result.setRecords(list);
        return R.data(result);
    }

    @Override
    public R saveRule(EquipmentBreakdownRule rule) {
        // 判断 属性:标准:productKey ,是否重复
        LambdaQueryWrapper<EquipmentBreakdownRule> query = Wrappers.lambdaQuery();
        query.eq(EquipmentBreakdownRule::getIdentify, rule.getIdentify());
        List<EquipmentBreakdownRule> list = this.list(query);
        if (list != null) {
            for (EquipmentBreakdownRule equipmentBreakdownRule : list) {
                // 同一个属性值,只能   全部存在设备,或者全部不存在
                if (StrUtil.isNotBlank(rule.getProductKey())) {
                    if (StrUtil.isBlank(equipmentBreakdownRule.getProductKey())) {
                        return R.error("该属性不能指定设备");
                    }
                }
                if (StrUtil.isBlank(rule.getProductKey())) {
                    if (StrUtil.isNotBlank(equipmentBreakdownRule.getProductKey())) {
                        return R.error("该属性需要指定设备");
                    }
                }
            }
        }
        query.eq(EquipmentBreakdownRule::getStandard, rule.getStandard());
        query.eq(StrUtil.isNotBlank(rule.getProductKey()), EquipmentBreakdownRule::getProductKey, rule.getProductKey());
        int count = this.count(query);
        if (count > 0) {
            return R.error("属性及判断标准重复");
        }
        this.save(rule);
        String filed = new StringBuilder(rule.getIdentify())
                .append(":")
                .append(rule.getStandard())
                .append(":")
                .append(rule.getProductKey() != null ? rule.getProductKey() : "")
                .toString();
        //添加缓存
        nestRedis.hSet(CacheNames.EQ_BREAKDOWN_RULE_KEY, filed, rule);
        return R.data(true);
    }

    @Override
    public R deleteRule(EquipmentBreakdownRule rule) {
        EquipmentBreakdownRule byId = this.getById(rule.getId());
        this.removeById(rule.getId());
        String filed = new StringBuilder(byId.getIdentify())
                .append(":")
                .append(byId.getStandard())
                .append(":")
                .append(byId.getProductKey() != null ? byId.getProductKey() : "")
                .toString();
        //删除缓存
        nestRedis.hDel(CacheNames.EQ_BREAKDOWN_RULE_KEY, filed);
        return R.data(true);
    }

    /**
     * 获得设备故障标准map
     *
     * @return
     */
    private Map<String, EquipmentBreakdownRule> getEquipmentBreakdownRuleMap() {
        Map<String, EquipmentBreakdownRule> map = nestRedis.hGetAll(CacheNames.EQ_BREAKDOWN_RULE_KEY);
        if (!MapUtils.isEmpty(map)) {
            return map;
        }
        List<EquipmentBreakdownRule> list = this.list();
        map = list.stream().collect(Collectors.toMap(rule -> {
            String filed = new StringBuilder(rule.getIdentify())
                    .append(":")
                    .append(rule.getStandard())
                    .append(":")
                    .append(rule.getProductKey() != null ? rule.getProductKey() : "")
                    .toString();
            return filed;
        }, Function.identity(), (key1, key2) -> key2));
        // 放入缓存中 filed key = identify:standard:productKey
        nestRedis.getHashOps().putAll(CacheNames.EQ_BREAKDOWN_RULE_KEY, map);
        return map;
    }
}