package com.sptg.iot.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.sptg.common.core.beans.ResultBean;
import com.sptg.common.core.beans.ResultEnum;
import com.sptg.common.core.constant.OperationConstant;
import com.sptg.common.core.util.JsonUtils;
import com.sptg.iot.api.beans.ApiResultBean;
import com.sptg.iot.api.beans.IotReturnCode;
import com.sptg.iot.api.beans.PageData;
import com.sptg.iot.api.dto.DeviceStatusNoticeDto;
import com.sptg.iot.api.dto.HeartbeatNoticeDto;
import com.sptg.iot.api.dto.IotDeviceDto;
import com.sptg.iot.api.entity.IotAuthentication;
import com.sptg.iot.api.entity.IotDevice;
import com.sptg.iot.api.entity.IotSysConf;
import com.sptg.iot.api.util.IotHttpUtil;
import com.sptg.iot.biz.mapper.IotDeviceMapper;
import com.sptg.iot.biz.service.IotApiLogServiceInterface;
import com.sptg.iot.biz.service.IotAuthServiceInterface;
import com.sptg.iot.biz.service.IotDeviceServiceInterface;
import com.sptg.iot.biz.service.IotSysConfServiceInterface;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @author zwx
 * @create 2020/10/22 17:32
 */
@Service
@RequiredArgsConstructor
public class IotDeviceServiceImpl extends ServiceImpl<IotDeviceMapper, IotDevice> implements IotDeviceServiceInterface {

    private final IotSysConfServiceInterface iotSysConfServiceInterface;
    private final IotApiLogServiceInterface iotApiLogServiceInterface;
    private final IotAuthServiceInterface iotAuthServiceInterface;

    @Override
    public ResultBean<Page<IotDevice>> showIotDeviceList(IotDeviceDto iotDeviceDto) {
        Page<IotDevice> page = iotDeviceDto.getPage();
        Wrapper<IotDevice> wrapper = new EntityWrapper<>();
        String device_type = iotDeviceDto.getDevice_type();
        if(StringUtils.hasText(device_type)){
            wrapper.eq("s_device_type", device_type);
        }
        page.setRecords(this.baseMapper.getList(wrapper));
        return new ResultBean<>(ResultEnum.SUCCESS, page);
    }

    @Override
    public ResultBean<Page<IotDevice>> pagingQuery(IotDeviceDto iotDeviceDto) {
        Page<IotDevice> page = iotDeviceDto.getPage();
        Wrapper<IotDevice> wrapper = new EntityWrapper<>();
        String device_type = iotDeviceDto.getDevice_type();
        String device_id = iotDeviceDto.getDevice_id();
        String status = iotDeviceDto.getStatus();
        Integer defense_status = iotDeviceDto.getDefense_status();
        if(StringUtils.hasText(device_type)){
            wrapper.eq("s_device_type", device_type);
        }
        if(StringUtils.hasText(device_id)){
            wrapper.eq("s_device_id", device_id);
        }
        if(StringUtils.hasText(status)){
            wrapper.eq("s_status", status);
        }
        if(defense_status != null){
            wrapper.eq("s_defense_status", defense_status);
        }
        page.setRecords(this.baseMapper.pagingQuery(wrapper,iotDeviceDto.getPage()));
        return new ResultBean<>(ResultEnum.SUCCESS,page);
    }

    @Override
    public IotDevice getIotDeviceById(Long id) {
        Wrapper<IotDevice> wrapper = new EntityWrapper<>();
        wrapper.eq("l_id", id);
        IotDevice iotDevice = this.baseMapper.getOne(wrapper);
        return iotDevice;
    }

