"""
全面的工作表测试 - 提升覆盖率到80%+
"""

from pathlib import Path

import pytest

from src.symphra_excel import CellStyle, PredefinedStyles, ValidationError, Workbook


class TestWorksheetEdgeCases:
    """工作表边界条件测试"""

    def test_set_cell_value_edge_cases(self):
        """测试设置单元格值的边界条件"""
        wb = Workbook()
        sheet = wb.active

        # None值
        sheet.set_cell_value("A1", None)
        assert sheet.get_cell_value("A1") is None

        # 空字符串
        sheet.set_cell_value("A2", "")
        assert sheet.get_cell_value("A2") == ""

        # 超长字符串
        long_string = "A" * 1000
        sheet.set_cell_value("A3", long_string)
        assert sheet.get_cell_value("A3") == long_string

        # Unicode和表情符号
        unicode_text = "测试中文 🎉 emoji 😀 特殊字符 ♥️"
        sheet.set_cell_value("A4", unicode_text)
        assert sheet.get_cell_value("A4") == unicode_text

        # 特殊字符
        special_chars = "Line1\nLine2\tTab\rReturn"
        sheet.set_cell_value("A5", special_chars)
        assert sheet.get_cell_value("A5") == special_chars

        # 数字边界值
        sheet.set_cell_value("B1", 0)
        assert sheet.get_cell_value("B1") == 0

        sheet.set_cell_value("B2", -999999999)
        assert sheet.get_cell_value("B2") == -999999999

        sheet.set_cell_value("B3", 999999999)
        assert sheet.get_cell_value("B3") == 999999999

        # 浮点数
        sheet.set_cell_value("B4", 3.14159265359)
        assert abs(sheet.get_cell_value("B4") - 3.14159265359) < 1e-10

    def test_get_cell_value_edge_cases(self):
        """测试获取单元格值的边界条件"""
        wb = Workbook()
        sheet = wb.active

        # 空单元格 - 默认返回None
        value = sheet.get_cell_value("Z99")
        assert value is None

        # 不存在的单元格
        value = sheet.get_cell_value("AA100")
        assert value is None

    def test_worksheet_name_operations(self):
        """测试工作表名称操作"""
        wb = Workbook()
        sheet = wb.create_worksheet("OriginalName")

        # 获取名称
        assert sheet.name == "OriginalName"

        # 修改名称 - 修改sheet.name同时更新openpyxl的title
        sheet.name = "NewName"
        assert sheet.name == "NewName"

        # 通过新名称可以获取工作表
        sheet_by_new_name = wb.get_worksheet("NewName")
        assert sheet_by_new_name is not None
        assert sheet_by_new_name.name == "NewName"


