"""性能分析器测试"""

import pytest
import time
from src.factors.engine.performance_profiler import PerformanceProfiler, ProfileRecord


class TestProfileRecord:
    """测试 ProfileRecord 数据类"""

    def test_profile_record_creation(self):
        """测试创建 ProfileRecord"""
        record = ProfileRecord(time_ms=1.5)
        assert record.time_ms == 1.5


class TestPerformanceProfiler:
    """测试 PerformanceProfiler 类"""

    def test_profiler_disabled_by_default(self):
        """测试默认情况下禁用"""
        profiler = PerformanceProfiler()
        assert profiler.enabled is False

    def test_profiler_enabled(self):
        """测试启用性能分析器"""
        profiler = PerformanceProfiler(enabled=True)
        assert profiler.enabled is True

    def test_measure_context_manager_disabled(self):
        """测试禁用时 measure 上下文管理器"""
        profiler = PerformanceProfiler(enabled=False)

        with profiler.measure("test_task"):
            time.sleep(0.001)

        # 禁用时不会记录数据
        assert len(profiler.records) == 0

    def test_measure_context_manager_enabled(self):
        """测试启用时 measure 上下文管理器"""
        profiler = PerformanceProfiler(enabled=True)

        with profiler.measure("test_task"):
            time.sleep(0.01)  # 10ms

        assert "test_task" in profiler.records
        assert profiler.records["test_task"].time_ms >= 0.01

    def test_measure_multiple_calls_accumulate(self):
        """测试多次调用同名任务会累加时间"""
        profiler = PerformanceProfiler(enabled=True)

        # 第一次调用
        with profiler.measure("task"):
            time.sleep(0.01)

        first_time = profiler.records["task"].time_ms

        # 第二次调用
        with profiler.measure("task"):
            time.sleep(0.01)

        # 时间应该累加
        assert profiler.records["task"].time_ms > first_time

    def test_measure_exception_handling(self):
        """测试异常发生时计时器正常闭合"""
        profiler = PerformanceProfiler(enabled=True)

        try:
            with profiler.measure("failing_task"):
                time.sleep(0.01)
                raise ValueError("Test error")
        except ValueError:
            pass

        # 异常发生时仍然记录了时间
        assert "failing_task" in profiler.records
        assert profiler.records["failing_task"].time_ms >= 0.01

    def test_get_report_empty(self):
        """测试空记录时的报告"""
        profiler = PerformanceProfiler(enabled=True)
        report = profiler.get_report()
        assert report == {}

    def test_get_report_with_data(self):
        """测试有数据时的报告"""
        profiler = PerformanceProfiler(enabled=True)

        with profiler.measure("task1"):
            time.sleep(0.02)
        with profiler.measure("task2"):
            time.sleep(0.01)

        report = profiler.get_report()

        assert report["enabled"] is True
        assert report["factor_count"] == 2
        assert report["total_time_ms"] > 0
        assert report["avg_time_ms"] > 0
        assert len(report["slowest_factors"]) <= 2
        assert "all_records" in report

    def test_get_report_sorts_by_time(self):
        """测试报告按时间排序"""
        profiler = PerformanceProfiler(enabled=True)

        # task1 耗时更长
        with profiler.measure("task1"):
            time.sleep(0.02)

        with profiler.measure("task2"):
            time.sleep(0.01)

        report = profiler.get_report()
        slowest = report["slowest_factors"]

        assert slowest[0][0] == "task1"  # 最慢的应该是 task1

    def test_reset_clears_data(self):
        """测试重置清除数据"""
        profiler = PerformanceProfiler(enabled=True)

        with profiler.measure("task"):
            time.sleep(0.01)

        assert len(profiler.records) == 1

        profiler.reset()

        assert len(profiler.records) == 0
        assert len(profiler._context_stack) == 0

    def test_print_report_disabled(self):
        """测试禁用时打印报告"""
        profiler = PerformanceProfiler(enabled=False)
        # 应该正常执行不报错
        profiler.print_report()

    def test_print_report_empty(self, capsys):
        """测试空数据时打印报告"""
        profiler = PerformanceProfiler(enabled=True)
        profiler.print_report()

        captured = capsys.readouterr()
        assert "无性能数据" in captured.out

    def test_print_report_with_data(self, capsys):
        """测试有数据时打印报告"""
        profiler = PerformanceProfiler(enabled=True)

        with profiler.measure("slow_task"):
            time.sleep(0.02)
        with profiler.measure("fast_task"):
            time.sleep(0.01)

        profiler.print_report()

        captured = capsys.readouterr()
        assert "Factor Engine 性能报告" in captured.out
        assert "slow_task" in captured.out
        assert "fast_task" in captured.out

    def test_get_factor_time(self):
        """测试获取单个因子的计算时间"""
        profiler = PerformanceProfiler(enabled=True)

        with profiler.measure("task"):
            time.sleep(0.01)

        time_val = profiler.get_factor_time("task")
        assert time_val is not None
        assert time_val >= 0.01

        # 不存在的因子返回 None
        assert profiler.get_factor_time("nonexistent") is None

    def test_nested_measure(self):
        """测试嵌套计时"""
        profiler = PerformanceProfiler(enabled=True)

        with profiler.measure("outer"):
            time.sleep(0.01)
            with profiler.measure("inner"):
                time.sleep(0.01)

        assert "outer" in profiler.records
        assert "inner" in profiler.records
        # 嵌套计时应该分别记录
        assert profiler.records["outer"].time_ms >= 0.01
        assert profiler.records["inner"].time_ms >= 0.01
