"""
性能基准测试

使用pytest-benchmark进行性能测试和基准记录
"""

import tracemalloc
from pathlib import Path

import pytest

from src.symphra_excel import CellStyle, PredefinedStyles, Workbook


class TestWritePerformance:
    """写入性能测试"""

    def test_write_1000_cells(self, benchmark):
        """测试写入1000个单元格的性能"""

        def write_cells():
            wb = Workbook()
            sheet = wb.active
            for i in range(1000):
                sheet.set_cell_value(f"A{i + 1}", f"Data {i}")
            return wb

        result = benchmark(write_cells)
        assert result is not None

    def test_write_large_dataset(self, benchmark):
        """测试写入大数据集性能 (100x100 = 10000单元格)"""

        def write_data():
            wb = Workbook()
            sheet = wb.active
            for i in range(100):
                row_data = [f"Data {i},{j}" for j in range(100)]
                sheet.append_row(row_data)
            return wb

        result = benchmark(write_data)
        assert result is not None

    def test_write_with_styles(self, benchmark):
        """测试带样式写入性能"""

        def write_with_styles():
            wb = Workbook()
            sheet = wb.active
            style = PredefinedStyles.header_style()

            for i in range(100):
                sheet.set_cell_value(f"A{i + 1}", f"Styled {i}")
                sheet.apply_style(f"A{i + 1}", style)

            return wb

        result = benchmark(write_with_styles)
        assert result is not None


class TestReadPerformance:
    """读取性能测试"""

    def test_read_1000_cells(self, benchmark):
        """测试读取1000个单元格的性能"""
        # 准备数据
        wb = Workbook()
        sheet = wb.active
        for i in range(1000):
            sheet.set_cell_value(f"A{i + 1}", f"Data {i}")

        def read_cells():
            values = []
            for i in range(1000):
                val = sheet.get_cell_value(f"A{i + 1}")
                values.append(val)
            return values

        result = benchmark(read_cells)
        assert len(result) == 1000

    def test_read_range(self, benchmark):
        """测试读取范围性能"""
        # 准备数据
        wb = Workbook()
        sheet = wb.active
        data = [[f"R{i}C{j}" for j in range(50)] for i in range(50)]
        sheet.set_range_values("A1", data)

        def read_range():
            return sheet.get_range_values("A1:AX50")

        result = benchmark(read_range)
        assert len(result) == 50
        assert len(result[0]) == 50


class TestStylePerformance:
    """样式性能测试"""

    def test_apply_styles_100_cells(self, benchmark):
        """测试应用样式到100个单元格"""
        wb = Workbook()
        sheet = wb.active
        style = PredefinedStyles.data_style()

        # 先填充数据
        for i in range(100):
            sheet.set_cell_value(f"A{i + 1}", f"Data {i}")

        def apply_styles():
            for i in range(100):
                sheet.apply_style(f"A{i + 1}", style)

        benchmark(apply_styles)

    def test_apply_range_style(self, benchmark):
        """测试应用范围样式性能"""
        wb = Workbook()
        sheet = wb.active

        # 填充10x10数据
        for i in range(10):
            for j in range(10):
                sheet.set_cell_value(f"{chr(65 + j)}{i + 1}", f"Cell {i},{j}")

        style = PredefinedStyles.header_style()

        def apply_range_style():
            sheet.apply_range_style("A1:J10", style)

        benchmark(apply_range_style)

    def test_create_complex_style(self, benchmark):
        """测试创建复杂样式的性能"""

        def create_style():
            style = CellStyle()
            style.set_font(
                name="Arial", size=14, bold=True, italic=True, color="#FF0000"
            )
            style.set_background_color("#FFFF00")
            style.set_alignment(horizontal="center", vertical="middle", wrap_text=True)
            return style

        result = benchmark(create_style)
        assert result is not None


class TestWorkbookPerformance:
    """工作簿性能测试"""

    def test_create_multiple_worksheets(self, benchmark):
        """测试创建多个工作表"""

        def create_worksheets():
            wb = Workbook()
            for i in range(50):
                wb.create_worksheet(f"Sheet{i}")
            return wb

        result = benchmark(create_worksheets)
        assert len(result.get_sheet_names()) == 51  # +1 默认sheet

    def test_save_workbook(self, benchmark, tmp_path: Path):
        """测试保存工作簿性能"""
        # 准备数据
        wb = Workbook()
        sheet = wb.active
        for i in range(500):
            sheet.append_row([f"Data{i}", i, i * 2, i * 3])

        file_path = tmp_path / "benchmark_save.xlsx"

        def save_workbook():
            wb.save(file_path)

        benchmark(save_workbook)
        assert file_path.exists()

    def test_load_workbook(self, benchmark, tmp_path: Path):
        """测试加载工作簿性能"""
        # 准备文件
        wb = Workbook()
        sheet = wb.active
        for i in range(500):
            sheet.append_row([f"Data{i}", i, i * 2])

        file_path = tmp_path / "benchmark_load.xlsx"
        wb.save(file_path)

        def load_workbook():
            return Workbook.load(file_path)

        result = benchmark(load_workbook)
        assert result is not None