class TestRangeOperations:
    """范围操作测试"""

    def test_get_range_values_comprehensive(self):
        """测试获取范围值的全面场景"""
        wb = Workbook()
        sheet = wb.active

        # 设置测试数据
        test_data = [
            ["A1", "B1", "C1"],
            ["A2", "B2", "C2"],
            ["A3", "B3", "C3"],
        ]
        for i, row in enumerate(test_data, start=1):
            for j, value in enumerate(row):
                sheet.set_cell_value(f"{chr(65 + j)}{i}", value)

        # 单行范围
        single_row = sheet.get_range_values("A1:C1")
        assert single_row == [["A1", "B1", "C1"]]

        # 单列范围
        single_col = sheet.get_range_values("A1:A3")
        assert single_col == [["A1"], ["A2"], ["A3"]]

        # 矩形范围
        rect_range = sheet.get_range_values("A1:C3")
        assert rect_range == test_data

        # 单个单元格范围
        single_cell = sheet.get_range_values("B2:B2")
        assert single_cell == [["B2"]]

    def test_set_range_values_comprehensive(self):
        """测试设置范围值的全面场景"""
        wb = Workbook()
        sheet = wb.active

        # 设置矩形数据
        data = [
            [1, 2, 3],
            [4, 5, 6],
            [7, 8, 9],
        ]
        sheet.set_range_values("A1", data)

        # 验证数据
        assert sheet.get_cell_value("A1") == 1
        assert sheet.get_cell_value("C3") == 9

        # 包含None的数据
        data_with_none = [
            [1, None, 3],
            [None, 5, None],
            [7, None, 9],
        ]
        sheet.set_range_values("E1", data_with_none)

        assert sheet.get_cell_value("E1") == 1
        assert sheet.get_cell_value("F1") is None
        assert sheet.get_cell_value("F2") == 5

        # 不规则嵌套列表
        irregular_data = [
            [1, 2],
            [3, 4, 5],
            [6],
        ]
        sheet.set_range_values("A10", irregular_data)

        assert sheet.get_cell_value("A10") == 1
        assert sheet.get_cell_value("C11") == 5
        assert sheet.get_cell_value("A12") == 6

    def test_clear_range(self):
        """测试清除范围"""
        wb = Workbook()
        sheet = wb.active

        # 设置数据和样式
        for i in range(1, 4):
            for j in range(1, 4):
                sheet.set_cell_value(f"{chr(64 + j)}{i}", f"Value {i},{j}")
                sheet.apply_style(f"{chr(64 + j)}{i}", PredefinedStyles.header_style())

        # 清除范围
        sheet.clear_range("A1:C3")

        # 验证数据已清除
        for i in range(1, 4):
            for j in range(1, 4):
                assert sheet.get_cell_value(f"{chr(64 + j)}{i}") is None


class TestRowColumnOperations:
    """行列操作测试"""

    def test_insert_rows_edge_cases(self):
        """测试插入行的边界条件"""
        wb = Workbook()
        sheet = wb.active

        # 插入初始数据
        sheet.set_cell_value("A1", "Row1")
        sheet.set_cell_value("A2", "Row2")
        sheet.set_cell_value("A3", "Row3")

        # 插入1行
        sheet.insert_rows(2, 1)
        assert sheet.get_cell_value("A1") == "Row1"
        assert sheet.get_cell_value("A2") is None  # 新插入的空行
        assert sheet.get_cell_value("A3") == "Row2"

        # 插入多行
        sheet.insert_rows(1, 3)
        assert sheet.get_cell_value("A1") is None
        assert sheet.get_cell_value("A4") == "Row1"

    def test_delete_rows_edge_cases(self):
        """测试删除行的边界条件"""
        wb = Workbook()
        sheet = wb.active

        # 插入初始数据
        for i in range(1, 11):
            sheet.set_cell_value(f"A{i}", f"Row{i}")

        # 删除单行
        sheet.delete_rows(5, 1)
        assert sheet.get_cell_value("A5") == "Row6"

        # 删除多行
        sheet.delete_rows(1, 3)
        assert sheet.get_cell_value("A1") == "Row4"

    def test_insert_columns_edge_cases(self):
        """测试插入列的边界条件"""
        wb = Workbook()
        sheet = wb.active

        # 插入初始数据
        sheet.set_cell_value("A1", "ColA")
        sheet.set_cell_value("B1", "ColB")
        sheet.set_cell_value("C1", "ColC")

        # 插入1列
        sheet.insert_columns(2, 1)
        assert sheet.get_cell_value("A1") == "ColA"
        assert sheet.get_cell_value("B1") is None  # 新插入的空列
        assert sheet.get_cell_value("C1") == "ColB"

        # 插入多列
        sheet.insert_columns(1, 2)
        assert sheet.get_cell_value("A1") is None
        assert sheet.get_cell_value("C1") == "ColA"

    def test_delete_columns_edge_cases(self):
        """测试删除列的边界条件"""
        wb = Workbook()
        sheet = wb.active

        # 插入初始数据
        for i in range(1, 11):
            sheet.set_cell_value(f"{chr(64 + i)}1", f"Col{chr(64 + i)}")

        # 删除单列
        sheet.delete_columns(5, 1)
        assert sheet.get_cell_value("E1") == "ColF"

        # 删除多列
        sheet.delete_columns(1, 2)
        assert sheet.get_cell_value("A1") == "ColC"


