package com.fuyuanshen.web.service;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.app.domain.AppDeviceBindRecord;
import com.fuyuanshen.app.domain.AppDeviceShare;
import com.fuyuanshen.app.domain.AppPersonnelInfo;
import com.fuyuanshen.app.domain.bo.AppDeviceShareBo;
import com.fuyuanshen.app.domain.vo.AppDeviceShareDetailVo;
import com.fuyuanshen.app.domain.vo.AppDeviceShareVo;
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper;
import com.fuyuanshen.app.mapper.AppDeviceShareMapper;
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.exception.ServiceException;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.DeviceType;
import com.fuyuanshen.equipment.mapper.DeviceMapper;
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;


@RequiredArgsConstructor
@Slf4j
@Service
public class DeviceShareService {

    private final AppDeviceShareMapper appDeviceShareMapper;

    private final DeviceMapper deviceMapper;

    private final DeviceTypeMapper deviceTypeMapper;

    private final AppPersonnelInfoMapper appPersonnelInfoMapper;

    private final AppDeviceBindRecordMapper appDeviceBindRecordMapper;

    public TableDataInfo<AppDeviceShareVo> queryPageList(AppDeviceShareBo bo, PageQuery pageQuery) {
        Long userId = AppLoginHelper.getUserId();
        bo.setCreateBy(userId);
        Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        Page<AppDeviceShareVo> result = appDeviceShareMapper.selectAppDeviceShareList(bo, page);
        List<AppDeviceShareVo> records = result.getRecords();
        records.forEach(DeviceShareService::buildDeviceStatus);
        return TableDataInfo.build(result);
    }

    public TableDataInfo<AppDeviceShareVo> queryWebPageList(AppDeviceShareBo bo, PageQuery pageQuery) {
//        Long userId = AppLoginHelper.getUserId();
//        bo.setCreateBy(userId);
        Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        Page<AppDeviceShareVo> result = appDeviceShareMapper.selectWebDeviceShareList(bo, page);
        List<AppDeviceShareVo> records = result.getRecords();
        records.forEach(DeviceShareService::buildDeviceStatus);
        return TableDataInfo.build(result);
    }

    private static void buildDeviceStatus(AppDeviceShareVo item) {
        // 设备在线状态
        String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
        if (StringUtils.isNotBlank(onlineStatus)) {

            item.setOnlineStatus(1);
        } else {
            item.setOnlineStatus(0);
        }
        String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX);
        // 获取电量
        if (StringUtils.isNotBlank(deviceStatus)) {
            JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
            item.setBattery(jsonObject.getString("batteryPercentage"));
        } else {
            item.setBattery("0");
        }

