package com.moral.api.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.moral.api.entity.*;
import com.moral.api.mapper.*;
import com.moral.api.pojo.vo.device.DeviceVO;
import com.moral.api.service.DeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moral.api.service.OrganizationService;
import com.moral.api.service.SysDictDataService;
import com.moral.api.util.CacheUtils;
import com.moral.api.util.AdjustDataUtils;
import com.moral.api.util.LogUtils;
import com.moral.constant.Constants;
import com.moral.constant.RedisConstants;
import com.moral.util.ConvertUtils;
import com.moral.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
/**
 * 
 * 设备表 服务实现类
 * 
 *
 * @author moral
 * @since 2021-05-11
 */
@Service
@Slf4j
public class DeviceServiceImpl extends ServiceImpl implements DeviceService {
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private ManageAccountMapper manageAccountMapper;
    @Autowired
    private OrganizationMapper organizationMapper;
    @Autowired
    private MonitorPointMapper monitorPointMapper;
    @Autowired
    private SysDictTypeMapper sysDictTypeMapper;
    @Autowired
    private SysDictDataMapper sysDictDataMapper;
    @Autowired
    private SysDictDataService sysDictDataService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OrganizationUnitAlarmMapper organizationUnitAlarmMapper;
    @Autowired
    private VersionSensorUnitMapper versionSensorUnitMapper;
    @Autowired
    private SpecialDeviceMapper specialDeviceMapper;
    @Autowired
    private AdjustDataUtils adjustDataUtils;
    @Autowired
    private OrganizationService organizationService;
    /*
     * 从redis获取设备信息
     * */
    private Map getDeviceInfoFromRedis(String mac) {
        return (Map) redisTemplate.opsForHash().get(RedisConstants.DEVICE, mac);
    }
    /*
     * 设备信息存入redis
     */
    private void setDeviceInfoToRedis(String mac, Map deviceInfo) {
        redisTemplate.opsForHash().put(RedisConstants.DEVICE, mac, deviceInfo);
    }
    /*
     * 从redis删除设备信息
     */
    private void delDeviceInfoFromRedis(String mac) {
        redisTemplate.opsForHash().delete(RedisConstants.DEVICE, mac);
    }
    @Override
    @Transactional
    public void insert(Device device) {
        Integer orgId = monitorPointMapper.selectById(device.getMonitorPointId()).getOrganizationId();
        device.setOrganizationId(orgId);
        deviceMapper.insert(device);
        Map deviceInfo = selectDeviceInfoById(device.getId());
        //维护组织型号关系表
        insertOrganizationUnitAlarm(orgId, device.getDeviceVersionId());
        //新增设备信息存入redis
        String mac = device.getMac();
        //从redis中删除设备信息
        delDeviceInfoFromRedis(mac);
        //设备信息存入redis
        setDeviceInfoToRedis(mac, deviceInfo);
        //刷新deviceInfo缓存
        CacheUtils.refreshDeviceAlarmInfo();
        //操作日志记录
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        StringBuilder content = new StringBuilder();
        content.append("添加了设备:").append(device.getName()).append(":").append("mac:").append(mac);
        LogUtils.saveOperationForManage(request, content.toString(), Constants.INSERT_OPERATE_TYPE);
    }
    @Override
    @Transactional
    public void delete(Integer deviceId) {
        Device device = deviceMapper.selectById(deviceId);
        UpdateWrapper updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", deviceId).set("is_delete", Constants.DELETE);
        deviceMapper.update(null, updateWrapper);
        String mac = device.getMac();
        //从redis中删除设备信息
        delDeviceInfoFromRedis(mac);
        //维护组织型号关系表
        Integer versionId = device.getDeviceVersionId();
        Integer orgId = device.getOrganizationId();
        deleteOrganizationUnitAlarm(orgId, versionId);
        //刷新deviceInfo缓存
        CacheUtils.refreshDeviceAlarmInfo();
        //操作日志记录
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        StringBuilder content = new StringBuilder();
        content.append("删除了设备:").append(device.getName()).append(";").append("mac:").append(mac);
        LogUtils.saveOperationForManage(request, content.toString(), Constants.DELETE_OPERATE_TYPE);
    }
    @Override
    @Transactional
    public void update(Device device) {
        Integer deviceId = device.getId();
        Device oldDevice = deviceMapper.selectById(deviceId);
        //判断是否更新了站点,如果更新了站点则查询对应站点的组织id进行更新
        if (!ObjectUtils.isEmpty(device.getMonitorPointId())) {
            MonitorPoint monitorPoint = monitorPointMapper.selectById(device.getMonitorPointId());
            device.setOrganizationId(monitorPoint.getOrganizationId());
        }
        deviceMapper.updateById(device);
        Device updateDevice = deviceMapper.selectById(deviceId);
        String mac = updateDevice.getMac();
        //维护组织型号关系表
        Integer oldOrgId = oldDevice.getOrganizationId();
        Integer newOrgId = updateDevice.getOrganizationId();
        Integer oldVersionId = oldDevice.getDeviceVersionId();
        Integer newVersionId = updateDevice.getDeviceVersionId();
        if (!oldOrgId.equals(newOrgId) || !oldVersionId.equals(newVersionId)) {
            deleteOrganizationUnitAlarm(oldOrgId, oldVersionId);
            insertOrganizationUnitAlarm(newOrgId, newVersionId);
        }
        //从redis中删除设备信息
        delDeviceInfoFromRedis(oldDevice.getMac());
        Map deviceInfo = selectDeviceInfoById(deviceId);
        //设备信息存入redis
        setDeviceInfoToRedis(mac, deviceInfo);
        //刷新deviceInfo缓存
        CacheUtils.refreshDeviceAlarmInfo(mac);
        //操作日志记录
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        StringBuilder content = new StringBuilder();
        content.append("修改了设备:" + oldDevice.getMac()).append("==>").append(mac).append(":");
        Field[] fields = Device.class.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().equals("id")) {
                continue;
            }
            if ("serialVersionUID".equals(field.getName())) {
                continue;
            }
            String fieldName = field.getName();
            PropertyDescriptor pd = null;
            try {
                pd = new PropertyDescriptor(fieldName, Device.class);
                Method method = pd.getReadMethod();
                Object o1 = method.invoke(oldDevice);
                Object o2 = method.invoke(device);
                if (o2 != null) {
                    content.append(fieldName).append(":").append(o1).append("-->").append(o2).append(":");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        LogUtils.saveOperationForManage(request, content.toString(), Constants.UPDATE_OPERATE_TYPE);
    }
    @Override
    public List