package com.qqchen.deploy.backend.deploy.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.qqchen.deploy.backend.deploy.dto.ServerMonitorDataDTO;
import com.qqchen.deploy.backend.deploy.dto.ServerMonitorMetricsDTO;
import com.qqchen.deploy.backend.deploy.dto.ServerMonitorMetricsQuery;
import com.qqchen.deploy.backend.deploy.entity.Server;
import com.qqchen.deploy.backend.deploy.entity.ServerMonitor;
import com.qqchen.deploy.backend.deploy.enums.MonitorTimeRange;
import com.qqchen.deploy.backend.deploy.repository.IServerMonitorRepository;
import com.qqchen.deploy.backend.deploy.repository.IServerRepository;
import com.qqchen.deploy.backend.deploy.service.IServerMonitorService;
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.enums.StatusEnum;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.utils.JsonUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务器监控服务实现
 */
@Slf4j
@Service
public class ServerMonitorServiceImpl implements IServerMonitorService {

    @Resource
    private IServerMonitorRepository monitorRepository;

    @Resource
    private IServerRepository serverRepository;

    @Override
    @Transactional
    public void batchSaveMonitorData(List<ServerMonitorDataDTO> dataList) {
        if (dataList == null || dataList.isEmpty()) {
            return;
        }

        List<ServerMonitor> monitors = dataList.stream()
            .map(this::convertToEntity)
            .collect(Collectors.toList());

        monitorRepository.saveAll(monitors);
        log.debug("批量保存监控数据成功: count={}", monitors.size());
    }

    @Override
    @Transactional
    public int deleteOldData(LocalDateTime beforeTime) {
        int deletedCount = monitorRepository.deleteByCollectTimeBefore(beforeTime);
        log.info("删除历史监控数据: beforeTime={}, count={}", beforeTime, deletedCount);
        return deletedCount;
    }

    @Override
    public ServerMonitor getLastMonitorData(Long serverId) {
        ServerMonitor lastMonitor = monitorRepository.findFirstByServerIdOrderByCollectTimeDesc(serverId);
        log.debug("查询最新监控数据: serverId={}, found={}", serverId, lastMonitor != null);
        return lastMonitor;
    }

    /**
     * 转换DTO为实体
     */
    private ServerMonitor convertToEntity(ServerMonitorDataDTO dto) {
        String diskUsageJson = null;
        if (dto.getDiskUsage() != null && !dto.getDiskUsage().isEmpty()) {
            diskUsageJson = JsonUtils.toJson(dto.getDiskUsage());
            if (diskUsageJson == null) {
                log.error("序列化磁盘使用率失败");
            }
        }

        return ServerMonitor.builder()
            .serverId(dto.getServerId())
            .cpuUsage(dto.getCpuUsage())
            .memoryUsage(dto.getMemoryUsage())
            .memoryUsed(dto.getMemoryUsed())
            .diskUsage(diskUsageJson)
            .networkRx(dto.getNetworkRx())
            .networkTx(dto.getNetworkTx())
            .collectTime(dto.getCollectTime())
            .status(StatusEnum.SUCCESS)  // 成功采集的记录
            .build();
    }

    @Override
    @Transactional
    public void saveMonitorRecord(ServerMonitor monitor) {
        monitorRepository.save(monitor);
        log.debug("保存监控记录: serverId={}, status={}", monitor.getServerId(), monitor.getStatus());
    }

    @Override
    public int countConsecutiveFailures(Long serverId, int checkLimit) {
        // 查询最近N条记录
        Pageable pageable = PageRequest.of(0, checkLimit);
        List<ServerMonitor> recentRecords = monitorRepository.findRecentMonitorRecords(serverId, pageable);
        
        if (recentRecords == null || recentRecords.isEmpty()) {
            log.debug("没有找到监控记录: serverId={}", serverId);
            return 0;
        }
        
        // 从最新记录开始统计连续失败次数
        int failureCount = 0;
        for (ServerMonitor record : recentRecords) {
            if (StatusEnum.FAILURE.equals(record.getStatus())) {
                failureCount++;
            } else {
                // 遇到成功记录，停止统计
                break;
            }
        }
        
        log.debug("统计连续失败次数: serverId={}, count={}", serverId, failureCount);
        return failureCount;
    }