    @Override
    public ResultBean<IotDevice> deviceHeartbeatNotice(List<HeartbeatNoticeDto> heartbeatDtoList) {
        ApiResultBean apiResultBean = new ApiResultBean();
        apiResultBean.setCode(0);
        apiResultBean.setMsg("成功");
        String apiMethod = "heartbeat/notice";
        String reqData = JsonUtils.objectToJson(heartbeatDtoList);
        HeartbeatNoticeDto heartbeatNoticeDto = heartbeatDtoList.get(0);
        String device_id = heartbeatNoticeDto.getDevice_id();
        IotDevice target = this.getIotDeviceByDeviceId(device_id);
        if(target == null){
            apiResultBean.setCode(-1);
            apiResultBean.setMsg("未找到设备记录");
            this.iotApiLogServiceInterface.recordIotApiLog(apiMethod, null, null, reqData, apiResultBean);
            return new ResultBean<>(ResultEnum.SUCCESS, null);
        }else{
            Map<String, Object> paramMap = new HashMap<>();
            for(int i = 0; i < heartbeatDtoList.size(); i++){
                HeartbeatNoticeDto source = heartbeatDtoList.get(i);
                paramMap.put(source.getMetric(), source.getDevice_data());
            }
            String specialData = JSONUtil.toJsonStr(paramMap);
            target.setSpecialData(specialData);
            target.setLastHeartbeatDate(new Date());
            this.iotApiLogServiceInterface.recordIotApiLog(apiMethod, null, null, reqData, apiResultBean);
            boolean b = this.updateById(target);
            if(b){
                return new ResultBean<>(ResultEnum.SUCCESS, target);
            }else{
                return new ResultBean<>(ResultEnum.FAILURE, null);
            }
        }
    }

    @Override
    public ResultBean<IotDevice> deviceStatusNotice(DeviceStatusNoticeDto deviceStatusNoticeDto) {
        ApiResultBean apiResultBean = new ApiResultBean();
        apiResultBean.setCode(0);
        apiResultBean.setMsg("成功");
        String apiMethod = "deviceStatus/notice";
        String reqData = JsonUtils.objectToJson(deviceStatusNoticeDto);
        String deviceId = deviceStatusNoticeDto.getDevice_id();
        String status = deviceStatusNoticeDto.getDevice_status();
        IotDevice target = this.getIotDeviceByDeviceId(deviceId);
        if(target == null){
            apiResultBean.setCode(-1);
            apiResultBean.setMsg("未找到设备记录");
            this.iotApiLogServiceInterface.recordIotApiLog(apiMethod, null, null, reqData, apiResultBean);
            return new ResultBean<>(ResultEnum.SUCCESS, null);
        }else{
            target.setStatus(status);
            target.setLastStatusChangeDate(new Date());
            this.iotApiLogServiceInterface.recordIotApiLog(apiMethod, null, null, reqData, apiResultBean);
            boolean b = this.updateById(target);
            if(b){
                return new ResultBean<>(ResultEnum.SUCCESS, target);
            }else{
                return new ResultBean<>(ResultEnum.FAILURE, null);
            }
        }
    }

    @Override
    public ResultBean<String> iotDeviceRegister(IotDeviceDto iotDeviceDto) {
        Map<String, Object> bizParamsMap = new HashMap<>();
        bizParamsMap.put("device_id", iotDeviceDto.getIMEI());
        bizParamsMap.put("imei", iotDeviceDto.getIMEI());
        bizParamsMap.put("device_name", iotDeviceDto.getDevice_name());
        bizParamsMap.put("is_aep", iotDeviceDto.getIs_aep());
        bizParamsMap.put("operator", iotDeviceDto.getOperator());
        bizParamsMap.put("product_id", iotDeviceDto.getProduct_id());
        bizParamsMap.put("auto_observer", iotDeviceDto.getAuto_observer());
        bizParamsMap.put("imsi", iotDeviceDto.getIMSI());
        bizParamsMap.put("psk_value", iotDeviceDto.getPsk_value());
        bizParamsMap.put("device_type", iotDeviceDto.getDevice_type());
        bizParamsMap.put("manufacturers_no", iotDeviceDto.getManufacturers_no());
        bizParamsMap.put("device_specld", iotDeviceDto.getDevice_specld());
        bizParamsMap.put("protocol_type", iotDeviceDto.getProtocol_type());
        bizParamsMap.put("tag", iotDeviceDto.getTag());
        bizParamsMap.put("latitude_longitude", iotDeviceDto.getLatitude_longitude());
        bizParamsMap.put("area", iotDeviceDto.getArea());
        bizParamsMap.put("organization", iotDeviceDto.getOrganization());
        bizParamsMap.put("person", iotDeviceDto.getPerson_id());
        bizParamsMap.put("ammeterId", iotDeviceDto.getPerson_id());
        bizParamsMap.put("device_install_address", iotDeviceDto.getDevice_install_address());
        bizParamsMap.put("dist_locate", iotDeviceDto.getDist_locate());
        List<IotSysConf> iotSysConfList = this.iotSysConfServiceInterface.selectList(null);
        IotSysConf iotSysConf = iotSysConfList.get(0);
        IotHttpUtil httpUtil = new IotHttpUtil(iotSysConf);
        String appId = iotSysConf.getAppId();
        IotAuthentication iotAuthentication = this.iotAuthServiceInterface.findByAppId(appId);
        String accessToken = iotAuthentication.getAccessToken();
        ApiResultBean<IotAuthentication> apiResultBean = httpUtil.register(bizParamsMap, iotDeviceDto.getPrefix(), accessToken);
        Map<String, Object> status = apiResultBean.getStatus();
        if(status.get("code").equals(OperationConstant.ZERO)){
            return new ResultBean<>(ResultEnum.SUCCESS, "注册成功");
        }
        return new ResultBean<>(ResultEnum.FAILURE, apiResultBean.getMsg());
    }

