package com.usky.demo.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.usky.common.core.exception.BusinessException;
import com.usky.demo.domain.*;
import com.usky.demo.mapper.QueryInfluxdbDataMapper;
import com.usky.demo.service.DmpDeviceService;
import com.usky.demo.service.DmpProductService;
import com.usky.demo.service.QueryInfluxdbDataService;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.demo.service.rocketmq.MyProducer;
import com.usky.demo.service.utils.TsdbUtils;
import com.usky.demo.service.vo.DeviceMapVO;
import com.usky.demo.service.vo.ProductMapVO;
import org.apache.commons.collections.ResettableListIterator;
import org.influxdb.dto.QueryResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ya
 * @since 2024-07-29
 */
@Service
public class QueryInfluxdbDataServiceImpl extends AbstractCrudService<QueryInfluxdbDataMapper, QueryInfluxdbData> implements QueryInfluxdbDataService {
    @Autowired
    private TsdbUtils tsdbUtils;
    @Autowired
    private DmpProductService dmpProductService;
    @Autowired
    private DmpDeviceService dmpDeviceService;

    @Value("${spring.influx.database}")
    private String database;


    @Cacheable(cacheNames = "productList",sync = true)
    public Map<String, ProductMapVO> getProductMap(){
        Map<String,ProductMapVO> productMap = new HashMap<>();
        LambdaQueryWrapper<DmpProduct> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DmpProduct::getDeleteFlag,0)
                .orderByDesc(DmpProduct::getId);
        List<DmpProduct> list = dmpProductService.list(queryWrapper);
        if(CollectionUtils.isNotEmpty(list)){
            for (int i = 0; i < list.size(); i++) {
                String productCode = list.get(i).getProductCode();
                ProductMapVO mapVO = new ProductMapVO();
                mapVO.setProductId(list.get(i).getId());
                mapVO.setProductCode(list.get(i).getProductCode());
                mapVO.setCreatedBy(list.get(i).getCreatedBy());
                mapVO.setTenantId(list.get(i).getTenantId());
                mapVO.setDeviceType(list.get(i).getDeviceType());

                productMap.put(productCode,mapVO);
            }
        }


