package cn.iocoder.yudao.module.pms.service.yanfan.device;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.cache.ITSLValueCache;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.constant.Constants;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.device.vo.DeviceShortOutput;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.device.vo.YfIotDevicePageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.device.vo.YfIotDeviceRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.device.vo.YfIotDeviceSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.product.vo.IotYfProductRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.redis.RedisCache;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.redis.RedisKeyBuilder;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.sip.relation.vo.IotYfSipRelationPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.thingsmodel.vo.ValueItem;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils.HttpUtils;
import cn.iocoder.yudao.module.pms.controller.admin.yanfan.utils.IpUtils;
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.device.YfIotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.devicetemplate.IotYfDeviceTemplateDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.product.IotYfProductDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.sip.relation.IotYfSipRelationDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.var.slave.IotYfVarTempSalveDO;
import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.device.YfIotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.devicetemplate.IotYfDeviceTemplateMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.yanfan.product.IotYfProductMapper;
import cn.iocoder.yudao.module.pms.service.yanfan.devicetemplate.IotYfDeviceTemplateService;
import cn.iocoder.yudao.module.pms.service.yanfan.product.IotYfProductService;
import cn.iocoder.yudao.module.pms.service.yanfan.sip.relation.IotYfSipRelationService;
import cn.iocoder.yudao.module.pms.service.yanfan.var.slave.IotVarTempSalveService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 设备 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
@Slf4j
public class YfIotDeviceServiceImpl implements YfIotDeviceService {

    @Resource
    private YfIotDeviceMapper yfIotDeviceMapper;
    @Autowired
    private IotYfProductService iotYfProductService;
    @Autowired
    private AdminUserApi adminUserApi;
    @Resource
    private ITSLValueCache itslValueCache;
    @Autowired
    private IotYfDeviceTemplateService iotYfDeviceTemplateService;
    @Autowired
    private IotVarTempSalveService iotVarTempSalveService;
    @Autowired
    private IotYfSipRelationService iotYfSipRelationService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IotYfDeviceTemplateMapper iotYfDeviceTemplateMapper;
    @Autowired
    private IotYfProductMapper iotYfProductMapper;
    @Autowired
    private DeptService deptService;


    /**
     * 修改设备
     *
     * @param device 设备
     * @return 结果
     */
    @Caching(evict = {
            @CacheEvict(value = "device", key = "'selectDeviceBySerialNumber_' + #device.getSerialNumber()"),
            @CacheEvict(value = "device", key = "'selectDeviceByDeviceId_' + #device.getDeviceId()"),
            @CacheEvict(value = "device", key = "'selectShortDeviceBySerialNumber_' + #device.getSerialNumber()")
    })
    @Override
    public void updateDevice(YfIotDeviceDO device) {
        // 设备编号唯一检查
        YfIotDeviceRespVO oldDevice = yfIotDeviceMapper.selectDeviceByDeviceId(device.getDeviceId());
        if (!oldDevice.getSerialNumber().equals(device.getSerialNumber())) {
            YfIotDeviceDO existDevice = yfIotDeviceMapper.selectDeviceBySerialNumber(device.getSerialNumber());
            if (existDevice != null) {
                log.error("设备编号：" + device.getSerialNumber() + " 已经存在，新增设备失败");
//                return AjaxResult.error("设备编号：" + device.getSerialNumber() + " 已经存在，修改失败", 0);
                throw new ServiceException(new ErrorCode(2, "设备编号：" + device.getSerialNumber() + " 已经存在，修改失败"));
            }
        }
        device.setUpdateTime(LocalDateTime.now());
        // 未激活状态,可以修改产品以及物模型值
        if (device.getStatus() == 1) {
            // 缓存设备状态（物模型值）
            itslValueCache.addCacheDeviceStatus(device.getProductId(), device.getSerialNumber());

        } else {
            device.setProductId(null);
            device.setProductName(null);
        }
        yfIotDeviceMapper.updateById(device);
    }