class TestStyleOperations:
    """样式操作测试"""

    def test_apply_style_comprehensive(self):
        """测试应用样式的全面场景"""
        wb = Workbook()
        sheet = wb.active

        # 创建自定义样式
        style = CellStyle()
        style.set_font(name="Arial", size=14, bold=True, color="FF0000")
        style.set_background_color("FFFF00")

        # 应用到单个单元格
        sheet.set_cell_value("A1", "Styled Cell")
        sheet.apply_style("A1", style)

        # 验证样式已应用
        assert "A1" in sheet._cached_styles

        # 应用预定义样式
        sheet.set_cell_value("B1", "Header")
        sheet.apply_style("B1", PredefinedStyles.header_style())

        assert "B1" in sheet._cached_styles

    def test_apply_range_style_comprehensive(self):
        """测试应用范围样式"""
        wb = Workbook()
        sheet = wb.active

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

        # 应用范围样式
        style = PredefinedStyles.data_style()
        sheet.apply_range_style("A1:C3", style)

        # 验证所有单元格都应用了样式
        for i in range(1, 4):
            for j in range(1, 4):
                assert f"{chr(64 + j)}{i}" in sheet._cached_styles

    def test_clear_cached_styles(self):
        """测试清除缓存样式"""
        wb = Workbook()
        sheet = wb.active

        # 应用一些样式
        for i in range(1, 11):
            sheet.set_cell_value(f"A{i}", f"Value {i}")
            sheet.apply_style(f"A{i}", PredefinedStyles.header_style())

        # 验证样式缓存不为空
        assert len(sheet._cached_styles) > 0

        # 清除缓存
        sheet.clear_cached_styles()

        # 验证缓存已清空
        assert len(sheet._cached_styles) == 0


class TestMergeCells:
    """合并单元格测试"""

    def test_merge_cells_comprehensive(self):
        """测试合并单元格"""
        wb = Workbook()
        sheet = wb.active

        # 基本合并
        sheet.set_cell_value("A1", "Merged Cell")
        sheet.merge_cells("A1:B2")

        # 验证合并成功 (openpyxl内部处理)
        # 这里我们主要测试方法调用不抛出异常

        # 合并大范围
        sheet.merge_cells("D1:F5")

    def test_unmerge_cells_comprehensive(self):
        """测试取消合并"""
        wb = Workbook()
        sheet = wb.active

        # 先合并
        sheet.merge_cells("A1:B2")

        # 取消合并
        sheet.unmerge_cells("A1:B2")

        # 取消合并不存在的合并单元格会抛出ValueError (openpyxl行为)
        # 这是预期的行为,我们验证异常被正确抛出
        with pytest.raises(ValueError, match="not merged"):
            sheet.unmerge_cells("C1:D2")


class TestAutoFit:
    """自动调整列宽行高测试"""

    def test_auto_fit_columns(self):
        """测试自动调整列宽"""
        wb = Workbook()
        sheet = wb.active

        # 插入不同长度的数据
        sheet.set_cell_value("A1", "Short")
        sheet.set_cell_value("B1", "This is a much longer text")
        sheet.set_cell_value("C1", "Medium length")

        # 自动调整所有列
        sheet.auto_fit_columns()

        # 验证列宽被设置 (非零)
        # openpyxl会设置column_dimensions

        # 自动调整特定范围
        sheet.auto_fit_columns(start_col=1, end_col=2)

    def test_auto_fit_rows(self):
        """测试自动调整行高"""
        wb = Workbook()
        sheet = wb.active

        # 插入数据
        for i in range(1, 6):
            sheet.set_cell_value(f"A{i}", f"Row {i}")

        # 自动调整所有行
        sheet.auto_fit_rows()

        # 自动调整特定范围
        sheet.auto_fit_rows(start_row=1, end_row=3)