    @Async
    @Override
    public ResultBean<String> syncIotDeviceList(IotDeviceDto iotDeviceDto) {
        List<IotSysConf> iotSysConfList = this.iotSysConfServiceInterface.selectList(null);
        List<IotDevice> allIotDeviceList = new ArrayList<>();
        for(int i = 0; i < iotSysConfList.size(); i++){
            IotSysConf iotSysConf = iotSysConfList.get(i);
            String appId = iotSysConf.getAppId();
            IotAuthentication iotAuthentication = this.iotAuthServiceInterface.findByAppId(appId);
            if(iotAuthentication != null){
                IotHttpUtil httpUtil = new IotHttpUtil(iotSysConf);
                List<IotDevice> iotDeviceList = new ArrayList<>();
                Map<String, Object> bizParamsMap = BeanUtil.beanToMap(iotDeviceDto);
                String[] prefixList = iotSysConf.getPrefix().split(",");
                for(int j = 0; j < prefixList.length; j++){
                    String prefix = prefixList[j];
                    String accessToken = iotAuthentication.getAccessToken();
                    ApiResultBean<PageData<IotDevice>> apiResultBean = httpUtil.syncIotDeviceList(bizParamsMap, prefix, accessToken);
                    String reqData = JsonUtils.objectToJson(bizParamsMap);
                    if(apiResultBean.getCode().equals(IotReturnCode.UNAUTHORIZED.getCode())){ //未认证，提示先去认证
                        this.iotApiLogServiceInterface.recordIotApiLog("/device/list", prefix, appId, reqData, apiResultBean);
                        return new ResultBean<>(ResultEnum.FAILURE, IotReturnCode.UNAUTHORIZED.toString());
                    }
                    if(apiResultBean.getCode().equals(OperationConstant.ZERO)){
                        PageData<IotDevice> pageData = apiResultBean.getData();
                        List<IotDevice> items = pageData.getItems();
                        items.forEach(iotDevice -> {
                            iotDevice.setLastSyncDate(new Date());
                            iotDevice.setAppId(appId);
                            iotDevice.setPrefix(prefix);
                        });
                        iotDeviceList.addAll(items);
                        this.iotApiLogServiceInterface.recordIotApiLog("/device/list", prefix, appId, reqData, apiResultBean);
                    }
                }
                allIotDeviceList.addAll(iotDeviceList); //将该应用ID下的所有设备记录下来
            }
        }
        List<IotDevice> updateIotDeviceList = new ArrayList<>();
        if(allIotDeviceList.size() > 0){
            allIotDeviceList.forEach(source ->{
                IotDevice target = this.getIotDeviceByDeviceId(source.getDevice_id());
                if(target == null){
                    source.setId(null);
                    target = new IotDevice();
                }else{
                    source.setId(target.getId());
                }
                BeanUtil.copyProperties(source, target);
                updateIotDeviceList.add(target);
            });
        }
        boolean result = this.insertOrUpdateBatch(updateIotDeviceList, 100);
        if(result){
            return new ResultBean<>(ResultEnum.SUCCESS, "同步成功");
        }else{
            return new ResultBean<>(ResultEnum.FAILURE, "同步成功，但保存失败");
        }
    }

