package cn.novalon.gym.manage.gateway.monitor;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;

class PerformanceMonitorTest {

    private PerformanceMonitor performanceMonitor;
    private MeterRegistry meterRegistry;

    @BeforeEach
    void setUp() {
        meterRegistry = new SimpleMeterRegistry();
        performanceMonitor = new PerformanceMonitor(meterRegistry);
    }

    @Test
    void testRecordRequest() {
        performanceMonitor.recordRequest("/api/test", 100);

        assertEquals(1, performanceMonitor.getPathStats().size());
        assertTrue(performanceMonitor.getAverageProcessingTime() > 0);
    }

    @Test
    void testSlowRequestDetection() {
        performanceMonitor.setSlowRequestThresholdMs(50);
        performanceMonitor.recordRequest("/api/test", 100);

        assertEquals(1, performanceMonitor.getPathStats().size());
    }

    @Test
    void testMultipleRequests() {
        performanceMonitor.recordRequest("/api/test1", 100);
        performanceMonitor.recordRequest("/api/test2", 200);
        performanceMonitor.recordRequest("/api/test1", 150);

        Map<String, PerformanceMonitor.PerformanceStats> stats = performanceMonitor.getPathStats();
        
        assertEquals(2, stats.size());
        
        PerformanceMonitor.PerformanceStats test1Stats = stats.get("/api/test1");
        assertNotNull(test1Stats);
        assertEquals(2, test1Stats.getRequestCount());
        assertEquals(125.0, test1Stats.getAverageTime());
        assertEquals(150, test1Stats.getMaxTime());
        assertEquals(100, test1Stats.getMinTime());
    }

    @Test
    void testMemoryStats() {
        Map<String, Object> memoryStats = performanceMonitor.getMemoryStats();

        assertNotNull(memoryStats);
        assertTrue(memoryStats.containsKey("totalMemory"));
        assertTrue(memoryStats.containsKey("freeMemory"));
        assertTrue(memoryStats.containsKey("usedMemory"));
        assertTrue(memoryStats.containsKey("maxMemory"));
        assertTrue(memoryStats.containsKey("memoryUsage"));
    }

    @Test
    void testThreadStats() {
        Map<String, Object> threadStats = performanceMonitor.getThreadStats();

        assertNotNull(threadStats);
        assertTrue(threadStats.containsKey("threadCount"));
        assertTrue(threadStats.containsKey("peakThreadCount"));
        assertTrue(threadStats.containsKey("daemonThreadCount"));
        assertTrue(threadStats.containsKey("totalStartedThreadCount"));
    }

    @Test
    void testMemoryUsage() {
        double memoryUsage = performanceMonitor.getMemoryUsage();

        assertTrue(memoryUsage >= 0.0);
        assertTrue(memoryUsage <= 1.0);
    }

    @Test
    void testAverageProcessingTime_NoRequests() {
        assertEquals(0.0, performanceMonitor.getAverageProcessingTime());
    }

    @Test
    void testAverageProcessingTime_WithRequests() {
        performanceMonitor.recordRequest("/api/test1", 100);
        performanceMonitor.recordRequest("/api/test2", 200);

        assertEquals(150.0, performanceMonitor.getAverageProcessingTime());
    }

    @Test
    void testClearStats() {
        performanceMonitor.recordRequest("/api/test", 100);
        performanceMonitor.clearStats();

        assertEquals(0, performanceMonitor.getPathStats().size());
        assertEquals(0.0, performanceMonitor.getAverageProcessingTime());
    }

    @Test
    void testSetSlowRequestThreshold() {
        performanceMonitor.setSlowRequestThresholdMs(500);
        performanceMonitor.recordRequest("/api/test", 600);

        assertEquals(1, performanceMonitor.getPathStats().size());
    }

    @Test
    void testSetMemoryWarningThreshold() {
        performanceMonitor.setMemoryWarningThreshold(0.9);
        performanceMonitor.recordRequest("/api/test", 100);

        assertEquals(1, performanceMonitor.getPathStats().size());
    }

    @Test
    void testPerformanceStats() {
        PerformanceMonitor.PerformanceStats stats = new PerformanceMonitor.PerformanceStats();

        stats.recordRequest(100);
        stats.recordRequest(200);
        stats.recordRequest(150);

        assertEquals(3, stats.getRequestCount());
        assertEquals(150.0, stats.getAverageTime());
        assertEquals(200, stats.getMaxTime());
        assertEquals(100, stats.getMinTime());
    }
}