class TestIterators:
    """迭代器测试"""

    def test_iter_rows(self):
        """测试行迭代器"""
        wb = Workbook()
        sheet = wb.active

        # 设置测试数据
        for i in range(1, 6):
            for j in range(1, 4):
                sheet.set_cell_value(f"{chr(64 + j)}{i}", f"R{i}C{j}")

        # 迭代所有行
        rows = list(
            sheet.iter_rows(
                min_row=1, max_row=5, min_col=1, max_col=3, values_only=True
            )
        )
        assert len(rows) == 5
        assert rows[0] == ("R1C1", "R1C2", "R1C3")

        # 迭代部分行
        partial_rows = list(
            sheet.iter_rows(
                min_row=2, max_row=3, min_col=1, max_col=2, values_only=True
            )
        )
        assert len(partial_rows) == 2
        assert partial_rows[0] == ("R2C1", "R2C2")

    def test_iter_cols(self):
        """测试列迭代器"""
        wb = Workbook()
        sheet = wb.active

        # 设置测试数据
        for i in range(1, 6):
            for j in range(1, 4):
                sheet.set_cell_value(f"{chr(64 + j)}{i}", f"R{i}C{j}")

        # 迭代所有列
        cols = list(
            sheet.iter_cols(
                min_row=1, max_row=5, min_col=1, max_col=3, values_only=True
            )
        )
        assert len(cols) == 3
        assert cols[0] == ("R1C1", "R2C1", "R3C1", "R4C1", "R5C1")

        # 迭代部分列
        partial_cols = list(
            sheet.iter_cols(
                min_row=1, max_row=3, min_col=2, max_col=3, values_only=True
            )
        )
        assert len(partial_cols) == 2
        assert partial_cols[0] == ("R1C2", "R2C2", "R3C2")


class TestUtilityMethods:
    """工具方法测试"""

    def test_get_used_range(self):
        """测试获取使用范围"""
        wb = Workbook()
        sheet = wb.active

        # 空工作表
        used_range = sheet.get_used_range()
        assert used_range == "A1:A1"

        # 有数据的工作表
        sheet.set_cell_value("A1", "Start")
        sheet.set_cell_value("E10", "End")

        used_range = sheet.get_used_range()
        assert used_range == "A1:E10"

        # 不连续数据
        sheet.set_cell_value("Z100", "Far")
        used_range = sheet.get_used_range()
        assert used_range == "A1:Z100"

    def test_max_row_max_column(self):
        """测试最大行和最大列"""
        wb = Workbook()
        sheet = wb.active

        # 空工作表
        assert sheet.max_row == 1  # openpyxl默认至少为1
        assert sheet.max_column == 1

        # 添加数据
        sheet.set_cell_value("A1", "Data")
        assert sheet.max_row >= 1
        assert sheet.max_column >= 1

        sheet.set_cell_value("Z50", "Far Data")
        assert sheet.max_row >= 50
        assert sheet.max_column >= 26


class TestAppendOperations:
    """追加操作测试"""

    def test_append_row(self):
        """测试追加单行"""
        wb = Workbook()
        sheet = wb.active

        # 追加行
        sheet.append_row(["A", "B", "C"])
        sheet.append_row([1, 2, 3])
        sheet.append_row(["X", "Y", "Z"])

        # 验证数据
        assert sheet.get_cell_value("A1") == "A"
        assert sheet.get_cell_value("B2") == 2
        assert sheet.get_cell_value("C3") == "Z"

    def test_append_rows(self):
        """测试批量追加行"""
        wb = Workbook()
        sheet = wb.active

        # 批量追加
        rows = [
            ["Header1", "Header2", "Header3"],
            [1, 2, 3],
            [4, 5, 6],
            [7, 8, 9],
        ]
        sheet.append_rows(rows)

        # 验证数据
        assert sheet.get_cell_value("A1") == "Header1"
        assert sheet.get_cell_value("B4") == 8
        assert sheet.max_row >= 4


class TestDunderMethods:
    """Dunder方法测试"""

    def test_getitem_setitem(self):
        """测试[]操作符"""
        wb = Workbook()
        sheet = wb.active

        # 使用[]设置值
        sheet["A1"] = "Test Value"
        assert sheet["A1"] == "Test Value"

        # 使用[]设置数字
        sheet["B1"] = 123
        assert sheet["B1"] == 123

        # 使用[]设置公式
        sheet["C1"] = "=A1&B1"
        assert sheet["C1"] == "=A1&B1"