    @Override
    public ResultBean<String> syncIotDeviceListByPrefix(List<String> prefixList) {
        if(prefixList == null && prefixList.size() == 0){
            return new ResultBean<>(ResultEnum.PARAMETER_ANOMALY);
        }
        List<IotSysConf> iotSysConfList = this.iotSysConfServiceInterface.selectList(null);
        IotSysConf iotSysConf = iotSysConfList.get(0);
        String appId = iotSysConf.getAppId();
        IotAuthentication iotAuthentication = this.iotAuthServiceInterface.findByAppId(appId);
        String accessToken = iotAuthentication.getAccessToken();
        IotHttpUtil httpUtil = new IotHttpUtil(iotSysConf);
        List<IotDevice> allIotDeviceList = new ArrayList<>();
        for(String prefix : prefixList){
            Map<String, Object> bizParamsMap = new HashMap<>();
            ApiResultBean<PageData<IotDevice>> apiResultBean = httpUtil.syncIotDeviceList(bizParamsMap, prefix, accessToken);
            String reqData = JsonUtils.objectToJson(bizParamsMap);
            if(apiResultBean.getCode().equals(IotReturnCode.UNAUTHORIZED.getCode())){ //未认证，提示先去认证
                this.iotApiLogServiceInterface.recordIotApiLog("/device/list", prefix, appId, reqData, apiResultBean);
                return new ResultBean<>(ResultEnum.FAILURE, IotReturnCode.UNAUTHORIZED.toString());
            }
            List<IotDevice> iotDeviceList = new ArrayList<>();
            if(apiResultBean.getCode().equals(OperationConstant.ZERO)){
                PageData<IotDevice> pageData = apiResultBean.getData();
                List<IotDevice> items = pageData.getItems();
                items.forEach(iotDevice -> {
                    iotDevice.setLastSyncDate(new Date());
                    iotDevice.setAppId(appId);
                    iotDevice.setPrefix(prefix);
                });
                iotDeviceList.addAll(items);
                this.iotApiLogServiceInterface.recordIotApiLog("/device/list", prefix, appId, reqData, apiResultBean);
            }
            allIotDeviceList.addAll(iotDeviceList);
        }
        List<IotDevice> updateIotDeviceList = new ArrayList<>();
        if(allIotDeviceList.size() > 0){
            allIotDeviceList.forEach(source ->{
                IotDevice target = this.getIotDeviceByDeviceId(source.getDevice_id());
                if(target == null){
                    source.setId(null);
                    target = new IotDevice();
                }else{
                    source.setId(target.getId());
                }
                BeanUtil.copyProperties(source, target);
                updateIotDeviceList.add(target);
            });
        }
        if(updateIotDeviceList.size() > 0){
            boolean result = this.insertOrUpdateBatch(updateIotDeviceList, 1000);
            if(result){
                return new ResultBean<>(ResultEnum.SUCCESS, "同步成功");
            }else{
                return new ResultBean<>(ResultEnum.FAILURE, "同步成功，但保存失败");
            }
        }else{
            return new ResultBean<>(ResultEnum.SUCCESS, "无信息需同步");
        }
    }

