package com.usky.demo.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.demo.domain.*;
import com.usky.demo.mapper.QueryInfluxdbDataMapper;
import com.usky.demo.mapper.QueryTdengineDataMapper;
import com.usky.demo.service.DmpDeviceService;
import com.usky.demo.service.DmpProductService;
import com.usky.demo.service.QueryInfluxdbDataService;
import com.usky.demo.service.QueryTdengineDataService;
import com.usky.demo.service.utils.TsdbUtils;
import com.usky.demo.service.vo.DeviceMapVO;
import com.usky.demo.service.vo.ProductMapVO;
import com.usky.demo.service.vo.SuperTableVO;
import org.apache.commons.lang3.StringUtils;
import org.influxdb.dto.QueryResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ya
 * @since 2024-07-29
 */
@Service
@DS("taos")
public class QueryTdengineDataServiceImpl extends AbstractCrudService<QueryTdengineDataMapper, QueryTdengineData> implements QueryTdengineDataService {

    private static final Pattern SQL_IDENTIFIER_PATTERN = Pattern.compile("^[a-zA-Z_][a-zA-Z0-9_]*$");

    @Autowired
    private TsdbUtils tsdbUtils;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private QueryTdengineDataMapper queryTdengineDataMapper;

    @Override
    public List<LastInnerResultVO> tdengineLast(LastInnerQueryVO requestVO){
        List<LastInnerResultVO> list = new ArrayList<>();
        List<String> deviceUUIds = requestVO.getDeviceuuid();
        List<String> metrics = requestVO.getMetrics();


        // 遍历设备表集合，自动忽略表中不存在的字段，用有效字段构建查询，避免错误
        for (int i = 0; i < deviceUUIds.size(); i++) {

            String tablename = "_"+deviceUUIds.get(i);

            try (Connection connection = dataSource.getConnection()) {
                String sql = "describe " + tablename;

                try (PreparedStatement itemStmt = connection.prepareStatement(sql)) {
                    try (ResultSet resultSet = itemStmt.executeQuery()) {
                        String tagStr = "";
                        List<String> taglist = new ArrayList<>();
                        List<String> fieldKeys = new ArrayList<>();
                        while (resultSet.next()) {
                            String note = resultSet.getString("note");
                            if("TAG".equals(note)){
                                tagStr = tagStr.concat(resultSet.getString("field")+",");
                                taglist.add(resultSet.getString("field"));
                            }else{
                                fieldKeys.add(resultSet.getString("field"));
                            }
                        }
                        resultSet.close();

                        // 过滤有效字段
                        List<String> filterValidFields = new ArrayList<>();
                        if(CollectionUtils.isNotEmpty(metrics)){
                            filterValidFields = metrics.stream().filter(item -> fieldKeys.contains(item)).collect(Collectors.toList());
                        }else{
                            filterValidFields = fieldKeys;
                        }
                        String filterValidFieldStr = filterValidFields.stream().collect(Collectors.joining(","));
                        if(CollectionUtils.isEmpty(filterValidFields)){
                            throw new BusinessException(tablename+"没有可用属性，请添加");
                        }

                        String query = "SELECT ts,"+tagStr+filterValidFieldStr+" FROM "+tablename+" order by ts desc limit 1";
                        try (PreparedStatement itemStmt1 = connection.prepareStatement(query)) {
                            try (ResultSet metricList = itemStmt1.executeQuery()) {
                                while (metricList.next()) {
                                    LastInnerResultVO resultVO = new LastInnerResultVO();
                                    resultVO.setDeviceuuid(deviceUUIds.get(i));
                                    Map<String, String> tag = new HashMap<String,String>();
                                    for(int k=0;k<taglist.size();k++){
                                        tag.put(taglist.get(k),metricList.getString(taglist.get(k)));
                                    }
                                    resultVO.setTags(tag);

                                    Map<String, Object> field = new HashMap<String,Object>();
                                    field.put("realtime",metricList.getTimestamp("ts").getTime());
                                    for(int k =0;k<filterValidFields.size();k++){
                                        field.put(filterValidFields.get(k),metricList.getString(filterValidFields.get(k)));
                                    }
                                    resultVO.setMetrics(field);
                                    list.add(resultVO);
                                }
                            }
                        }

                    }
                }

            } catch (SQLException e) {
                // 判断TDengine专属错误码 0x2603 = 表不存在
                if (e.getMessage().contains("0x2603") || e.getMessage().contains("Table does not exist")) {
                    System.out.println("表" + tablename + "不存在，跳过");
                    log.error("表" + tablename + "不存在，跳过");
                } else {
                    // 其他异常正常打印堆栈
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return list;
    }

    @Override
    public List<HistorysInnerResultVO> tdengineHistory(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();

        // 遍历设备表集合，自动忽略表中不存在的字段，用有效字段构建查询，避免错误
        for (int i = 0; i < deviceUUIds.size(); i++) {

            String tablename = "_"+deviceUUIds.get(i);

            try (Connection connection = dataSource.getConnection()) {
                String sql = "describe " + tablename;

                try (PreparedStatement itemStmt = connection.prepareStatement(sql)) {
                    try (ResultSet resultSet = itemStmt.executeQuery()) {
                        String tagStr = "";
                        List<String> taglist = new ArrayList<>();
                        List<String> fieldKeys = new ArrayList<>();
                        while (resultSet.next()) {
                            String note = resultSet.getString("note");
                            if("TAG".equals(note)){
                                tagStr = tagStr.concat(resultSet.getString("field")+",");
                                taglist.add(resultSet.getString("field"));
                            }else{
                                fieldKeys.add(resultSet.getString("field"));
                            }
                        }
                        resultSet.close();

                        // 过滤有效字段
                        List<String> filterValidFields = new ArrayList<>();
                        if(CollectionUtils.isNotEmpty(metrics)){
                            filterValidFields = metrics.stream().filter(item -> fieldKeys.contains(item)).collect(Collectors.toList());
                        }else{
                            filterValidFields = fieldKeys;
                        }
                        String filterValidFieldStr = filterValidFields.stream().collect(Collectors.joining(","));
                        if(CollectionUtils.isEmpty(filterValidFields)){
                            throw new BusinessException(tablename+"没有可用属性，请添加");
                        }

                        HistorysInnerResultVO resultVO = new HistorysInnerResultVO();
                        resultVO.setDeviceuuid(deviceUUIds.get(i));

                        String query = "SELECT ts,"+tagStr+filterValidFieldStr+" FROM "+tablename+" where ts >= '"+startTime+"' and ts <= '"+endTime+"'";
                        try (PreparedStatement itemStmt1 = connection.prepareStatement(query)) {
                            try (ResultSet resultSet1 = itemStmt1.executeQuery()) {
                                int count = resultSet1.getMetaData().getColumnCount();
                                List<Map<String, Object>> resultList = new ArrayList<>();
                                while (resultSet1.next()) {
                                    Map<String, Object> map = new HashMap<>();
                                    for (int k = 1; k <= count; k++) {
                                        String key = resultSet1.getMetaData().getColumnName(k);
                                        Object value = resultSet1.getString(k);
                                        map.put(key, value);
                                    }
                                    resultList.add(map);
                                }
                                resultSet1.close();

                                if(CollectionUtils.isNotEmpty(resultList)){
                                    Map<String, String> tag = new HashMap<>();
                                    for (int k = 0; k < taglist.size(); k++) {
                                        tag.put(taglist.get(k), resultList.get(0).get(taglist.get(k)).toString());
                                    }
                                    resultVO.setTags(tag);

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

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

                    }
                }

            } catch (SQLException e) {
                // 判断TDengine专属错误码 0x2603 = 表不存在
                if (e.getMessage().contains("0x2603") || e.getMessage().contains("Table does not exist")) {
                    System.out.println("表" + tablename + "不存在，跳过");
                    log.error("表" + tablename + "不存在，跳过");
                } else {
                    // 其他异常正常打印堆栈
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return list;

    }

    @Override
    public List<Map<String, Object>> getAllDeviceRealTime(){
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
//        List<DeviceRealDataVO> realData =  queryTdengineDataMapper.getAllDeviceRealTime();
//        return realData.stream().map(item -> {
//            Map<String, Object> map = new HashMap<>();
//            map.put("device_uuid", item.getDeviceUuid());
//            map.put("device_id", item.getDeviceId());
//            try {
//                map.put("realtime", sdf.parse(item.getRealtime().toString()).getTime());
//            } catch (ParseException e) {
//                throw new RuntimeException(e);
//            }
//            return map;
//        }).collect(Collectors.toList());
        List<Map<String, Object>> resultList = new ArrayList<>();

        try (Connection connection = dataSource.getConnection()) {

            String query = "select device_uuid,realtime,device_id from datarealtime";
            try (PreparedStatement itemStmt = connection.prepareStatement(query)) {
                try (ResultSet resultSet1 = itemStmt.executeQuery()){
                    while (resultSet1.next()) {
                        Map<String, Object> map = new HashMap<>();
                        map.put("device_uuid", resultSet1.getString("device_uuid"));
                        map.put("device_id", resultSet1.getString("device_id"));
                        map.put("realtime", resultSet1.getTimestamp("realtime").getTime());

                        resultList.add(map);
                    }
                }

            }


        } catch (Exception e) {
            e.printStackTrace();
        }

        return resultList;
    }

    @Override
    public void createSuperTableAndColumn(SuperTableDTO superTableDTO){
        queryTdengineDataMapper.createSuperTableAndColumn(superTableDTO);
    }

    @Override
    public void addSuperTableColumn(String superTableName, Fields fields) {
        queryTdengineDataMapper.addSuperTableColumn(superTableName, fields);
    }

    @Override
    public void dropSuperTableColumn(String superTableName, Fields fields) {
        queryTdengineDataMapper.dropSuperTableColumn(superTableName, fields);
    }

    @Override
    public List<SuperTableDescribeVO> describeSuperOrSubTable(String tableName) {
        try {
            return queryTdengineDataMapper.describeSuperOrSubTable(tableName);
        } catch (Exception e) {
            log.warn("Error describing super or sub table. Database: {}, Table: {}, Error: {}"+tableName+", "+e.getMessage());
            return Collections.emptyList();
        }
    }

    @Override
    public void addSuperTableTag(String superTableName, Fields fields) {
        queryTdengineDataMapper.addSuperTableTag(superTableName, fields);
    }

    @Override
    public void dropSuperTableTag(String superTableName, Fields fields) {
        queryTdengineDataMapper.dropSuperTableTag(superTableName, fields);
    }

    @Override
    public EnergyItemSumResultVO sumEnergyItemDiff(EnergyItemSumQueryVO requestVO) {
        if (requestVO == null) {
            throw new BusinessException("查询参数不能为空");
        }
        String superTable = requestVO.getSuperTable();
        String identifier = requestVO.getIdentifier();
        String startTime = requestVO.getStartTime();
        String endTime = requestVO.getEndTime();
        if (StringUtils.isAnyBlank(superTable, identifier, startTime, endTime)) {
            throw new BusinessException("super_table、identifier、startTime、endTime 均不能为空");
        }
        assertSqlIdentifier(superTable, "super_table");
        assertSqlIdentifier(identifier, "identifier");

        String deviceFilter = buildDeviceUuidFilter(requestVO.getDeviceUuid());
        String sql = "SELECT SUM(diff) AS sum_diff FROM ("
                + " SELECT device_id, LAST(" + identifier + ") - FIRST(" + identifier + ") AS diff"
                + " FROM " + superTable
                + " WHERE ts >= '" + startTime + "' AND ts < '" + endTime + "'"
                + deviceFilter
                + " GROUP BY device_id"
                + ") AS sub_table_diff";

        EnergyItemSumResultVO result = new EnergyItemSumResultVO();
        result.setSumDiff(BigDecimal.ZERO);

        try (Connection connection = dataSource.getConnection();
             PreparedStatement stmt = connection.prepareStatement(sql);
             ResultSet rs = stmt.executeQuery()) {
            if (rs.next()) {
                Object value = rs.getObject("sum_diff");
                if (value != null) {
                    result.setSumDiff(new BigDecimal(value.toString()));
                }
            }
        } catch (SQLException e) {
            log.error("能耗分项汇总查询失败, sql=" + sql + ", " + e.getMessage());
        }
        return result;
    }

    @Override
    public EnergyItemTrendResultVO sumEnergyItemTrend(EnergyItemTrendQueryVO requestVO) {
        if (requestVO == null) {
            throw new BusinessException("查询参数不能为空");
        }
        String superTable = requestVO.getSuperTable();
        String identifier = requestVO.getIdentifier();
        String startTime = requestVO.getStartTime();
        String endTime = requestVO.getEndTime();
        Integer dateType = requestVO.getDateType();
        if (StringUtils.isAnyBlank(superTable, identifier, startTime, endTime) || dateType == null) {
            throw new BusinessException("super_table、identifier、startTime、endTime、dateType 均不能为空");
        }
        assertSqlIdentifier(superTable, "super_table");
        assertSqlIdentifier(identifier, "identifier");
        String interval = resolveTrendInterval(dateType);

        String sql = "SELECT _wstart, SUM(diff) AS sum_diff FROM ("
                + " SELECT _wstart, device_id, LAST(" + identifier + ") - FIRST(" + identifier + ") AS diff"
                + " FROM " + superTable
                + " WHERE ts >= '" + startTime + "' AND ts < '" + endTime + "'"
                + " PARTITION BY device_id"
                + " INTERVAL(" + interval + ")"
                + ") AS trend_diff GROUP BY _wstart ORDER BY _wstart";

        EnergyItemTrendResultVO result = new EnergyItemTrendResultVO();
        List<EnergyItemTrendPointVO> points = new ArrayList<>();

        try (Connection connection = dataSource.getConnection();
             PreparedStatement stmt = connection.prepareStatement(sql);
             ResultSet rs = stmt.executeQuery()) {
            while (rs.next()) {
                Object wstart = rs.getObject("_wstart");
                if (wstart == null) {
                    continue;
                }
                Object sumDiff = rs.getObject("sum_diff");
                EnergyItemTrendPointVO point = new EnergyItemTrendPointVO();
                point.setTime(wstart.toString());
                if (sumDiff != null) {
                    point.setValue(new BigDecimal(sumDiff.toString()));
                } else {
                    point.setValue(BigDecimal.ZERO);
                }
                points.add(point);
            }
        } catch (SQLException e) {
            log.error("能耗分项趋势查询失败, sql=" + sql + ", " + e.getMessage());
        }

        result.setPoints(points);
        return result;
    }

    private static String resolveTrendInterval(Integer dateType) {
        if (dateType == 1) {
            return "1h";
        }
        if (dateType == 2) {
            return "1d";
        }
        if (dateType == 3) {
            return "1n";
        }
        throw new BusinessException("dateType 仅支持 1-小时、2-天、3-月");
    }

    private static String buildDeviceUuidFilter(List<String> deviceUuids) {
        if (deviceUuids == null || deviceUuids.isEmpty()) {
            return "";
        }
        String tbnames = deviceUuids.stream()
                .filter(StringUtils::isNotBlank)
                .map(uuid -> "'_" + uuid.trim().replace("'", "''") + "'")
                .collect(Collectors.joining(","));
        if (tbnames.isEmpty()) {
            return "";
        }
        return " AND tbname IN (" + tbnames + ")";
    }

    private static void assertSqlIdentifier(String name, String paramName) {
        if (!SQL_IDENTIFIER_PATTERN.matcher(name).matches()) {
            throw new BusinessException(paramName + " 格式非法，仅允许字母、数字与下划线，且不能以数字开头");
        }
    }
}