        return productMap;
    }

    @Cacheable(cacheNames = "deviceList",sync = true)
    public Map<String, DeviceMapVO> getDeviceMap(){
        Map<String,DeviceMapVO> deviceMap = new HashMap<>();
        LambdaQueryWrapper<DmpDevice> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DmpDevice::getDeleteFlag,0)
                .orderByDesc(DmpDevice::getId);
        List<DmpDevice> list = dmpDeviceService.list(queryWrapper);
        if(CollectionUtils.isNotEmpty(list)){
            for (int i = 0; i < list.size(); i++) {
                String deviceId = list.get(i).getDeviceId();
                DeviceMapVO mapVO = new DeviceMapVO();
                mapVO.setProductCode(list.get(i).getProductCode());
                mapVO.setDeviceId(list.get(i).getDeviceId());
                mapVO.setDeviceUuid(list.get(i).getDeviceUuid());
                mapVO.setDeviceStatus(list.get(i).getServiceStatus());

                deviceMap.put(deviceId,mapVO);
            }
        }

        return deviceMap;
    }

    @Override
    public LastResultVO queryLastDeviceData(String deviceUUId){

        String tableName = deviceUUId;
        String query = "SELECT *::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
        List<Map<String, Object>> metrics = tsdbUtils.fetchRecords(query);
        String tagQuery = "SELECT \"deviceid\",*::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
        List<Map<String, String>> tag = tsdbUtils.fetchTagRecords(tagQuery);
        LastResultVO resultVO = new LastResultVO();
        if(tag.size() == 0){
            Map<String,String> tagMap = new HashMap<>();
            tagMap.put("deviceId","");
            tag.add(tagMap);
            resultVO.setDeviceUUId(deviceUUId);
            resultVO.setTags(tag);
            resultVO.setMetrics(metrics);
        }else{
            resultVO.setDeviceUUId(deviceUUId);
            resultVO.setTags(tag);
            resultVO.setMetrics(metrics);
        }

        return resultVO;
    }

    @Override
    public List<LastResultVO> queryLastDeviceData(LastRequestVO requestVO){
        List<LastResultVO> result = new ArrayList<>();
        List<String> deviceUUIds = requestVO.getDeviceUUId();
        if(CollectionUtils.isNotEmpty(deviceUUIds)){
            for (int i = 0; i < deviceUUIds.size(); i++) {
                String tableName = deviceUUIds.get(i);
                String query = "SELECT *::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
                List<Map<String, Object>> metrics = tsdbUtils.fetchRecords(query);
                String tagQuery = "SELECT \"deviceid\",*::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
                List<Map<String, String>> tag = tsdbUtils.fetchTagRecords(tagQuery);
                LastResultVO resultVO = new LastResultVO();
                resultVO.setDeviceUUId(deviceUUIds.get(i));
                resultVO.setTags(tag);
                resultVO.setMetrics(metrics);
                result.add(resultVO);
            }
        }

        return result;

    }

    @Override
    public HistoryResultVO queryHistoryDeviceData(String deviceUUId,String startTime,String endTime){
        List<MetricVO> metricList = new ArrayList<>();
        String tableName = deviceUUId;
        String query = "SELECT *::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
        QueryResult queryResult = tsdbUtils.query(query);
        String tagQuery = "SELECT \"deviceid\",*::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
        List<Map<String, String>> tag = tsdbUtils.fetchTagRecords(tagQuery);
        if(queryResult.getResults().get(0).getSeries() != null){
            List<String> fields = queryResult.getResults().get(0).getSeries().get(0).getColumns();
            if(CollectionUtils.isNotEmpty(fields)){
                String fieldQuery = "SELECT *::field FROM \""+tableName+"\" where time >= '"+startTime+"' and time <= '"+endTime+"' tz('Asia/Shanghai')";
                List<Map<String,Object>> metircs = tsdbUtils.fetchRecords(fieldQuery);

                if(CollectionUtils.isNotEmpty(metircs)){
                    for (int j = 0; j < fields.size(); j++) {
                        List<Map<String,Object>> metircItems = new ArrayList<>();
                        if(!"time".equals(fields.get(j))){
                            for (int k = 0; k < metircs.size(); k++) {
                                String field = fields.get(j);
                                Map<String,Object> map = new HashMap<>();
                                map.put("timestamp",metircs.get(k).get("time"));
                                map.put("value",metircs.get(k).get(field));
                                metircItems.add(map);
                            }
                            MetricVO metricVO = new MetricVO();
                            metricVO.setMetric(fields.get(j));
                            metricVO.setMetricItems(metircItems);
                            metricList.add(metricVO);
                        }

                    }
                }

            }
        }

        HistoryResultVO resultVO = new HistoryResultVO();
        resultVO.setDeviceUUId(deviceUUId);
        resultVO.setTags(tag);
        resultVO.setMetrics(metricList);
        return resultVO;
    }

    @Override
    public List<HistoryResultVO> queryHistoryDeviceData(HistoryRequestVO requestVO){
        List<HistoryResultVO> list = new ArrayList<>();
        List<String> deviceIds = requestVO.getDeviceUUId();
        String startTime = requestVO.getStartTime();
        String endTime = requestVO.getEndTime();
        for (int i = 0; i < deviceIds.size(); i++) {
            List<MetricVO> metricList = new ArrayList<>();
            String tableName = deviceIds.get(i);
            String query = "SELECT *::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
            QueryResult queryResult = tsdbUtils.query(query);
            String tagQuery = "SELECT \"deviceid\",*::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
            List<Map<String, String>> tag = tsdbUtils.fetchTagRecords(tagQuery);
            if(queryResult.getResults().get(0).getSeries() != null){
                List<String> fields = queryResult.getResults().get(0).getSeries().get(0).getColumns();
                if(CollectionUtils.isNotEmpty(fields)){
                    String fieldQuery = "SELECT *::field FROM \""+tableName+"\" where time >= '"+startTime+"' and time <= '"+endTime+"' tz('Asia/Shanghai')";
                    List<Map<String,Object>> metircs = tsdbUtils.fetchRecords(fieldQuery);

                    if(CollectionUtils.isNotEmpty(metircs)){
                        for (int j = 0; j < fields.size(); j++) {
                            List<Map<String,Object>> metircItems = new ArrayList<>();
                            if(!"time".equals(fields.get(j))){
                                for (int k = 0; k < metircs.size(); k++) {
                                    String field = fields.get(j);
                                    Map<String,Object> map = new HashMap<>();
                                    map.put("timestamp",metircs.get(k).get("time"));
                                    map.put("value",metircs.get(k).get(field));
                                    metircItems.add(map);
                                }
                                MetricVO metricVO = new MetricVO();
                                metricVO.setMetric(fields.get(j));
                                metricVO.setMetricItems(metircItems);
                                metricList.add(metricVO);
                            }

                        }
                    }

                }
            }

            HistoryResultVO resultVO = new HistoryResultVO();
            resultVO.setDeviceUUId(deviceIds.get(i));
            resultVO.setTags(tag);
            resultVO.setMetrics(metricList);
            list.add(resultVO);
        }

        return list;
    }

    @Override
    public List<Map<String, Object>> getAllDeviceRealTime(){
        // 构建查询语句，获取所有 measurement 的最新数据
        String queryStr = "SELECT *::field FROM datarealtime tz('Asia/Shanghai')";

        return tsdbUtils.fetchRealTimeRecords(queryStr);
    }

    @Override
    public List<LastInnerResultVO> last(LastInnerQueryVO requestVO){
        List<LastInnerResultVO> list = new ArrayList<>();
        List<String> deviceUUIds = requestVO.getDeviceuuid();
        List<String> metrics = requestVO.getMetrics();
//        if(CollectionUtils.isNotEmpty(metrics)){
//            String metricStr = "\""+metrics.get(0)+"\"";
//            for (int i = 1; i < metrics.size(); i++) {
//                metricStr=metricStr.concat(",\""+metrics.get(i)+"\"");
//            }
//            for (int i = 0; i < deviceUUIds.size(); i++) {
//                String tableName = deviceUUIds.get(i);
//                LastInnerResultVO resultVO = new LastInnerResultVO();
//                resultVO.setDeviceuuid(deviceUUIds.get(i));
//
//                String tagQuery = "SELECT \"device_id\",*::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
//                List<Map<String, String>> tag = tsdbUtils.fetchTagRecords(tagQuery);
//                if(CollectionUtils.isNotEmpty(tag)){
//                    resultVO.setTags(tag.get(0));
//                    String query = "SELECT time,"+metricStr+" FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
//                    List<Map<String, Object>> metricList = tsdbUtils.fetchRecords(query);
//                    if(CollectionUtils.isEmpty(metricList)){
//                        throw new BusinessException(tableName+"设备没有对应属性，请添加");
//                    }
//                    resultVO.setMetrics(metricList.get(0));
//                }
//
//                list.add(resultVO);
//            }
//
//        }else{
//            for (int i = 0; i < deviceUUIds.size(); i++) {
//                String tableName = deviceUUIds.get(i);
//                LastInnerResultVO resultVO = new LastInnerResultVO();
//                resultVO.setDeviceuuid(deviceUUIds.get(i));
//                String tagQuery = "SELECT \"device_id\",*::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
//                List<Map<String, String>> tag = tsdbUtils.fetchTagRecords(tagQuery);
//                if(CollectionUtils.isNotEmpty(tag)){
//                    resultVO.setTags(tag.get(0));
//                    String query = "SELECT *::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
//                    List<Map<String, Object>> metricList = tsdbUtils.fetchRecords(query);
//                    resultVO.setMetrics(metricList.get(0));
//                }
//                list.add(resultVO);
//            }
//        }

        String deviceUUId = "device_uuid='"+deviceUUIds.get(0)+"'";
        for (int i = 1; i < deviceUUIds.size(); i++) {
            deviceUUId=deviceUUId.concat(" or device_uuid='"+deviceUUIds.get(i)+"'");
        }
        if(CollectionUtils.isNotEmpty(metrics)){
            String metricStr = "\""+metrics.get(0)+"\"";
            for (int i = 1; i < metrics.size(); i++) {
                metricStr=metricStr.concat(",\""+metrics.get(i)+"\"");
            }
            String query = "SELECT \"realtime\",\"device_uuid\",\"device_id\","+metricStr+" FROM \"datarealtime\" where ("+deviceUUId+") tz('Asia/Shanghai')";
            List<Map<String, Object>> metricList = tsdbUtils.fetchRecords(query);
            if(CollectionUtils.isNotEmpty(metricList)){
                for (int i = 0; i < metricList.size(); i++) {
                    LastInnerResultVO resultVO = new LastInnerResultVO();
                    resultVO.setDeviceuuid(metricList.get(i).get("device_uuid").toString());
                    Map<String, String> tag = new HashMap<String,String>();
                    tag.put("device_id",metricList.get(i).get("device_id").toString());
                    resultVO.setTags(tag);
                    resultVO.setMetrics(metricList.get(i));

                    list.add(resultVO);
                }
            }

        }else{
            String query = "SELECT *::field FROM \"datarealtime\" where ("+deviceUUId+") tz('Asia/Shanghai')";
            List<Map<String, Object>> metricList = tsdbUtils.fetchRecords(query);
            if(CollectionUtils.isNotEmpty(metricList)){
                for (int i = 0; i < metricList.size(); i++) {
                    LastInnerResultVO resultVO = new LastInnerResultVO();
                    resultVO.setDeviceuuid(metricList.get(i).get("device_uuid").toString());
                    Map<String, String> tag = new HashMap<String,String>();
                    tag.put("device_id",metricList.get(i).get("device_id").toString());
                    resultVO.setTags(tag);
                    resultVO.setMetrics(metricList.get(i));

                    list.add(resultVO);
                }
            }
        }

        return list;
    }

    @Override
    public List<HistorysInnerResultVO> history(HistorysInnerRequestVO requestVO){
        List<HistorysInnerResultVO> list = new ArrayList<>();
        String startTime = requestVO.getStartTime();
        String endTime = requestVO.getEndTime();
        List<String> deviceUUIds = requestVO.getDeviceuuid();
        List<String> metrics = requestVO.getMetrics();
        if(CollectionUtils.isNotEmpty(metrics)){
            String metricStr = "\""+metrics.get(0)+"\"";
            for (int i = 1; i < metrics.size(); i++) {
                metricStr=metricStr.concat(",\""+metrics.get(i)+"\"");
            }
            for (int i = 0; i < deviceUUIds.size(); i++) {
                List<MetricVO> metricList = new ArrayList<>();
                String tableName = deviceUUIds.get(i);
                HistorysInnerResultVO resultVO = new HistorysInnerResultVO();
                resultVO.setDeviceuuid(deviceUUIds.get(i));
                String tagQuery = "SELECT \"device_id\",*::field FROM \""+tableName+"\" where time >= '"+startTime+"' and time <= '"+endTime+"' tz('Asia/Shanghai')";
                List<Map<String, String>> tag = tsdbUtils.fetchTagRecords(tagQuery);
                if(CollectionUtils.isNotEmpty(tag)){
                    resultVO.setTags(tag.get(0));

                    String fieldQuery = "SELECT time,"+metricStr+" FROM \""+tableName+"\" where time >= '"+startTime+"' and time <= '"+endTime+"' tz('Asia/Shanghai')";
                    List<Map<String,Object>> metircList = tsdbUtils.fetchRecords(fieldQuery);
                    if(CollectionUtils.isEmpty(metircList)){
                        throw new BusinessException(tableName+"设备没有对应属性，请添加");
                    }

                    for (int j = 0; j < metrics.size(); j++) {
                        if(!"time".equals(metrics.get(j))){
                            List<Map<String,Object>> metircItems = new ArrayList<>();
                            MetricVO metricVO = new MetricVO();
                            metricVO.setMetric(metrics.get(j));
                            if(CollectionUtils.isNotEmpty(metircList)){
                                for (int k = 0; k < metircList.size(); k++) {
                                    String field = metrics.get(j);
                                    Map<String,Object> map = new HashMap<>();
                                    map.put("timestamp",metircList.get(k).get("time"));
                                    if(Objects.isNull(metircList.get(k).get(field)))
                                        break;
                                    map.put("value",metircList.get(k).get(field));
                                    metircItems.add(map);
                                }
                                metricVO.setMetricItems(metircItems);
                            }
                            metricList.add(metricVO);
                        }

                    }
                    resultVO.setMetrics(metricList);
                }

                list.add(resultVO);
            }

        }else{
            for (int i = 0; i < deviceUUIds.size(); i++) {
                List<MetricVO> metricList = new ArrayList<>();
                String tableName = deviceUUIds.get(i);
                HistorysInnerResultVO resultVO = new HistorysInnerResultVO();
                resultVO.setDeviceuuid(deviceUUIds.get(i));
                String query = "SELECT *::field FROM \""+tableName+"\" order by desc limit 1 tz('Asia/Shanghai')";
                QueryResult queryResult = tsdbUtils.query(query);
                if(queryResult.getResults().get(0).getSeries() != null){
                    String tagQuery = "SELECT \"device_id\",*::field FROM \""+tableName+"\" where time >= '"+startTime+"' and time <= '"+endTime+"' tz('Asia/Shanghai')";
                    List<Map<String, String>> tag = tsdbUtils.fetchTagRecords(tagQuery);
                    if(CollectionUtils.isNotEmpty(tag)){
                        resultVO.setTags(tag.get(0));

                        List<String> fields = queryResult.getResults().get(0).getSeries().get(0).getColumns();
                        if(CollectionUtils.isNotEmpty(fields)){
                            String fieldQuery = "SELECT *::field FROM \""+tableName+"\" where time >= '"+startTime+"' and time <= '"+endTime+"' tz('Asia/Shanghai')";
                            List<Map<String,Object>> metircs = tsdbUtils.fetchRecords(fieldQuery);

                            for (int j = 0; j < fields.size(); j++) {
                                if(!"time".equals(fields.get(j))){
                                    List<Map<String,Object>> metircItems = new ArrayList<>();
                                    MetricVO metricVO = new MetricVO();
                                    metricVO.setMetric(fields.get(j));
                                    if(CollectionUtils.isNotEmpty(metircs)){
                                        for (int k = 0; k < metircs.size(); k++) {
                                            String field = fields.get(j);
                                            Map<String,Object> map = new HashMap<>();
                                            map.put("timestamp",metircs.get(k).get("time"));
                                            map.put("value",metircs.get(k).get(field));
                                            metircItems.add(map);
                                        }
                                        metricVO.setMetricItems(metircItems);
                                    }
                                    metricList.add(metricVO);
                                }

                            }

                        }
                        resultVO.setMetrics(metricList);
                    }
                }
                list.add(resultVO);
            }
        }


        return list;
    }


}