    /**
     * 根据设备编号查询设备
     *
     * @param serialNumber 设备主键
     * @return 设备
     */
    @Override
    @Cacheable(value = "device", key = "#root.methodName + '_' + #serialNumber", unless = "#result == null")
    @TenantIgnore
    public YfIotDeviceDO selectDeviceBySerialNumber(String serialNumber) {
        YfIotDeviceDO device = yfIotDeviceMapper.selectDeviceBySerialNumber(serialNumber);
        if (!Objects.isNull(device)) {
            // redis中获取设备状态（物模型值）
            List<ValueItem> list = itslValueCache.getCacheDeviceStatus(device.getProductId(), device.getSerialNumber());
            if (list != null && list.size() > 0) {
                device.setThingsModelValue(JSONObject.toJSONString(list));
            }
        }
        return device;
    }

    /**
     * 删除设备
     *
     * @param deviceId 需要删除的设备主键
     * @return 结果
     */
    @CacheEvict(value = "device", allEntries = true)
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDeviceByDeviceId(Long deviceId) {
        //查询设备
        YfIotDeviceRespVO device = yfIotDeviceMapper.selectDeviceByDeviceId(deviceId);
        //判断设备是否有子产品
        List<String> strings = yfIotDeviceMapper.selectGwDevCodeList(device.getSerialNumber());
        if (null != strings && strings.size() > 0) {
            yfIotDeviceMapper.delGwDevCode(device.getSerialNumber());
        }
        //删除生命周期
        //todo yf
//        yfIotDeviceMapper.deleteDeviceLifecyle(deviceId);
        // redis中删除规则脚本
        String cacheKey = RedisKeyBuilder.buildDeviceMsgCacheKey(device.getSerialNumber());
        redisCache.deleteObject(cacheKey);
        // 删除设备
        yfIotDeviceMapper.deleteDeviceByDeviceIds(new Long[]{deviceId});
    }

    /**
     * 查询设备分页简短列表
     *
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<DeviceShortOutput> selectDeviceShortList(YfIotDeviceSaveReqVO device) {
        Long deptId = SecurityFrameworkUtils.getLoginUserDeptId();
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(deptId)) {
            ids = deptService.getChildDeptIdListFromCache(deptId);
            ids.add(deptId);
        }
        device.setDeptIds(ids);
        List<DeviceShortOutput> list = yfIotDeviceMapper.selectDeviceShortList(device);
//        List<DeviceAlertCount> alist = alertLogService.selectDeviceAlertCount();
//        for (DeviceAlertCount item : alist) {
//            list
//                    .stream()
//                    .filter(it -> Objects.equals(it.getSerialNumber(), item.getSerialNumber()))
//                    .forEach(it -> it.setAlertCount(item));
//        }
        return list;
    }

    @Override
    public String generationDeviceNum(Integer type) {
        // 设备编号：D + userId + 15位随机字母和数字
        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        String number;
        //Hex随机字符串
        if (type == 3) {
            number = cn.iocoder.yudao.module.pms.util.StringUtils.generateRandomHex(12);
        } else {
            number = "D" + user.getId().toString() + cn.iocoder.yudao.module.pms.util.StringUtils.getStringRandomYf(10);
        }
        int count = yfIotDeviceMapper.getDeviceNumCount(number);
        if (count == 0) {
            return number;
        } else {
            generationDeviceNum(type);
        }
        return "";
    }

    /**
     * 查询设备
     *
     * @param deviceId 设备主键
     * @return 设备
     */
    @Cacheable(value = "device", key = "#root.methodName + '_' + #deviceId", unless = "#result == null")
    @Override
    public YfIotDeviceRespVO selectDeviceByDeviceId(Long deviceId) {
        YfIotDeviceRespVO device = yfIotDeviceMapper.selectDeviceByDeviceId(deviceId);
        List<ValueItem> list = itslValueCache.getCacheDeviceStatus(device.getProductId(), device.getSerialNumber());
        if (list != null && list.size() > 0) {
            // redis中获取设备状态（物模型值）
            device.setThingsModelValue(JSONObject.toJSONString(list));
        }
        //查询关联的监控设备
        IotYfSipRelationPageReqVO sipRelation = new IotYfSipRelationPageReqVO();
        sipRelation.setReDeviceId(deviceId);
        List<IotYfSipRelationDO> sipRelationList = iotYfSipRelationService.selectSipRelationList(sipRelation);
        device.setSipRelationList(sipRelationList);

        /*查询子设备*/
        if (device != null) {
            YfIotDeviceSaveReqVO yfIotDeviceSaveReqVO = new YfIotDeviceSaveReqVO();
            yfIotDeviceSaveReqVO.setGwDevCode(device.getSerialNumber());
            List<YfIotDeviceRespVO> subDeviceList = yfIotDeviceMapper.selectDeviceList(yfIotDeviceSaveReqVO);
            //获取子设备的首地址
            if (!CollectionUtils.isEmpty(subDeviceList)) {
                device.setSlaveId(subDeviceList.get(0).getSlaveId());
            }
            device.setSubDeviceList(subDeviceList);
            // 没图片用产品图片
            if (StringUtils.isEmpty(device.getImgUrl())) {
                device.setImgUrl(iotYfProductService.selectImgUrlByProductId(device.getProductId()));
            }
        }
        return device;
    }

