package com.tongran.common.core.utils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class EchartsDataUtils {

    /**
     * 构建ECharts图表数据
     * @param list 原始数据列表
     * @param timeExtractor 时间字段提取函数
     * @param dataExtractors 数据提取器Map (key: 数据名称, value: 数据提取函数)
     * @param <T> 数据类型泛型
     * @return 包含xData和yData的Map
     */
    public static <T> Map<String, Object> buildEchartsData(
            List<T> list,
            Function<T, Date> timeExtractor,
            Map<String, Function<T, ?>> dataExtractors) {

        // 按时间排序
        List<T> sortedList = list.stream()
                .sorted(Comparator.comparing(timeExtractor))
                .collect(Collectors.toList());

        // 准备X轴数据
        List<String> xAxisData = sortedList.stream()
                .map(item -> DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", timeExtractor.apply(item)))
                .collect(Collectors.toList());

        // 准备Y轴数据
        Map<String, Object> yData = new LinkedHashMap<>();
        dataExtractors.forEach((name, extractor) -> {
            yData.put(name, sortedList.stream().map(extractor).collect(Collectors.toList()));
        });

        // 构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("xData", xAxisData);
        result.put("yData", yData);
        return result;
    }


    /**
     * 微秒转秒
     */
    public static double convertMicrosecondsToSeconds(long microseconds) {
        return Math.round(microseconds / 1_000_000.0 * 100.0) / 100.0;
    }
    /**
     * 构建ECharts图表数据（带时间补全和特殊值处理）- 最终修复版本
     */
    public static <T> Map<String, Object> buildEchartsDataAutoPadding(
            List<T> list,
            Function<T, Date> timeExtractor,
            Map<String, Function<T, ?>> dataExtractors,
            String startTime,
            String endTime) {

        try {
            // 解析时间字符串
            Date startDate = parseStringToDate(startTime);
            Date endDate = parseStringToDate(endTime);

            if (startDate == null || endDate == null) {
                throw new IllegalArgumentException("开始时间或结束时间格式错误");
            }

            if (startDate.after(endDate)) {
                throw new IllegalArgumentException("开始时间不能晚于结束时间");
            }

            if (list == null || list.isEmpty()) {
                return createEmptyResult(dataExtractors.keySet(), startTime, endTime);
            }

            // 按时间排序
            List<T> sortedList = list.stream()
                    .sorted(Comparator.comparing(timeExtractor))
                    .collect(Collectors.toList());

            // 获取数据实际的时间范围
            Date actualStartTime = timeExtractor.apply(sortedList.get(0));
            Date actualEndTime = timeExtractor.apply(sortedList.get(sortedList.size() - 1));

            // 计算稀疏间隔
            long totalTimeRange = endDate.getTime() - startDate.getTime();
            long sparseInterval = totalTimeRange > 12L * 30 * 24 * 60 * 60 * 1000 ?
                    30L * 24 * 60 * 60 * 1000 : 2L * 24 * 60 * 60 * 1000;

            // 核心修改：生成X轴时间序列
            List<Date> xAxisTimes = generateXAxisTimeSeries(
                    startDate, endDate,
                    actualStartTime, actualEndTime,
                    sortedList, timeExtractor,
                    sparseInterval
            );

            // 创建时间到数据的映射
            Map<String, T> timeDataMap = new HashMap<>();
            for (T item : sortedList) {
                Date itemTime = timeExtractor.apply(item);
                String timeKey = parseDateToStr(itemTime);
                timeDataMap.put(timeKey, item);
            }

            // 检测整个数据集中是否有真实数据
            boolean hasRealData = checkHasRealData(sortedList, dataExtractors);

            // 查找特殊字段的固定值
            Object fixedPercentile95Value = findFixedValueForPercentile95(sortedList, dataExtractors);

            // 准备X轴和Y轴数据
            List<String> xAxisData = new ArrayList<>();
            Map<String, Object> yData = new LinkedHashMap<>();

            // 初始化Y轴数据结构
            dataExtractors.keySet().forEach(name ->
                    yData.put(name, new ArrayList<>()));

            for (Date time : xAxisTimes) {
                // X轴数据
                String timeStr = parseDateToStr(time);
                xAxisData.add(timeStr);

                // 判断当前时间点是否在数据实际时间范围内
                boolean isInDataRange = !time.before(actualStartTime) && !time.after(actualEndTime);

                // 查找对应的数据项
                T item = timeDataMap.get(timeStr);

                for (Map.Entry<String, Function<T, ?>> entry : dataExtractors.entrySet()) {
                    String name = entry.getKey();
                    Function<T, ?> extractor = entry.getValue();

                    @SuppressWarnings("unchecked")
                    List<Object> seriesData = (List<Object>) yData.get(name);

                    if (item != null) {
                        // 有真实数据
                        Object value = extractor.apply(item);
                        seriesData.add(value != null ? value : null);
                    } else {
                        // 智能数据补全
                        if (isInDataRange) {
                            // 在数据时间范围内但该时间点无数据
                            seriesData.add(getDefaultValue(name, fixedPercentile95Value, xAxisData.size()-1, hasRealData));
                        } else {
                            // 在数据时间范围外
                            seriesData.add(getEmptyDataDefaultValue(name, xAxisData.size()-1));
                        }
                    }
                }
            }

            Map<String, Object> result = new HashMap<>();
            result.put("xData", xAxisData);
            result.put("yData", yData);
            return result;

        } catch (Exception e) {
            System.err.println("构建图表数据失败: " + e.getMessage());
            e.printStackTrace();
            return createEmptyResult(dataExtractors.keySet(), startTime, endTime);
        }
    }

    /**
     * 生成X轴时间序列（核心方法）
     * 策略：优先使用实际数据的时间点，然后在数据点之间按需补全
     */
    private static <T> List<Date> generateXAxisTimeSeries(
            Date queryStart, Date queryEnd,
            Date dataStart, Date dataEnd,
            List<T> sortedList, Function<T, Date> timeExtractor,
            long sparseInterval) {

        List<Date> timeSeries = new ArrayList<>();

        // 1. 查询开始时间到数据开始时间（稀疏间隔）
        if (queryStart.before(dataStart)) {
            List<Date> beforeSeries = generateTimeSeries(queryStart, dataStart, sparseInterval, false);
            timeSeries.addAll(beforeSeries);
        }

        // 2. 数据时间范围内的处理
        if (sortedList != null && !sortedList.isEmpty()) {
            // 优先使用实际数据的所有时间点
            List<Date> dataTimePoints = sortedList.stream()
                    .map(timeExtractor)
                    .sorted()
                    .collect(Collectors.toList());
            timeSeries.addAll(dataTimePoints);

            // 检测数据点之间的间隔，补全缺失的时间点
            if (dataTimePoints.size() > 1) {
                List<Date> filledSeries = fillMissingTimePoints(dataTimePoints);
                timeSeries.addAll(filledSeries);
            }
        }

        // 3. 数据结束时间到查询结束时间（稀疏间隔）
        if (dataEnd.before(queryEnd)) {
            // 从数据结束时间的下一个稀疏间隔点开始
            Calendar cal = Calendar.getInstance();
            cal.setTime(dataEnd);
            cal.add(Calendar.MILLISECOND, (int)sparseInterval);
            Date nextAfterDataEnd = cal.getTime();

            if (nextAfterDataEnd.before(queryEnd) || nextAfterDataEnd.equals(queryEnd)) {
                List<Date> afterSeries = generateTimeSeries(nextAfterDataEnd, queryEnd, sparseInterval, false);
                timeSeries.addAll(afterSeries);
            }
        }

        // 去重、排序
        return timeSeries.stream()
                .distinct()
                .sorted()
                .collect(Collectors.toList());
    }

    /**
     * 补全缺失的时间点
     * 在相邻数据点之间，如果间隔太大，插入中间点
     */
    private static List<Date> fillMissingTimePoints(List<Date> dataTimePoints) {
        List<Date> filledPoints = new ArrayList<>();

        if (dataTimePoints.size() < 2) {
            return filledPoints;
        }

        // 检测常见间隔
        long commonInterval = detectCommonInterval(dataTimePoints);

        for (int i = 0; i < dataTimePoints.size() - 1; i++) {
            Date current = dataTimePoints.get(i);
            Date next = dataTimePoints.get(i + 1);
            long diff = next.getTime() - current.getTime();

            // 如果间隔大于常见间隔的1.5倍，说明中间有缺失
            if (diff > commonInterval * 1.5) {
                // 计算可以插入几个点
                int pointsToInsert = (int) (diff / commonInterval) - 1;

                Calendar cal = Calendar.getInstance();
                cal.setTime(current);

                for (int j = 1; j <= pointsToInsert; j++) {
                    cal.add(Calendar.MILLISECOND, (int)commonInterval);
                    Date insertedPoint = cal.getTime();

                    // 确保插入的点不晚于next
                    if (insertedPoint.before(next)) {
                        filledPoints.add(insertedPoint);
                    }
                }
            }
        }

        return filledPoints;
    }

    /**
     * 检测常见时间间隔
     */
    private static long detectCommonInterval(List<Date> timePoints) {
        if (timePoints.size() < 2) {
            return 300000L; // 默认5分钟
        }

        Map<Long, Integer> intervalCount = new HashMap<>();
        for (int i = 1; i < timePoints.size(); i++) {
            long interval = timePoints.get(i).getTime() - timePoints.get(i-1).getTime();
            if (interval > 0) {
                intervalCount.merge(interval, 1, Integer::sum);
            }
        }

        if (intervalCount.isEmpty()) {
            return 300000L;
        }

        return intervalCount.entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse(300000L);
    }

    /**
     * 生成时间序列
     * @param alignToInterval 是否对齐到时间间隔
     */
    private static List<Date> generateTimeSeries(Date start, Date end, long interval, boolean alignToInterval) {
        List<Date> timeSeries = new ArrayList<>();

        if (interval <= 0) {
            interval = 300000L;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);
        calendar.set(Calendar.MILLISECOND, 0);

        if (alignToInterval) {
            // 对齐到间隔
            long startMillis = calendar.getTimeInMillis();
            long normalizedStart = (startMillis / interval) * interval;
            calendar.setTimeInMillis(normalizedStart);

            if (normalizedStart < startMillis) {
                calendar.add(Calendar.MILLISECOND, (int)interval);
            }
        }

        // 包含开始时间
        if (!calendar.getTime().after(end)) {
            timeSeries.add(calendar.getTime());
        }

        while (true) {
            calendar.add(Calendar.MILLISECOND, (int)interval);
            if (calendar.getTime().after(end)) {
                break;
            }
            timeSeries.add(calendar.getTime());
        }

        return timeSeries;
    }

    /**
     * 获取空数据默认值（用于数据时间范围外的点）
     */
    private static Object getEmptyDataDefaultValue(String metricName, int timeIndex) {
        // deployDevice特殊处理：始终补空字符串
        if ("deployDevice".equals(metricName)) {
            return "";
        }

        return null;
    }

    /**
     * 检测整个数据集中是否有真实数据（非null）
     */
    private static <T> boolean checkHasRealData(List<T> list, Map<String, Function<T, ?>> dataExtractors) {
        for (T item : list) {
            for (Map.Entry<String, Function<T, ?>> entry : dataExtractors.entrySet()) {
                String name = entry.getKey();
                Function<T, ?> extractor = entry.getValue();

                Object value = extractor.apply(item);
                if (value != null) {
                    return true; // 发现至少一个真实数据
                }
            }
        }
        return false; // 没有发现任何真实数据
    }

    /**
     * 判断值是否为0（支持多种数值类型）
     */
    private static boolean isZeroValue(Object value) {
        if (value == null) return true;

        if (value instanceof Number) {
            return ((Number) value).doubleValue() == 0.0;
        }
        if (value instanceof BigDecimal) {
            return ((BigDecimal) value).compareTo(BigDecimal.ZERO) == 0;
        }
        if (value instanceof String) {
            try {
                return new BigDecimal(value.toString()).compareTo(BigDecimal.ZERO) == 0;
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }

    /**
     * 智能获取默认值
     * 策略：
     * 1. 如果整个数据集有真实数据：所有缺失点都补null
     * 2. 如果整个数据集没有真实数据：第一个点补0，其他点补null
     * 3. percentile95特殊处理：使用固定值
     */
    private static Object getDefaultValue(String metricName, Object fixedPercentile95Value,
                                          int timeIndex, boolean hasRealData) {

        // percentile95特殊处理
        if ("percentile95".equals(metricName) && !fixedPercentile95Value.equals(0)) {
            return fixedPercentile95Value;
        }
        // deployDevice特殊处理
        if ("deployDevice".equals(metricName)) {
            return fixedPercentile95Value;
        }
        // 智能补全策略
        if (hasRealData) {
            // 数据集中有真实数据：所有缺失点都补null
            return null;
        } else {
            // 数据集中没有真实数据：第一个点补0，其他点补null
            if (timeIndex == 0) {
                return 0;
            } else {
                return null;
            }
        }
    }

    /**
     * 创建空结果（智能补全策略）
     */
    private static Map<String, Object> createEmptyResult(Set<String> dataNames, String startTime, String endTime) {
        Map<String, Object> result = new HashMap<>();

        try {
            // 解析时间范围
            Date startDate = parseStringToDate(startTime);
            Date endDate = parseStringToDate(endTime);

            if (startDate != null && endDate != null && !startDate.after(endDate)) {
                // 动态计算时间间隔
                long timeRange = endDate.getTime() - startDate.getTime();
                long interval;

                if (timeRange > 12L * 30 * 24 * 60 * 60 * 1000) { // 超过12个月
                    interval = 30L * 24 * 60 * 60 * 1000; // 每月1个点
                } else {
                    interval = 2L * 24 * 60 * 60 * 1000; // 2天1个点
                }

                List<Date> fullTimeSeries = generateTimeSeries(startDate, endDate, interval);

                // 构建x轴数据
                List<String> xAxisData = new ArrayList<>();
                for (Date date : fullTimeSeries) {
                    xAxisData.add(parseDateToStr(date));
                }
                result.put("xData", xAxisData);

                // 构建y轴数据（空数据集）
                Map<String, Object> yData = new LinkedHashMap<>();
                int dataSize = xAxisData.size();
                dataNames.forEach(name -> {
                    List<Object> seriesData = new ArrayList<>();
                    for (int i = 0; i < dataSize; i++) {
                        // deployDevice特殊处理：始终补空字符串
                        if ("deployDevice".equals(name)) {
                            seriesData.add("");
                        }
                        else if (i == 0) {
                            // 第一个点补0
                            seriesData.add(0);
                        } else {
                            // 其他点补null
                            seriesData.add(null);
                        }
                    }
                    yData.put(name, seriesData);
                });
                result.put("yData", yData);

            } else {
                // 时间解析失败时返回空数据
                result.put("xData", new ArrayList<>());
                Map<String, Object> yData = new LinkedHashMap<>();
                dataNames.forEach(name -> yData.put(name, new ArrayList<>()));
                result.put("yData", yData);
            }

        } catch (Exception e) {
            // 异常时返回空数据
            result.put("xData", new ArrayList<>());
            Map<String, Object> yData = new LinkedHashMap<>();
            dataNames.forEach(name -> yData.put(name, new ArrayList<>()));
            result.put("yData", yData);
        }

        return result;
    }

    /**
     * 查找特殊字段的固定值
     * percentile95: 第一个非零值
     * deployDevice: 第一个非空值，没值填充空字符串
     */
    private static <T> Object findFixedValueForPercentile95(List<T> list, Map<String, Function<T, ?>> dataExtractors) {
        // 处理percentile95字段
        if (dataExtractors.containsKey("percentile95")) {
            Function<T, ?> extractor = dataExtractors.get("percentile95");
            for (T item : list) {
                Object value = extractor.apply(item);
                if (value != null && !isZeroValue(value)) {
                    return value;
                }
            }
        }

        // 处理deployDevice字段
        if (dataExtractors.containsKey("deployDevice")) {
            Function<T, ?> extractor = dataExtractors.get("deployDevice");
            for (T item : list) {
                Object value = extractor.apply(item);
                if (value != null) {
                    return value;
                }
            }
            return ""; // deployDevice没值返回空字符串
        }

        return 0; // 默认返回0
    }

    /**
     * 字符串转日期
     */
    private static Date parseStringToDate(String dateStr) {
        if (dateStr == null || dateStr.trim().isEmpty()) {
            return null;
        }
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            sdf.setLenient(false); // 严格模式
            return sdf.parse(dateStr);
        } catch (ParseException e) {
            System.err.println("日期解析失败: " + dateStr);
            return null;
        }
    }

    /**
     * 日期转字符串
     */
    private static String parseDateToStr(Date date) {
        if (date == null) {
            return "";
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    /**
     * 生成完整的时间序列
     */
    private static List<Date> generateTimeSeries(Date start, Date end, long interval) {
        List<Date> timeSeries = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);

        // 确保开始时间对齐到时间间隔
        long startMillis = normalizeTime(start, interval);
        calendar.setTimeInMillis(startMillis);

        while (!calendar.getTime().after(end)) {
            timeSeries.add(calendar.getTime());
            calendar.setTimeInMillis(calendar.getTimeInMillis() + interval);
        }
        // 在generateFullTimeSeriesForMultiInterface方法的最后添加：
        timeSeries.sort(Date::compareTo);
        // 去重
        List<Date> uniqueSeries = new ArrayList<>();
        Date lastDate = null;
        for (Date date : timeSeries) {
            if (lastDate == null || !date.equals(lastDate)) {
                uniqueSeries.add(date);
                lastDate = date;
            }
        }
        return uniqueSeries;
    }

    /**
     * 自动检测时间间隔
     */
    private static <T> long detectTimeInterval(List<T> list, Function<T, Date> timeExtractor) {
        if (list.size() < 2) {
            return 300000; // 默认5分钟
        }

        // 计算时间间隔的众数
        Map<Long, Integer> intervalCount = new HashMap<>();
        for (int i = 1; i < list.size(); i++) {
            long interval = timeExtractor.apply(list.get(i)).getTime() -
                    timeExtractor.apply(list.get(i - 1)).getTime();
            if (interval > 0) {
                intervalCount.merge(interval, 1, Integer::sum);
            }
        }

        // 如果没有有效间隔，使用默认值
        if (intervalCount.isEmpty()) {
            return 300000L;
        }

        return intervalCount.entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse(300000L);
    }

    /**
     * 时间标准化（对齐到时间间隔）
     */
    private static long normalizeTime(Date time, long interval) {
        long timeMillis = time.getTime();
        return (timeMillis / interval) * interval;
    }

}