package com.mosquito.project.performance;

import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.concurrent.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.lang.management.*;
import org.junit.jupiter.api.Assertions;

/**
 * 性能测试基类
 * 提供响应时间、并发、内存使用等性能指标的测试框架
 */
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("performance")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
abstract class AbstractPerformanceTest {

    @Autowired
    protected TestRestTemplate restTemplate;

    protected MemoryMXBean memoryBean;
    protected ThreadMXBean threadBean;
    protected Runtime runtime;

    @BeforeAll
    void setUpPerformanceMonitoring() {
        memoryBean = ManagementFactory.getMemoryMXBean();
        threadBean = ManagementFactory.getThreadMXBean();
        runtime = Runtime.getRuntime();
        
        // 执行GC清理内存
        System.gc();
        try {
            Thread.sleep(1000); // 等待GC完成
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    @BeforeEach
    void setUpEachTest() {
        // 每次测试前清理内存
        System.gc();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 性能测试结果容器
     */
    protected static class PerformanceMetrics {
        private String testName;
        private long totalRequests;
        private long successRequests;
        private long failedRequests;
        private double totalTimeMs;
        private double minResponseTimeMs;
        private double maxResponseTimeMs;
        private double avgResponseTimeMs;
        private double p95ResponseTimeMs;
        private double p99ResponseTimeMs;
        private long startMemoryUsed;
        private long endMemoryUsed;
        private long memoryUsedDelta;
        private int startThreadCount;
        private int endThreadCount;
        private int threadCountDelta;
        private double throughputPerSecond;

        public PerformanceMetrics(String testName) {
            this.testName = testName;
        }

        // Getters and setters
        public String getTestName() { return testName; }
        public void setTestName(String testName) { this.testName = testName; }
        public long getTotalRequests() { return totalRequests; }
        public void setTotalRequests(long totalRequests) { this.totalRequests = totalRequests; }
        public long getSuccessRequests() { return successRequests; }
        public void setSuccessRequests(long successRequests) { this.successRequests = successRequests; }
        public long getFailedRequests() { return failedRequests; }
        public void setFailedRequests(long failedRequests) { this.failedRequests = failedRequests; }
        public double getTotalTimeMs() { return totalTimeMs; }
        public void setTotalTimeMs(double totalTimeMs) { this.totalTimeMs = totalTimeMs; }
        public double getMinResponseTimeMs() { return minResponseTimeMs; }
        public void setMinResponseTimeMs(double minResponseTimeMs) { this.minResponseTimeMs = minResponseTimeMs; }
        public double getMaxResponseTimeMs() { return maxResponseTimeMs; }
        public void setMaxResponseTimeMs(double maxResponseTimeMs) { this.maxResponseTimeMs = maxResponseTimeMs; }
        public double getAvgResponseTimeMs() { return avgResponseTimeMs; }
        public void setAvgResponseTimeMs(double avgResponseTimeMs) { this.avgResponseTimeMs = avgResponseTimeMs; }
        public double getP95ResponseTimeMs() { return p95ResponseTimeMs; }
        public void setP95ResponseTimeMs(double p95ResponseTimeMs) { this.p95ResponseTimeMs = p95ResponseTimeMs; }
        public double getP99ResponseTimeMs() { return p99ResponseTimeMs; }
        public void setP99ResponseTimeMs(double p99ResponseTimeMs) { this.p99ResponseTimeMs = p99ResponseTimeMs; }
        public long getStartMemoryUsed() { return startMemoryUsed; }
        public void setStartMemoryUsed(long startMemoryUsed) { this.startMemoryUsed = startMemoryUsed; }
        public long getEndMemoryUsed() { return endMemoryUsed; }
        public void setEndMemoryUsed(long endMemoryUsed) { this.endMemoryUsed = endMemoryUsed; }
        public long getMemoryUsedDelta() { return memoryUsedDelta; }
        public void setMemoryUsedDelta(long memoryUsedDelta) { this.memoryUsedDelta = memoryUsedDelta; }
        public double getSuccessRate() {
            if (totalRequests == 0) {
                return 0.0;
            }
            return (double) successRequests / totalRequests;
        }
        public long getMemoryUsedDeltaMB() { return memoryUsedDelta / 1024 / 1024; }
        public int getStartThreadCount() { return startThreadCount; }
        public void setStartThreadCount(int startThreadCount) { this.startThreadCount = startThreadCount; }
        public int getEndThreadCount() { return endThreadCount; }
        public void setEndThreadCount(int endThreadCount) { this.endThreadCount = endThreadCount; }
        public int getThreadCountDelta() { return threadCountDelta; }
        public void setThreadCountDelta(int threadCountDelta) { this.threadCountDelta = threadCountDelta; }
        public double getThroughputPerSecond() { return throughputPerSecond; }
        public void setThroughputPerSecond(double throughputPerSecond) { this.throughputPerSecond = throughputPerSecond; }

        @Override
        public String toString() {
            return String.format("""
                === %s 性能测试结果 ===
                总请求数: %d, 成功: %d, 失败: %d
                响应时间: 平均=%.2fms, 最小=%.2fms, 最大=%.2fms
                响应时间: P95=%.2fms, P99=%.2fms
                吞吐量: %.2f 请求/秒
                内存使用: 开始=%dMB, 结束=%dMB, 变化=%dMB
                线程数量: 开始=%d, 结束=%d, 变化=%d
                """,
                testName, totalRequests, successRequests, failedRequests,
                avgResponseTimeMs, minResponseTimeMs, maxResponseTimeMs,
                p95ResponseTimeMs, p99ResponseTimeMs,
                throughputPerSecond,
                startMemoryUsed / 1024 / 1024, endMemoryUsed / 1024 / 1024, memoryUsedDelta / 1024 / 1024,
                startThreadCount, endThreadCount, threadCountDelta);
        }
    }

    /**
     * 执行并发性能测试
     */
    protected PerformanceMetrics runConcurrentTest(
            String testName,
            int threadCount,
            int requestsPerThread,
            RunnableWithResult task) throws InterruptedException {
        
        PerformanceMetrics metrics = new PerformanceMetrics(testName);
        
        // 记录开始时的系统状态
        metrics.setStartMemoryUsed(runtime.totalMemory() - runtime.freeMemory());
        metrics.setStartThreadCount(threadBean.getThreadCount());
        
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);
        List<Double> responseTimes = Collections.synchronizedList(new ArrayList<>());
        List<Boolean> successResults = Collections.synchronizedList(new ArrayList<>());
        
        long startTime = System.currentTimeMillis();
        
        // 启动所有线程
        for (int i = 0; i < threadCount; i++) {
            final int threadId = i;
            executor.submit(() -> {
                try {
                    for (int j = 0; j < requestsPerThread; j++) {
                        long requestStart = System.nanoTime();
                        boolean success = false;
                        
                        try {
                            success = task.run();
                            responseTimes.add((System.nanoTime() - requestStart) / 1_000_000.0);
                            successResults.add(success);
                        } catch (Exception e) {
                            responseTimes.add((System.nanoTime() - requestStart) / 1_000_000.0);
                            successResults.add(false);
                        }
                    }
                } finally {
                    latch.countDown();
                }
            });
        }
        
        // 等待所有线程完成
        boolean completed = latch.await(5, TimeUnit.MINUTES);
        long endTime = System.currentTimeMillis();
        
        executor.shutdown();
        
        if (!completed) {
            throw new RuntimeException("性能测试超时");
        }
        
        // 计算指标
        metrics.setTotalRequests(responseTimes.size());
        metrics.setSuccessRequests((int) successResults.stream().mapToLong(b -> b ? 1 : 0).sum());
        metrics.setFailedRequests(metrics.getTotalRequests() - metrics.getSuccessRequests());
        metrics.setTotalTimeMs(endTime - startTime);
        
        if (!responseTimes.isEmpty()) {
            metrics.setAvgResponseTimeMs(responseTimes.stream().mapToDouble(d -> d).average().orElse(0));
            metrics.setMinResponseTimeMs(responseTimes.stream().mapToDouble(d -> d).min().orElse(0));
            metrics.setMaxResponseTimeMs(responseTimes.stream().mapToDouble(d -> d).max().orElse(0));
            metrics.setP95ResponseTimeMs(calculatePercentile(responseTimes, 95));
            metrics.setP99ResponseTimeMs(calculatePercentile(responseTimes, 99));
        }
        
        metrics.setThroughputPerSecond(metrics.getTotalRequests() * 1000.0 / metrics.getTotalTimeMs());
        
        // 记录结束时的系统状态
        System.gc();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        metrics.setEndMemoryUsed(runtime.totalMemory() - runtime.freeMemory());
        metrics.setEndThreadCount(threadBean.getThreadCount());
        metrics.setMemoryUsedDelta(metrics.getEndMemoryUsed() - metrics.getStartMemoryUsed());
        metrics.setThreadCountDelta(metrics.getEndThreadCount() - metrics.getStartThreadCount());
        
        return metrics;
    }

    /**
     * 执行负载测试
     */
    protected PerformanceMetrics runLoadTest(
            String testName,
            int durationSeconds,
            int targetRPS,
            RunnableWithResult task) throws InterruptedException {
        
        PerformanceMetrics metrics = new PerformanceMetrics(testName);
        
        // 记录开始时的系统状态
        metrics.setStartMemoryUsed(runtime.totalMemory() - runtime.freeMemory());
        metrics.setStartThreadCount(threadBean.getThreadCount());
        
        ExecutorService executor = Executors.newCachedThreadPool();
        List<Double> responseTimes = Collections.synchronizedList(new ArrayList<>());
        List<Boolean> successResults = Collections.synchronizedList(new ArrayList<>());
        AtomicLong requestCount = new AtomicLong(0);
        
        long startTime = System.currentTimeMillis();
        long endTime = startTime + (durationSeconds * 1000);
        
        // 启动请求生成器
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> {
            if (System.currentTimeMillis() < endTime) {
                for (int i = 0; i < targetRPS; i++) {
                    requestCount.incrementAndGet();
                    executor.submit(() -> {
                        long requestStart = System.nanoTime();
                        boolean success = false;
                        
                        try {
                            success = task.run();
                            responseTimes.add((System.nanoTime() - requestStart) / 1_000_000.0);
                            successResults.add(success);
                        } catch (Exception e) {
                            responseTimes.add((System.nanoTime() - requestStart) / 1_000_000.0);
                            successResults.add(false);
                        }
                    });
                }
            }
        }, 0, 1000, TimeUnit.MILLISECONDS);
        
        // 等待测试完成
        Thread.sleep(durationSeconds * 1000);
        scheduler.shutdown();
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
        
        // 计算指标
        long actualEndTime = System.currentTimeMillis();
        metrics.setTotalRequests(responseTimes.size());
        metrics.setSuccessRequests((int) successResults.stream().mapToLong(b -> b ? 1 : 0).sum());
        metrics.setFailedRequests(metrics.getTotalRequests() - metrics.getSuccessRequests());
        metrics.setTotalTimeMs(actualEndTime - startTime);
        
        if (!responseTimes.isEmpty()) {
            metrics.setAvgResponseTimeMs(responseTimes.stream().mapToDouble(d -> d).average().orElse(0));
            metrics.setMinResponseTimeMs(responseTimes.stream().mapToDouble(d -> d).min().orElse(0));
            metrics.setMaxResponseTimeMs(responseTimes.stream().mapToDouble(d -> d).max().orElse(0));
            metrics.setP95ResponseTimeMs(calculatePercentile(responseTimes, 95));
            metrics.setP99ResponseTimeMs(calculatePercentile(responseTimes, 99));
        }
        
        metrics.setThroughputPerSecond(metrics.getTotalRequests() * 1000.0 / metrics.getTotalTimeMs());
        
        // 记录结束时的系统状态
        System.gc();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        metrics.setEndMemoryUsed(runtime.totalMemory() - runtime.freeMemory());
        metrics.setEndThreadCount(threadBean.getThreadCount());
        metrics.setMemoryUsedDelta(metrics.getEndMemoryUsed() - metrics.getStartMemoryUsed());
        metrics.setThreadCountDelta(metrics.getEndThreadCount() - metrics.getStartThreadCount());
        
        return metrics;
    }

    /**
     * 计算百分位数
     */
    private double calculatePercentile(List<Double> values, double percentile) {
        if (values.isEmpty()) return 0;
        
        List<Double> sorted = new ArrayList<>(values);
        Collections.sort(sorted);
        
        int index = (int) Math.ceil(percentile / 100 * sorted.size()) - 1;
        index = Math.max(0, Math.min(index, sorted.size() - 1));
        
        return sorted.get(index);
    }

    /**
     * 断言性能指标是否符合预期
     */
    protected void assertPerformance(PerformanceMetrics metrics, PerformanceExpectations expectations) {
        double throughputTolerance = Math.max(0.5, expectations.minThroughputPerSecond * 0.05);
        Assertions.assertAll(
            () -> Assertions.assertTrue(metrics.getAvgResponseTimeMs() <= expectations.maxAvgResponseTimeMs,
                String.format("平均响应时间超出预期: 实际=%.2fms, 预期≤%.2fms",
                    metrics.getAvgResponseTimeMs(), expectations.maxAvgResponseTimeMs)),
            () -> Assertions.assertTrue(metrics.getP95ResponseTimeMs() <= expectations.maxP95ResponseTimeMs,
                String.format("P95响应时间超出预期: 实际=%.2fms, 预期≤%.2fms",
                    metrics.getP95ResponseTimeMs(), expectations.maxP95ResponseTimeMs)),
            () -> Assertions.assertTrue(metrics.getSuccessRate() >= expectations.minSuccessRate,
                String.format("成功率低于预期: 实际=%.2f%%, 预期≥%.2f%%",
                    metrics.getSuccessRate() * 100, expectations.minSuccessRate * 100)),
            () -> Assertions.assertTrue(metrics.getThroughputPerSecond() + throughputTolerance >= expectations.minThroughputPerSecond,
                String.format("吞吐量低于预期: 实际=%.2freq/s, 预期≥%.2freq/s (容差=%.2f)",
                    metrics.getThroughputPerSecond(), expectations.minThroughputPerSecond, throughputTolerance)),
            () -> Assertions.assertTrue(metrics.getMemoryUsedDeltaMB() <= expectations.maxMemoryUsedDeltaMB,
                String.format("内存增长超出预期: 实际=%dMB, 预期≤%dMB",
                    metrics.getMemoryUsedDeltaMB(), expectations.maxMemoryUsedDeltaMB))
        );
    }

    /**
     * 性能预期配置
     */
    protected static class PerformanceExpectations {
        double maxAvgResponseTimeMs;
        double maxP95ResponseTimeMs;
        double minSuccessRate;
        double minThroughputPerSecond;
        long maxMemoryUsedDeltaMB;

        public PerformanceExpectations(
                double maxAvgResponseTimeMs,
                double maxP95ResponseTimeMs,
                double minSuccessRate,
                double minThroughputPerSecond,
                long maxMemoryUsedDeltaMB) {
            this.maxAvgResponseTimeMs = maxAvgResponseTimeMs;
            this.maxP95ResponseTimeMs = maxP95ResponseTimeMs;
            this.minSuccessRate = minSuccessRate;
            this.minThroughputPerSecond = minThroughputPerSecond;
            this.maxMemoryUsedDeltaMB = maxMemoryUsedDeltaMB;
        }
    }

    /**
     * 函数式接口用于性能测试任务
     */
    @FunctionalInterface
    protected interface RunnableWithResult {
        boolean run() throws Exception;
    }

    /**
     * 生成测试报告
     */
    protected void generatePerformanceReport(PerformanceMetrics metrics) {
        System.out.println(metrics);
        
        // 如果需要，可以添加到文件或数据库
        // logPerformanceMetrics(metrics);
    }

    protected void logPerformanceMetrics(PerformanceMetrics metrics) {
        // 记录到日志文件或监控系统
        System.out.println("Performance: " + metrics.getTestName() + 
            " - Avg: " + metrics.getAvgResponseTimeMs() + "ms, " +
            "Throughput: " + metrics.getThroughputPerSecond() + " req/s, " +
            "Success Rate: " + (metrics.getSuccessRate() * 100) + "%");
    }
}