    @Override
    public YfIotDeviceDO createYfIotDevice(YfIotDeviceSaveReqVO createReqVO) {

        List<YfIotDeviceDO> serialNumber = yfIotDeviceMapper.selectList("serial_number", createReqVO.getSerialNumber());
        if (CollUtil.isNotEmpty(serialNumber)) {
            throw new ServiceException(new ErrorCode(111,"设备编码已存在"));
        }
        YfIotDeviceDO device = BeanUtils.toBean(createReqVO, YfIotDeviceDO.class);
        //添加设备
        device.setCreateTime(LocalDateTime.now());
        device.setTenantId(1L);
        device.setRssi(0);
        // 设置图片
        IotYfProductRespVO product = iotYfProductService.getIotProduct(device.getProductId());
        device.setImgUrl(product.getImgUrl());
        // 随机经纬度和地址
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        AdminUserRespDTO user = adminUserApi.getUser(loginUserId);

        device.setNetworkIp(user.getLoginIp());
        setLocation(user.getLoginIp(), device);
        device.setDeleted(false);
        yfIotDeviceMapper.insert(device);

        // redis缓存设备默认状态（物模型值）
        itslValueCache.addCacheDeviceStatus(device.getProductId(), device.getSerialNumber());
        /*如果设备属于网关设备并且关联有采集点模板将根据采集点模板自动添加子设备*/
        IotYfDeviceTemplateDO deviceTemplate = iotYfDeviceTemplateMapper.selectOne("product_id", device.getProductId());

        if (null != deviceTemplate) {
            IotYfVarTempSalveDO tempSalve = new IotYfVarTempSalveDO();
            tempSalve.setDeviceTempId(deviceTemplate.getTemplateId());
            /**从机列表*/
            //todo yf
            List<IotYfVarTempSalveDO> salveList = iotVarTempSalveService.selectVarTempSalveList(tempSalve);
            if (!CollectionUtils.isEmpty(salveList)) {
                salveList.forEach(var -> {
                    //从机设备编号唯一 设备编号+_+从机编号
                    YfIotDeviceDO subDev = new YfIotDeviceDO();
                    org.springframework.beans.BeanUtils.copyProperties(device, subDev);
                    subDev.setSerialNumber(device.getSerialNumber() + "_" + var.getSlaveAddr());
                    subDev.setGwDevCode(device.getSerialNumber());
                    subDev.setDeviceName(var.getSlaveName());
                    subDev.setSlaveId(var.getSlaveAddr());
                    subDev.setDeleted(false);
                    yfIotDeviceMapper.insert(subDev);
                });
            }
        }


        // 返回设备信息
        List<ValueItem> list = itslValueCache.getCacheDeviceStatus(device.getProductId(), device.getSerialNumber());
        if (list != null && list.size() > 0) {
            device.setThingsModelValue(JSONObject.toJSONString(list));
        }
        /*查询子设备*/
        YfIotDeviceDO subBo = new YfIotDeviceDO();
        subBo.setGwDevCode(device.getSerialNumber());
        YfIotDeviceSaveReqVO yfIotDeviceSaveReqVO = new YfIotDeviceSaveReqVO();
        BeanUtils.copyProperties(device, yfIotDeviceSaveReqVO);
        List<YfIotDeviceRespVO> subDeviceList = yfIotDeviceMapper.selectDeviceList(yfIotDeviceSaveReqVO);
        //获取子设备的首地址
        //todo yf
//        if (!CollectionUtils.isEmpty(subDeviceList)) {
//            device.setSlaveId(subDeviceList.get(0).getSlaveId());
//        }
        YfIotDeviceRespVO respVO = BeanUtils.toBean(device, YfIotDeviceRespVO.class);
        respVO.setSubDeviceList(subDeviceList);
//        if (getUserId() != 1) {
//            insertDeviceShare(getUserId(), device);
//        }
//        deviceMapper.addDeviceLifecyle(device.getDeviceId());
        return device;
    }