class TestMemoryUsage:
    """内存使用测试"""

    def test_memory_usage_1000_cells(self):
        """测试1000个单元格的内存使用"""
        tracemalloc.start()

        wb = Workbook()
        sheet = wb.active

        for i in range(1000):
            sheet.set_cell_value(f"A{i + 1}", f"Data {i}")

        current, peak = tracemalloc.get_traced_memory()
        tracemalloc.stop()

        # 记录内存使用(不设置硬性断言,因为环境不同)
        print("\n内存使用 - 1000单元格:")
        print(f"  当前: {current / 1024 / 1024:.2f} MB")
        print(f"  峰值: {peak / 1024 / 1024:.2f} MB")

        # 合理的内存上限: 100MB
        assert peak < 100 * 1024 * 1024, f"内存使用过高: {peak / 1024 / 1024:.2f} MB"

    def test_memory_usage_10000_cells(self):
        """测试10000个单元格的内存使用"""
        tracemalloc.start()

        wb = Workbook()
        sheet = wb.active

        # 使用append_row更高效
        for i in range(100):
            row = [f"Data {i},{j}" for j in range(100)]
            sheet.append_row(row)

        current, peak = tracemalloc.get_traced_memory()
        tracemalloc.stop()

        print("\n内存使用 - 10000单元格:")
        print(f"  当前: {current / 1024 / 1024:.2f} MB")
        print(f"  峰值: {peak / 1024 / 1024:.2f} MB")

        # 合理的内存上限: 200MB
        assert peak < 200 * 1024 * 1024, f"内存使用过高: {peak / 1024 / 1024:.2f} MB"

    def test_memory_usage_with_styles(self):
        """测试带样式的内存使用"""
        tracemalloc.start()

        wb = Workbook()
        sheet = wb.active
        style = PredefinedStyles.header_style()

        for i in range(500):
            sheet.set_cell_value(f"A{i + 1}", f"Styled {i}")
            sheet.apply_style(f"A{i + 1}", style)

        current, peak = tracemalloc.get_traced_memory()
        tracemalloc.stop()

        print("\n内存使用 - 500单元格带样式:")
        print(f"  当前: {current / 1024 / 1024:.2f} MB")
        print(f"  峰值: {peak / 1024 / 1024:.2f} MB")

        # 样式会增加内存使用,但应该在合理范围
        assert peak < 150 * 1024 * 1024, f"内存使用过高: {peak / 1024 / 1024:.2f} MB"


class TestBatchOperations:
    """批量操作性能测试"""

    def test_append_rows_performance(self, benchmark):
        """测试批量追加行性能"""

        def append_rows():
            wb = Workbook()
            sheet = wb.active

            rows = [[f"R{i}C{j}" for j in range(20)] for i in range(100)]
            sheet.append_rows(rows)

            return wb

        result = benchmark(append_rows)
        assert result is not None

    def test_set_range_values_performance(self, benchmark):
        """测试设置范围值性能"""

        def set_range():
            wb = Workbook()
            sheet = wb.active

            data = [[f"R{i}C{j}" for j in range(50)] for i in range(50)]
            sheet.set_range_values("A1", data)

            return wb

        result = benchmark(set_range)
        assert result is not None


class TestComparisonWithDirectOpenpyxl:
    """与直接使用openpyxl的性能对比"""

    def test_symphra_write(self, benchmark):
        """Symphra Excel写入性能"""

        def write_with_symphra():
            wb = Workbook()
            sheet = wb.active
            for i in range(500):
                sheet.set_cell_value(f"A{i + 1}", f"Data {i}")
            return wb

        benchmark(write_with_symphra)

    def test_direct_openpyxl_write(self, benchmark):
        """直接使用openpyxl写入性能"""
        from openpyxl import Workbook as OpenpyxlWorkbook

        def write_with_openpyxl():
            wb = OpenpyxlWorkbook()
            sheet = wb.active
            for i in range(500):
                sheet[f"A{i + 1}"] = f"Data {i}"
            return wb

        benchmark(write_with_openpyxl)


@pytest.mark.slow
class TestLargeScaleOperations:
    """大规模操作测试(标记为slow,可以选择性运行)"""

    def test_write_100k_cells(self):
        """测试写入100k单元格"""
        wb = Workbook()
        sheet = wb.active

        # 1000行 x 100列 = 100k单元格
        for i in range(1000):
            row = [f"Data {i},{j}" for j in range(100)]
            sheet.append_row(row)

        # 验证
        assert sheet.max_row >= 1000

    def test_save_large_workbook(self, tmp_path: Path):
        """测试保存大工作簿"""
        wb = Workbook()
        sheet = wb.active

        for i in range(5000):
            sheet.append_row([f"Data{i}", i, i * 2, i * 3])

        file_path = tmp_path / "large_workbook.xlsx"
        wb.save(file_path)

        # 验证文件大小合理
        file_size = file_path.stat().st_size
        print(f"\n大工作簿文件大小: {file_size / 1024 / 1024:.2f} MB")

        assert file_path.exists()
        assert file_size > 0