    @Override
    public ResultBean<String> syncIotDeviceDetailOne(IotDeviceDto iotDeviceDto) {
        String appId = iotDeviceDto.getAppId();
        String prefix = iotDeviceDto.getPrefix();
        IotSysConf iotSysConf = this.iotSysConfServiceInterface.findSysConfByAppId(appId);
        IotAuthentication iotAuthentication = this.iotAuthServiceInterface.findByAppId(appId);
        String accessToken = iotAuthentication.getAccessToken();
        IotHttpUtil httpUtil = new IotHttpUtil(iotSysConf);
        Map<String, Object> bizParamsMap = BeanUtil.beanToMap(iotDeviceDto);
        ApiResultBean<IotDevice> apiResultBean = httpUtil.syncIotDeviceDetail(bizParamsMap, prefix, accessToken);
        String reqData = JsonUtils.objectToJson(iotDeviceDto);
        if(apiResultBean.getCode().equals(IotReturnCode.UNAUTHORIZED.getCode())){ //未认证，提示先去认证
            this.iotApiLogServiceInterface.recordIotApiLog("/device/search", prefix, appId, reqData, apiResultBean);
            return new ResultBean<>(ResultEnum.FAILURE, IotReturnCode.UNAUTHORIZED.toString());
        }
        this.iotApiLogServiceInterface.recordIotApiLog("/device/search", prefix, appId, reqData, apiResultBean);
        if(apiResultBean.getCode().equals(OperationConstant.ZERO)){
            IotDevice source = apiResultBean.getData();
            if(source != null){
                IotDevice target = this.getIotDeviceByDeviceId(source.getDevice_id());
                if(target == null){
                    source.setId(null);
                    target = new IotDevice();
                }else{
                    source.setId(target.getId());
                }
                BeanUtil.copyProperties(source, target);
                target.setAppId(appId);
                target.setPrefix(prefix);
                target.setLastSyncDate(new Date());
                boolean b = this.insertOrUpdate(target);
                if(b){
                    return new ResultBean<>(ResultEnum.SUCCESS, "同步设备详情成功");
                }else{
                    return new ResultBean<>(ResultEnum.FAILURE, "同步设备详情成功，但保存失败");
                }
            }else{
                return new ResultBean<>(ResultEnum.FAILURE, apiResultBean.getMsg());
            }
        }else{
            return new ResultBean<>(ResultEnum.FAILURE, apiResultBean.getMsg());
        }
    }

    @Override
    public ResultBean<String> syncIotDeviceDetailBatch(List<IotDeviceDto> iotDeviceDtoList) {
        List<IotDevice> updateIotDeviceList = new ArrayList<>();
        for(int i = 0; i < iotDeviceDtoList.size(); i++){
            IotDeviceDto iotDeviceDto = iotDeviceDtoList.get(i);
            String appId = iotDeviceDto.getAppId();
            IotSysConf iotSysConf = this.iotSysConfServiceInterface.findSysConfByAppId(appId);
            IotAuthentication iotAuthentication = this.iotAuthServiceInterface.findByAppId(appId);
            String accessToken = iotAuthentication.getAccessToken();
            IotHttpUtil httpUtil = new IotHttpUtil(iotSysConf);
            String prefix = iotDeviceDto.getPrefix();
            Map<String, Object> bizParamsMap = BeanUtil.beanToMap(iotDeviceDto);
            ApiResultBean<IotDevice> apiResultBean = httpUtil.syncIotDeviceDetail(bizParamsMap, prefix, accessToken);
            String reqData = JsonUtils.objectToJson(iotDeviceDto);
            if(apiResultBean.getCode().equals(IotReturnCode.UNAUTHORIZED.getCode())){ //未认证，提示先去认证
                this.iotApiLogServiceInterface.recordIotApiLog("/device/search", prefix, appId, reqData, apiResultBean);
                return new ResultBean<>(ResultEnum.FAILURE, IotReturnCode.UNAUTHORIZED.toString());
            }
            this.iotApiLogServiceInterface.recordIotApiLog("/device/search", prefix, appId, reqData, apiResultBean);
            if(apiResultBean.getCode().equals(OperationConstant.ZERO)){
                IotDevice source = apiResultBean.getData();
                if(source != null){
                    IotDevice target = this.getIotDeviceByDeviceId(source.getDevice_id());
                    if(target == null){
                        source.setId(null);
                        target = new IotDevice();
                    }else{
                        source.setId(target.getId());
                    }
                    BeanUtil.copyProperties(source, target);
                    target.setAppId(appId);
                    target.setPrefix(prefix);
                    target.setLastSyncDate(new Date());
                    updateIotDeviceList.add(target);
                }
            }
        }
        if(updateIotDeviceList.size() > 0){
            boolean b = this.insertOrUpdateBatch(updateIotDeviceList);
            if(b){
                return new ResultBean<>(ResultEnum.SUCCESS, "批量（部分）同步设备详情成功");
            }else{
                return new ResultBean<>(ResultEnum.FAILURE, "批量（部分）同步设备详情成功，但保存失败");
            }
        }else{
            return new ResultBean<>(ResultEnum.SUCCESS, "批量（部分）同步设备详情失败，请查看同步日志");
        }
    }