        String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_LOCATION_KEY_PREFIX);
        if (StringUtils.isNotBlank(location)) {
            JSONObject jsonObject = JSONObject.parseObject(location);
            item.setLatitude(jsonObject.getString("latitude"));
            item.setLongitude(jsonObject.getString("longitude"));
        }

        String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX);
        if (StringUtils.isNotBlank(alarmStatus)) {
            item.setAlarmStatus(alarmStatus);
        }
    }

    public AppDeviceShareDetailVo getInfo(Long id) {

        LambdaQueryWrapper<AppDeviceShare> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AppDeviceShare::getId, id);
        List<AppDeviceShareVo> appDeviceShareVos = appDeviceShareMapper.selectVoList(queryWrapper);
        if (appDeviceShareVos == null || appDeviceShareVos.isEmpty()) {
            return null;
        }

        AppDeviceShareVo shareVo = appDeviceShareVos.get(0);
        AppDeviceShareDetailVo shareDetailVo = new AppDeviceShareDetailVo();
        shareDetailVo.setId(shareVo.getId());
        shareDetailVo.setDeviceId(shareVo.getDeviceId());
        shareDetailVo.setPhonenumber(shareVo.getPhonenumber());
        shareDetailVo.setPermission(shareVo.getPermission());

        Device device = deviceMapper.selectById(shareVo.getDeviceId());
        shareDetailVo.setDeviceName(device.getDeviceName());
        shareDetailVo.setDeviceImei(device.getDeviceImei());
        shareDetailVo.setDeviceMac(device.getDeviceMac());

        DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
        if (deviceType != null) {
            shareDetailVo.setCommunicationMode(Integer.valueOf(deviceType.getCommunicationMode()));
        }
        shareDetailVo.setDevicePic(device.getDevicePic());
        shareDetailVo.setTypeName(deviceType.getTypeName());
        shareDetailVo.setBluetoothName(device.getBluetoothName());
        shareDetailVo.setDeviceStatus(device.getDeviceStatus());
        shareDetailVo.setSendMsg(device.getSendMsg());

        LambdaQueryWrapper<AppPersonnelInfo> qw = new LambdaQueryWrapper<>();
        qw.eq(AppPersonnelInfo::getDeviceId, device.getId());
        List<AppPersonnelInfoVo> appPersonnelInfoVos = appPersonnelInfoMapper.selectVoList(qw);
        if (appPersonnelInfoVos != null && !appPersonnelInfoVos.isEmpty()) {
            shareDetailVo.setPersonnelInfo(appPersonnelInfoVos.get(0));
        }
        // 设备在线状态
        String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
        if (StringUtils.isNotBlank(onlineStatus)) {
            shareDetailVo.setOnlineStatus(1);
        } else {
            shareDetailVo.setOnlineStatus(0);
        }
        String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX);
        // 获取电量
        if (StringUtils.isNotBlank(deviceStatus)) {
            JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
            shareDetailVo.setMainLightMode(jsonObject.getString("mainLightMode"));
            shareDetailVo.setLaserLightMode(jsonObject.getString("laserLightMode"));
            shareDetailVo.setBatteryPercentage(jsonObject.getString("batteryPercentage"));
            shareDetailVo.setChargeState(jsonObject.getString("chargeState"));
            shareDetailVo.setBatteryRemainingTime(jsonObject.getString("batteryRemainingTime"));
        } else {
            shareDetailVo.setBatteryPercentage("0");
        }

        // 获取经度纬度
        String locationKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
        String locationInfo = RedisUtils.getCacheObject(locationKey);
        if (StringUtils.isNotBlank(locationInfo)) {
            JSONObject jsonObject = JSONObject.parseObject(locationInfo);
            shareDetailVo.setLongitude(jsonObject.get("longitude").toString());
            shareDetailVo.setLatitude(jsonObject.get("latitude").toString());
            shareDetailVo.setAddress((String) jsonObject.get("address"));
        }


        String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX);
        if (StringUtils.isNotBlank(alarmStatus)) {
            shareDetailVo.setAlarmStatus(alarmStatus);
        }

        String lightBrightness = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX);
        if (StringUtils.isNotBlank(lightBrightness)) {
            shareDetailVo.setLightBrightness(lightBrightness);
        }

        return shareDetailVo;
    }

    /**
     * 校验短信验证码
     */
    private boolean validateSmsCode(String phonenumber, String smsCode) {
        String code = RedisUtils.getCacheObject(GlobalConstants.DEVICE_SHARE_CODES_KEY + phonenumber);
        if (StringUtils.isBlank(code)) {
            throw new ServiceException("验证码失效");
        }
        return code.equals(smsCode);
    }

    public int deviceShare(AppDeviceShareBo bo) {
        Device device = deviceMapper.selectById(bo.getDeviceId());
        if (device == null) {
            throw new ServiceException("设备不存在");
        }

        boolean flag = validateSmsCode( bo.getPhonenumber(), bo.getSmsCode());
        if (!flag) {
            throw new ServiceException("验证码错误");
        }

        LambdaQueryWrapper<AppDeviceBindRecord> qw = new LambdaQueryWrapper<>();
        qw.eq(AppDeviceBindRecord::getDeviceId, bo.getDeviceId());
        AppDeviceBindRecord bindRecord = appDeviceBindRecordMapper.selectOne(qw);
        if (bindRecord == null) {
            throw new ServiceException("设备未绑定");
        }
        Long userId = bindRecord.getBindingUserId();

        LambdaQueryWrapper<AppDeviceShare> lqw = new LambdaQueryWrapper<>();
        lqw.eq(AppDeviceShare::getDeviceId, bo.getDeviceId());
        lqw.eq(AppDeviceShare::getPhonenumber, bo.getPhonenumber());
        Long count = appDeviceShareMapper.selectCount(lqw);
        if (count > 0) {

            UpdateWrapper<AppDeviceShare> uw = new UpdateWrapper<>();
            uw.eq("device_id", bo.getDeviceId());
            uw.eq("phonenumber", bo.getPhonenumber());
            uw.set("permission", bo.getPermission());
            uw.set("update_by", userId);
            uw.set("update_time", new Date());

            return appDeviceShareMapper.update(uw);
        } else {
            AppDeviceShare appDeviceShare = new AppDeviceShare();
            appDeviceShare.setDeviceId(bo.getDeviceId());
            appDeviceShare.setPhonenumber(bo.getPhonenumber());
            appDeviceShare.setPermission(bo.getPermission());
            appDeviceShare.setCreateBy(userId);
            return appDeviceShareMapper.insert(appDeviceShare);
        }
    }

    public int permission(AppDeviceShareBo bo) {
        Device device = deviceMapper.selectById(bo.getDeviceId());
        if (device == null) {
            throw new ServiceException("设备不存在");
        }
        LambdaQueryWrapper<AppDeviceBindRecord> qw = new LambdaQueryWrapper<>();
        qw.eq(AppDeviceBindRecord::getDeviceId, bo.getDeviceId());
        AppDeviceBindRecord bindRecord = appDeviceBindRecordMapper.selectOne(qw);
        if (bindRecord == null) {
            throw new ServiceException("设备未绑定");
        }
        Long userId = bindRecord.getBindingUserId();

        LambdaQueryWrapper<AppDeviceShare> lqw = new LambdaQueryWrapper<>();
        lqw.eq(AppDeviceShare::getDeviceId, bo.getDeviceId());
        lqw.eq(AppDeviceShare::getPhonenumber, bo.getPhonenumber());
        Long count = appDeviceShareMapper.selectCount(lqw);
        if (count > 0) {

            UpdateWrapper<AppDeviceShare> uw = new UpdateWrapper<>();
            uw.eq("device_id", bo.getDeviceId());
            uw.eq("phonenumber", bo.getPhonenumber());
            uw.set("permission", bo.getPermission());
            uw.set("update_by", userId);
            uw.set("update_time", new Date());

            return appDeviceShareMapper.update(uw);
        } else {
            AppDeviceShare appDeviceShare = new AppDeviceShare();
            appDeviceShare.setDeviceId(bo.getDeviceId());
            appDeviceShare.setPhonenumber(bo.getPhonenumber());
            appDeviceShare.setPermission(bo.getPermission());
            appDeviceShare.setCreateBy(userId);
            return appDeviceShareMapper.insert(appDeviceShare);
        }
    }

    public int remove(Long[] ids) {
        return appDeviceShareMapper.deleteByIds(Arrays.asList(ids));
    }

    public TableDataInfo<AppDeviceShareVo> otherDeviceShareList(AppDeviceShareBo bo, PageQuery pageQuery) {
        String username = AppLoginHelper.getUsername();
        bo.setPhonenumber(username);
        Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        IPage<AppDeviceShareVo> result = appDeviceShareMapper.otherDeviceShareList(bo, page);
        List<AppDeviceShareVo> records = result.getRecords();

        records.forEach(DeviceShareService::buildDeviceStatus);
        return TableDataInfo.build(result);
    }


    /**
     * 查询设备分享列表(web)
     *
     * @param bo
     * @param pageQuery
     * @return
     */
    public TableDataInfo<AppDeviceShareVo> queryWebList(AppDeviceShareBo bo, PageQuery pageQuery) {
        Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        Page<AppDeviceShareVo> result = appDeviceShareMapper.selectWebDeviceShareList(bo, page);
        List<AppDeviceShareVo> records = result.getRecords();
        records.forEach(DeviceShareService::buildDeviceStatus);
        return TableDataInfo.build(result);
    }

}