class TestReadOnlyMode:
    """只读模式测试"""

    def test_read_only_restrictions(self, tmp_path: Path):
        """测试只读模式的限制"""
        # 创建并保存测试文件
        wb = Workbook()
        sheet = wb.active
        sheet.set_cell_value("A1", "Test Data")
        file_path = tmp_path / "readonly_test.xlsx"
        wb.save(file_path)

        # 以只读模式打开
        wb_readonly = Workbook(file_path, read_only=True)
        sheet_readonly = wb_readonly.active

        # 读取应该正常
        value = sheet_readonly.get_cell_value("A1")
        assert value == "Test Data"

        # 写入应该抛出异常
        with pytest.raises(ValidationError, match="只读模式"):
            sheet_readonly.set_cell_value("A2", "New Data")

        with pytest.raises(ValidationError, match="只读模式"):
            sheet_readonly.set_range_values("A1", [[1, 2, 3]])

        with pytest.raises(ValidationError, match="只读"):
            sheet_readonly.append_row([1, 2, 3])

        with pytest.raises(ValidationError, match="只读"):
            sheet_readonly.insert_rows(1, 1)

        with pytest.raises(ValidationError, match="当前模式不支持"):
            sheet_readonly.delete_rows(1, 1)

        with pytest.raises(ValidationError, match="当前模式不支持"):
            sheet_readonly.insert_columns(1, 1)

        with pytest.raises(ValidationError, match="当前模式不支持"):
            sheet_readonly.delete_columns(1, 1)


class TestWriteOnlyMode:
    """只写模式测试"""

    def test_write_only_restrictions(self, tmp_path: Path):
        """测试只写模式的限制"""
        wb = Workbook(write_only=True)
        sheet = wb.active

        # append操作应该正常
        sheet.append_row(["Header1", "Header2", "Header3"])
        sheet.append_row([1, 2, 3])

        # 读取应该抛出异常
        with pytest.raises(ValidationError, match="只写"):
            sheet.get_cell_value("A1")

        # 随机访问应该抛出异常
        with pytest.raises(ValidationError, match="只写"):
            sheet.set_cell_value("A1", "Test")

        # 范围操作应该抛出异常
        with pytest.raises(ValidationError, match="只写"):
            sheet.get_range_values("A1:B2")

        with pytest.raises(ValidationError, match="只写"):
            sheet.set_range_values("A1", [[1, 2]])

        # 样式操作应该抛出异常
        with pytest.raises(ValidationError, match="只写"):
            sheet.apply_style("A1", PredefinedStyles.header_style())

        with pytest.raises(ValidationError, match="只写"):
            sheet.apply_range_style("A1:B2", PredefinedStyles.data_style())

        # 结构操作应该抛出异常
        with pytest.raises(ValidationError, match="只写"):
            sheet.merge_cells("A1:B2")

        with pytest.raises(ValidationError, match="只写"):
            sheet.insert_rows(1, 1)

        with pytest.raises(ValidationError, match="当前模式不支持"):
            sheet.delete_rows(1, 1)

        with pytest.raises(ValidationError, match="当前模式不支持"):
            sheet.insert_columns(1, 1)

        with pytest.raises(ValidationError, match="只写"):
            sheet.auto_fit_columns()

        with pytest.raises(ValidationError, match="只写"):
            sheet.clear_range("A1:B2")

        with pytest.raises(ValidationError, match="只写"):
            sheet.insert_image("test.png", "A1")

        # 保存应该正常
        file_path = tmp_path / "writeonly_test.xlsx"
        wb.save(file_path)
        assert file_path.exists()

    def test_write_only_worksheet_name_restriction(self):
        """测试只写模式不能重命名工作表"""
        wb = Workbook(write_only=True)
        sheet = wb.active

        with pytest.raises(ValidationError, match="只写模式下无法重命名"):
            sheet.name = "NewName"