    @Async
    @Override
    public ResultBean<String> syncIotDeviceDetailAll(IotDeviceDto iotDeviceDto) {
        List<IotDevice> updateIotDeviceList = new ArrayList<>();
        Wrapper<IotDevice> wrapper = new EntityWrapper<>();
        List<IotDevice> iotDeviceList = this.baseMapper.getList(wrapper);
        for(int i = 0; i < iotDeviceList.size(); i++){
            IotDevice iotDevice = iotDeviceList.get(i);
            String appId = iotDevice.getAppId();
            String prefix = iotDevice.getPrefix();
            IotSysConf iotSysConf = this.iotSysConfServiceInterface.findSysConfByAppId(appId);
            IotAuthentication iotAuthentication = this.iotAuthServiceInterface.findByAppId(appId);
            String accessToken = iotAuthentication.getAccessToken();
            IotHttpUtil httpUtil = new IotHttpUtil(iotSysConf);
            Map<String, Object> bizParamsMap = BeanUtil.beanToMap(iotDevice);
            ApiResultBean<IotDevice> apiResultBean = httpUtil.syncIotDeviceDetail(bizParamsMap, prefix, accessToken);
            String reqData = JsonUtils.objectToJson(iotDevice);
            if(apiResultBean.getCode().equals(IotReturnCode.UNAUTHORIZED.getCode())){ //未认证，提示先去认证
                this.iotApiLogServiceInterface.recordIotApiLog("/device/search", prefix, appId, reqData, apiResultBean);
                return new ResultBean<>(ResultEnum.FAILURE, IotReturnCode.UNAUTHORIZED.toString());
            }
            this.iotApiLogServiceInterface.recordIotApiLog("/device/search", prefix, appId, reqData, apiResultBean);
            if(apiResultBean.getCode().equals(OperationConstant.ZERO)){
                IotDevice source = apiResultBean.getData();
                if(source != null){
                    IotDevice target = this.getIotDeviceByDeviceId(source.getDevice_id());
                    if(target == null){
                        source.setId(null);
                        target = new IotDevice();
                    }else{
                        source.setId(target.getId());
                    }
                    BeanUtil.copyProperties(source, target);
                    target.setAppId(appId);
                    target.setPrefix(prefix);
                    target.setLastSyncDate(new Date());
                    updateIotDeviceList.add(target);
                }
            }
        }
        if(updateIotDeviceList.size() > 0){
            boolean b = this.insertOrUpdateBatch(updateIotDeviceList);
            if(b){
                return new ResultBean<>(ResultEnum.SUCCESS, "全量同步设备详情成功");
            }else{
                return new ResultBean<>(ResultEnum.FAILURE, "全量同步设备详情成功，但保存失败");
            }
        }else{
            return new ResultBean<>(ResultEnum.SUCCESS, "全量同步设备详情失败，请查看同步日志");
        }
    }

    @Override
    public IotDevice getIotDeviceByDeviceId(String deviceId) {
        Wrapper<IotDevice> wrapper = new EntityWrapper<>();
        wrapper.eq("s_device_id", deviceId);
        return this.baseMapper.getOne(wrapper);
    }

    @Override
    public ResultBean<String> deviceStatusChange(IotDevice iotDevice) {
        Wrapper<IotDevice> wrapper = new EntityWrapper<>();
        wrapper.eq("s_device_id", iotDevice.getDevice_id());
        Integer update = this.baseMapper.update(iotDevice, wrapper);
        if(update > 0){
            return new ResultBean<>(ResultEnum.SUCCESS, "更新成功");
        }else{
            return new ResultBean<>(ResultEnum.FAILURE, "更新失败");
        }
    }

    @Override
    public List<IotDevice> getList() {
        Wrapper<IotDevice> wrapper = new EntityWrapper<>();
        return this.baseMapper.getList(wrapper);
    }
}