    @Override
    public ServerMonitorMetricsDTO getServerMetrics(ServerMonitorMetricsQuery query) {
        // 1. 参数校验
        if (query == null || query.getServerId() == null) {
            throw new BusinessException(ResponseCode.INVALID_PARAM, new Object[]{"服务器ID不能为空"});
        }
        if (query.getTimeRange() == null) {
            throw new BusinessException(ResponseCode.INVALID_PARAM, new Object[]{"时间范围不能为空"});
        }

        // 2. 查询服务器信息
        Server server = serverRepository.findById(query.getServerId())
            .orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND, new Object[]{"服务器不存在"}));

        // 3. 根据枚举确定时间范围和聚合间隔
        MonitorTimeRange timeRange = query.getTimeRange();
        LocalDateTime endTime = LocalDateTime.now();
        LocalDateTime startTime = endTime.minus(timeRange.getDuration());
        String interval = timeRange.getDefaultInterval();

        // 4. 查询监控数据
        List<ServerMonitor> monitorData = monitorRepository.findByServerIdAndTimeRange(
            query.getServerId(), startTime, endTime);

        if (CollectionUtils.isEmpty(monitorData)) {
            log.warn("未查询到监控数据: serverId={}, timeRange={}, startTime={}, endTime={}", 
                query.getServerId(), timeRange, startTime, endTime);
            return buildEmptyResponse(server, startTime, endTime, interval);
        }

        // 5. 根据聚合间隔处理数据
        List<ServerMonitor> aggregatedData = aggregateData(monitorData, interval);

        // 6. 构建响应
        return buildMetricsResponse(server, aggregatedData, startTime, endTime, interval, query.getMetrics());
    }

    /**
     * 数据聚合处理
     */
    private List<ServerMonitor> aggregateData(List<ServerMonitor> data, String interval) {
        if ("5m".equals(interval) || data.size() <= 100) {
            return data;
        }

        int aggregateMinutes = getAggregateMinutes(interval);
        Map<String, List<ServerMonitor>> groupedData = data.stream()
            .collect(Collectors.groupingBy(m -> 
                m.getCollectTime().minusMinutes(m.getCollectTime().getMinute() % aggregateMinutes)
                    .withSecond(0).withNano(0).toString()
            ));

        return groupedData.values().stream()
            .map(this::aggregateMonitorGroup)
            .sorted(Comparator.comparing(ServerMonitor::getCollectTime))
            .collect(Collectors.toList());
    }

    /**
     * 获取聚合时间间隔（分钟）
     */
    private int getAggregateMinutes(String interval) {
        return switch (interval) {
            case "15m" -> 15;
            case "1h" -> 60;
            case "4h" -> 240;
            default -> 5;
        };
    }

    /**
     * 聚合一组监控数据（取平均值）
     */
    private ServerMonitor aggregateMonitorGroup(List<ServerMonitor> group) {
        if (group.size() == 1) {
            return group.get(0);
        }

        List<ServerMonitor> successRecords = group.stream()
            .filter(m -> StatusEnum.SUCCESS.equals(m.getStatus()))
            .collect(Collectors.toList());

        if (successRecords.isEmpty()) {
            return group.get(0);
        }

        BigDecimal avgCpu = successRecords.stream()
            .map(ServerMonitor::getCpuUsage)
            .filter(Objects::nonNull)
            .reduce(BigDecimal.ZERO, BigDecimal::add)
            .divide(BigDecimal.valueOf(successRecords.size()), 2, RoundingMode.HALF_UP);

        BigDecimal avgMemory = successRecords.stream()
            .map(ServerMonitor::getMemoryUsage)
            .filter(Objects::nonNull)
            .reduce(BigDecimal.ZERO, BigDecimal::add)
            .divide(BigDecimal.valueOf(successRecords.size()), 2, RoundingMode.HALF_UP);

        return ServerMonitor.builder()
            .serverId(group.get(0).getServerId())
            .cpuUsage(avgCpu)
            .memoryUsage(avgMemory)
            .memoryUsed(successRecords.get(0).getMemoryUsed())
            .diskUsage(successRecords.get(successRecords.size() - 1).getDiskUsage())
            .networkRx(successRecords.stream().mapToLong(m -> m.getNetworkRx() != null ? m.getNetworkRx() : 0).sum())
            .networkTx(successRecords.stream().mapToLong(m -> m.getNetworkTx() != null ? m.getNetworkTx() : 0).sum())
            .collectTime(group.get(0).getCollectTime())
            .status(StatusEnum.SUCCESS)
            .build();
    }

    /**
     * 构建空响应
     */
    private ServerMonitorMetricsDTO buildEmptyResponse(Server server, LocalDateTime startTime, 
                                                             LocalDateTime endTime, String interval) {
        return ServerMonitorMetricsDTO.builder()
            .server(ServerMonitorMetricsDTO.ServerInfo.builder()
                .serverId(server.getId())
                .serverName(server.getServerName())
                .hostIp(server.getHostIp())
                .status(server.getStatus().name())
                .build())
            .timeRange(ServerMonitorMetricsDTO.TimeRangeInfo.builder()
                .startTime(startTime)
                .endTime(endTime)
                .interval(interval)
                .dataPoints(0)
                .build())
            .metrics(ServerMonitorMetricsDTO.MetricsData.builder()
                .cpu(new ArrayList<>())
                .memory(new ArrayList<>())
                .network(new ArrayList<>())
                .build())
            .statistics(ServerMonitorMetricsDTO.StatisticsInfo.builder().build())
            .build();
    }

    /**
     * 构建完整的监控指标响应
     */
    private ServerMonitorMetricsDTO buildMetricsResponse(Server server, List<ServerMonitor> data,
                                                               LocalDateTime startTime, LocalDateTime endTime,
                                                               String interval, List<MonitorMetricEnum> requestedMetrics) {
        Set<MonitorMetricEnum> metricsToInclude = requestedMetrics == null || requestedMetrics.isEmpty()
            ? EnumSet.allOf(MonitorMetricEnum.class)
            : EnumSet.copyOf(requestedMetrics);

        // 先构建所有metrics数据（避免重复计算）
        List<ServerMonitorMetricsDTO.NetworkMetric> networkMetrics = 
            metricsToInclude.contains(MonitorMetricEnum.NETWORK) ? buildNetworkMetrics(data) : null;

        ServerMonitorMetricsDTO.MetricsData metricsData = ServerMonitorMetricsDTO.MetricsData.builder()
            .cpu(metricsToInclude.contains(MonitorMetricEnum.CPU) ? buildCpuMetrics(data) : null)
            .memory(metricsToInclude.contains(MonitorMetricEnum.MEMORY) ? buildMemoryMetrics(data) : null)
            .network(networkMetrics)
            .disk(metricsToInclude.contains(MonitorMetricEnum.DISK) ? buildDiskMetric(data) : null)
            .build();

        ServerMonitorMetricsDTO.StatisticsInfo statistics = ServerMonitorMetricsDTO.StatisticsInfo.builder()
            .cpu(metricsToInclude.contains(MonitorMetricEnum.CPU) ? buildCpuStats(data) : null)
            .memory(metricsToInclude.contains(MonitorMetricEnum.MEMORY) ? buildMemoryStats(data) : null)
            .network(metricsToInclude.contains(MonitorMetricEnum.NETWORK) ? buildNetworkStats(data, networkMetrics) : null)
            .build();

        return ServerMonitorMetricsDTO.builder()
            .server(ServerMonitorMetricsDTO.ServerInfo.builder()
                .serverId(server.getId())
                .serverName(server.getServerName())
                .hostIp(server.getHostIp())
                .status(server.getStatus().name())
                .build())
            .timeRange(ServerMonitorMetricsDTO.TimeRangeInfo.builder()
                .startTime(startTime)
                .endTime(endTime)
                .interval(interval)
                .dataPoints(data.size())
                .build())
            .metrics(metricsData)
            .statistics(statistics)
            .build();
    }

    private List<ServerMonitorMetricsDTO.CpuMetric> buildCpuMetrics(List<ServerMonitor> data) {
        return data.stream()
            .map(m -> ServerMonitorMetricsDTO.CpuMetric.builder()
                .time(m.getCollectTime())
                .value(m.getCpuUsage())
                .status(m.getStatus().name())
                .build())
            .collect(Collectors.toList());
    }

    private List<ServerMonitorMetricsDTO.MemoryMetric> buildMemoryMetrics(List<ServerMonitor> data) {
        return data.stream()
            .map(m -> ServerMonitorMetricsDTO.MemoryMetric.builder()
                .time(m.getCollectTime())
                .usagePercent(m.getMemoryUsage())
                .usedGB(m.getMemoryUsed())
                .status(m.getStatus().name())
                .build())
            .collect(Collectors.toList());
    }

    private List<ServerMonitorMetricsDTO.NetworkMetric> buildNetworkMetrics(List<ServerMonitor> data) {
        List<ServerMonitorMetricsDTO.NetworkMetric> metrics = new ArrayList<>();
        for (int i = 0; i < data.size(); i++) {
            ServerMonitor current = data.get(i);
            BigDecimal rxMBps = BigDecimal.ZERO;
            BigDecimal txMBps = BigDecimal.ZERO;

            if (i > 0 && current.getNetworkRx() != null && current.getNetworkTx() != null) {
                ServerMonitor previous = data.get(i - 1);
                long timeDiff = Duration.between(previous.getCollectTime(), current.getCollectTime()).getSeconds();
                if (timeDiff > 0 && previous.getNetworkRx() != null && previous.getNetworkTx() != null) {
                    long rxDiff = current.getNetworkRx() - previous.getNetworkRx();
                    long txDiff = current.getNetworkTx() - previous.getNetworkTx();
                    rxMBps = BigDecimal.valueOf(rxDiff).divide(BigDecimal.valueOf(timeDiff * 1024 * 1024), 2, RoundingMode.HALF_UP);
                    txMBps = BigDecimal.valueOf(txDiff).divide(BigDecimal.valueOf(timeDiff * 1024 * 1024), 2, RoundingMode.HALF_UP);
                }
            }

            metrics.add(ServerMonitorMetricsDTO.NetworkMetric.builder()
                .time(current.getCollectTime())
                .rxBytes(current.getNetworkRx())
                .txBytes(current.getNetworkTx())
                .rxMBps(rxMBps)
                .txMBps(txMBps)
                .build());
        }
        return metrics;
    }

    private ServerMonitorMetricsDTO.DiskMetric buildDiskMetric(List<ServerMonitor> data) {
        ServerMonitor latest = data.get(data.size() - 1);
        if (latest.getDiskUsage() == null) {
            return null;
        }

        try {
            List<Map<String, Object>> diskData = JsonUtils.fromJson(
                latest.getDiskUsage(), new TypeReference<List<Map<String, Object>>>() {});

            List<ServerMonitorMetricsDTO.DiskPartition> partitions = diskData.stream()
                .map(disk -> ServerMonitorMetricsDTO.DiskPartition.builder()
                    .mountPoint((String) disk.get("mountPoint"))
                    .fileSystem((String) disk.get("fileSystem"))
                    .totalSizeGB(((Number) disk.get("totalSize")).longValue())
                    .usedSizeGB(((Number) disk.get("usedSize")).longValue())
                    .usagePercent(BigDecimal.valueOf(((Number) disk.get("usagePercent")).doubleValue()))
                    .build())
                .collect(Collectors.toList());

            BigDecimal maxUsage = partitions.stream()
                .map(ServerMonitorMetricsDTO.DiskPartition::getUsagePercent)
                .max(BigDecimal::compareTo)
                .orElse(BigDecimal.ZERO);

            String maxPartition = partitions.stream()
                .filter(p -> p.getUsagePercent().compareTo(maxUsage) == 0)
                .map(ServerMonitorMetricsDTO.DiskPartition::getMountPoint)
                .findFirst()
                .orElse(null);

            return ServerMonitorMetricsDTO.DiskMetric.builder()
                .latestTime(latest.getCollectTime())
                .partitions(partitions)
                .maxUsagePercent(maxUsage)
                .maxUsagePartition(maxPartition)
                .build();
        } catch (Exception e) {
            log.error("解析磁盘数据失败", e);
            return null;
        }
    }

    private ServerMonitorMetricsDTO.CpuStats buildCpuStats(List<ServerMonitor> data) {
        List<ServerMonitor> successData = data.stream()
            .filter(m -> StatusEnum.SUCCESS.equals(m.getStatus()) && m.getCpuUsage() != null)
            .collect(Collectors.toList());

        if (successData.isEmpty()) {
            return null;
        }

        BigDecimal avg = successData.stream()
            .map(ServerMonitor::getCpuUsage)
            .reduce(BigDecimal.ZERO, BigDecimal::add)
            .divide(BigDecimal.valueOf(successData.size()), 2, RoundingMode.HALF_UP);

        ServerMonitor maxRecord = successData.stream()
            .max(Comparator.comparing(ServerMonitor::getCpuUsage))
            .orElse(null);

        BigDecimal min = successData.stream()
            .map(ServerMonitor::getCpuUsage)
            .min(BigDecimal::compareTo)
            .orElse(null);

        return ServerMonitorMetricsDTO.CpuStats.builder()
            .avg(avg)
            .max(maxRecord != null ? maxRecord.getCpuUsage() : null)
            .min(min)
            .maxTime(maxRecord != null ? maxRecord.getCollectTime() : null)
            .build();
    }

    private ServerMonitorMetricsDTO.MemoryStats buildMemoryStats(List<ServerMonitor> data) {
        List<ServerMonitor> successData = data.stream()
            .filter(m -> StatusEnum.SUCCESS.equals(m.getStatus()) && m.getMemoryUsage() != null)
            .collect(Collectors.toList());

        if (successData.isEmpty()) {
            return null;
        }

        BigDecimal avg = successData.stream()
            .map(ServerMonitor::getMemoryUsage)
            .reduce(BigDecimal.ZERO, BigDecimal::add)
            .divide(BigDecimal.valueOf(successData.size()), 2, RoundingMode.HALF_UP);

        ServerMonitor maxRecord = successData.stream()
            .max(Comparator.comparing(ServerMonitor::getMemoryUsage))
            .orElse(null);

        BigDecimal min = successData.stream()
            .map(ServerMonitor::getMemoryUsage)
            .min(BigDecimal::compareTo)
            .orElse(null);

        return ServerMonitorMetricsDTO.MemoryStats.builder()
            .avgPercent(avg)
            .maxPercent(maxRecord != null ? maxRecord.getMemoryUsage() : null)
            .minPercent(min)
            .maxTime(maxRecord != null ? maxRecord.getCollectTime() : null)
            .build();
    }

    private ServerMonitorMetricsDTO.NetworkStats buildNetworkStats(List<ServerMonitor> data, 
                                                                     List<ServerMonitorMetricsDTO.NetworkMetric> networkMetrics) {
        if (networkMetrics == null || networkMetrics.isEmpty()) {
            return null;
        }

        // 计算总流量（从原始数据）
        List<ServerMonitor> successData = data.stream()
            .filter(m -> StatusEnum.SUCCESS.equals(m.getStatus()) 
                && m.getNetworkRx() != null && m.getNetworkTx() != null)
            .collect(Collectors.toList());

        if (successData.isEmpty()) {
            return null;
        }

        long totalRx = successData.stream().mapToLong(ServerMonitor::getNetworkRx).sum();
        long totalTx = successData.stream().mapToLong(ServerMonitor::getNetworkTx).sum();

        // 计算速率统计（从已构建的 NetworkMetric 数据中提取）
        BigDecimal avgRxMBps = null;
        BigDecimal avgTxMBps = null;
        BigDecimal peakRxMBps = null;
        BigDecimal peakTxMBps = null;
        
        // 跳过第一个数据点（无前置数据，速率为0），从第二个开始统计
        List<ServerMonitorMetricsDTO.NetworkMetric> validMetrics = networkMetrics.size() > 1
            ? networkMetrics.subList(1, networkMetrics.size())
            : new ArrayList<>();
        
        if (!validMetrics.isEmpty()) {
            // 平均接收速率
            avgRxMBps = validMetrics.stream()
                .map(ServerMonitorMetricsDTO.NetworkMetric::getRxMBps)
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .divide(BigDecimal.valueOf(validMetrics.size()), 2, RoundingMode.HALF_UP);
            
            // 平均发送速率
            avgTxMBps = validMetrics.stream()
                .map(ServerMonitorMetricsDTO.NetworkMetric::getTxMBps)
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .divide(BigDecimal.valueOf(validMetrics.size()), 2, RoundingMode.HALF_UP);
            
            // 峰值接收速率
            peakRxMBps = validMetrics.stream()
                .map(ServerMonitorMetricsDTO.NetworkMetric::getRxMBps)
                .max(BigDecimal::compareTo)
                .orElse(null);
            
            // 峰值发送速率
            peakTxMBps = validMetrics.stream()
                .map(ServerMonitorMetricsDTO.NetworkMetric::getTxMBps)
                .max(BigDecimal::compareTo)
                .orElse(null);
        }

        return ServerMonitorMetricsDTO.NetworkStats.builder()
            .totalRxBytes(totalRx)
            .totalTxBytes(totalTx)
            .avgRxMBps(avgRxMBps)
            .avgTxMBps(avgTxMBps)
            .peakRxMBps(peakRxMBps)
            .peakTxMBps(peakTxMBps)
            .build();
    }
}