    /**
     * 根据IP获取地址
     *
     * @param ip
     * @return
     */
    private void setLocation(String ip, YfIotDeviceDO device) {
        String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
        String address = "未知地址";
        device.setNetworkAddress(address);
        // 内网不查询
        if (IpUtils.internalIp(ip)) {
            device.setNetworkAddress("内网IP");
            return;
        }

        try {
            String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK);
            if (!StringUtils.isEmpty(rspStr)) {
                JSONObject obj = JSONObject.parseObject(rspStr);
                device.setNetworkAddress(obj.getString("addr"));
                // 查询经纬度
                setLatitudeAndLongitude(obj.getString("city"), device);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 设置经纬度
     *
     * @param city
     */
    private void setLatitudeAndLongitude(String city, YfIotDeviceDO device) {
        String BAIDU_URL = "https://api.map.baidu.com/geocoder";
        String baiduResponse = HttpUtils.sendGet(BAIDU_URL, "address=" + city + "&output=json", Constants.GBK);
        if (!StringUtils.isEmpty(baiduResponse)) {
            JSONObject baiduObject = JSONObject.parseObject(baiduResponse);
            JSONObject location = baiduObject.getJSONObject("result").getJSONObject("location");
            device.setLongitude(location.getBigDecimal("lng"));
            device.setLatitude(location.getBigDecimal("lat"));
            System.out.println(device.getSerialNumber() + "- 设置经度：" + location.getBigDecimal("lng") + "，设置纬度：" + location.getBigDecimal("lat"));
        }
    }
    @Override
    public void updateYfIotDevice(YfIotDeviceSaveReqVO updateReqVO) {
        // 校验存在
        validateYfIotDeviceExists(updateReqVO.getDeviceId());
        // 更新
        YfIotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, YfIotDeviceDO.class);
        yfIotDeviceMapper.updateById(updateObj);
    }

    @Override
    public void deleteYfIotDevice(Long id) {
        // 校验存在
        validateYfIotDeviceExists(id);
        // 删除
        yfIotDeviceMapper.deleteById(id);
    }

    private void validateYfIotDeviceExists(Long id) {
        if (yfIotDeviceMapper.selectById(id) == null) {
            throw exception(new ErrorCode(222, "不存在"));
        }
    }

    @Override
    public YfIotDeviceDO getYfIotDevice(Long id) {
        return yfIotDeviceMapper.selectById(id);
    }

    @Override
    public PageResult<YfIotDeviceDO> getYfIotDevicePage(YfIotDevicePageReqVO pageReqVO) {
        return yfIotDeviceMapper.selectPage(pageReqVO);
    }


    /**
     * 设备认证后自动添加设备
     *
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertDeviceAuto(String serialNumber, Long userId, Long productId) {
        // 设备编号唯一检查
        int count = yfIotDeviceMapper.selectDeviceCountBySerialNumber(serialNumber);
        if (count != 0) {
            log.error("设备编号：" + serialNumber + "已经存在了，新增设备失败");
            return 0;
        }
        IotYfProductDO product = iotYfProductMapper.selectById(productId);
        if (product == null) {
            log.error("自动添加设备时，根据产品ID查找不到对应产品");
            return 0;
        }
        YfIotDeviceDO device = new YfIotDeviceDO();
        device.setSerialNumber(serialNumber);
//        SysUser user = userService.getDeptUserByUserId(userId);
//        device.setTenantId(user.getUserId());
//        device.setTenantName(user.getUserName());
        device.setFirmwareVersion(BigDecimal.valueOf(1.0));
        // 设备状态（1-未激活，2-禁用，3-在线，4-离线）
        device.setStatus(3);
        device.setActiveTime(LocalDateTime.now());
        device.setIsShadow(0);
        device.setRssi(0);
        // 1-自动定位，2-设备定位，3-自定义位置
        device.setLocationWay(3);
        device.setCreateTime(LocalDateTime.now());
        // 随机位置
        device.setLongitude(BigDecimal.valueOf(116.23 - (Math.random() * 15)));
        device.setLatitude(BigDecimal.valueOf(39.54 - (Math.random() * 15)));
        device.setNetworkAddress("中国");
        device.setNetworkIp("127.0.0.1");

        int random = (int) (Math.random() * (90)) + 10;
        device.setDeviceName(product.getProductName() + random);
        device.setImgUrl(product.getImgUrl());
        device.setProductId(product.getProductId());
        device.setProductName(product.getProductName());
        int result = yfIotDeviceMapper.insert(device);

        // 缓存设备状态
        itslValueCache.addCacheDeviceStatus(device.getProductId(), device.getSerialNumber());
        return result;
    }


    /**
     * @param device 设备状态和定位更新
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDeviceStatusAndLocation(YfIotDeviceDO device, String ipAddress) {
        // 设置自动定位和状态
        if (ipAddress != null && !Objects.equals(ipAddress, "")) {
            if (device.getActiveTime() == null) {
                device.setActiveTime(LocalDateTime.now());
                yfIotDeviceMapper.updateDeviceStatus(device);
            }
            // 定位方式(1=ip自动定位，2=设备定位，3=自定义)
            if (device.getLocationWay() == 1) {
                //todo yf
//                AsyncManager.me().execute(new TimerTask() {
//                    @Override
//                    public void run() {
//                        Device newDevice = new Device();
//                        newDevice.setStatus(device.getStatus());
//                        newDevice.setSerialNumber(device.getSerialNumber());
//                        newDevice.setDeviceId(device.getDeviceId());
//                        newDevice.setNetworkIp(ipAddress);
//                        newDevice.setUpdateTime(newDevice.getUpdateTime());
//                        setLocation(ipAddress, newDevice);
//                        deviceMapper.updateDeviceStatus(newDevice);
//                    }
//                });
            }
        }

//        AsyncManager.me().execute(new TimerTask() {
//            @Override
//            public void run() {
//
//                // 添加到设备日志
//                EventLog event = new EventLog();
//                event.setDeviceId(device.getDeviceId());
//                event.setDeviceName(device.getDeviceName());
//                event.setSerialNumber(device.getSerialNumber());
//                event.setIsMonitor(0);
//                event.setUserId(device.getTenantId());
//                event.setUserName(device.getTenantName());
//                event.setCreateTime(DateUtils.getNowDate());
//                // 日志模式 1=影子模式，2=在线模式，3=其他
//                event.setMode(3);
//                if (device.getStatus() == 3) {
//                    event.setLogValue("1");
//                    event.setRemark("设备上线");
//                    event.setIdentity("online");
//                    event.setLogType(5);
//                } else if (device.getStatus() == 4) {
//                    event.setLogValue("0");
//                    event.setRemark("设备离线");
//                    event.setIdentity("offline");
//                    event.setLogType(6);
//                }
//                eventLogMapper.insertEventLog(event);            }
//        });
        return 1;
    }
}
