"""
测试：Config 序列化和自定义参数
"""
import pytest
import sys
import os
import json
import tempfile

sys.path.insert(0, "src")

from playwright_ez import Config, get_config, set_config


class TestConfigSerialization:
    """测试 Config 序列化"""

    def test_to_dict(self):
        """测试导出为字典"""
        config = Config(headless=False, browser_type="firefox")

        d = config.to_dict()

        assert isinstance(d, dict)
        assert d["headless"] is False
        assert d["browser_type"] == "firefox"
        assert "default_timeout" in d
        assert "extra_params" in d

    def test_from_dict(self):
        """测试从字典创建"""
        data = {
            "headless": False,
            "browser_type": "webkit",
            "default_timeout": 60.0,
        }

        config = Config.from_dict(data)

        assert config.headless is False
        assert config.browser_type == "webkit"
        assert config.default_timeout == 60.0

    def test_from_dict_ignores_invalid_fields(self):
        """测试忽略无效字段"""
        data = {
            "headless": True,
            "invalid_field": "should_be_ignored",
        }

        config = Config.from_dict(data)

        assert config.headless is True
        assert not hasattr(config, "invalid_field")

    def test_to_json(self):
        """测试导出为 JSON"""
        config = Config(headless=True)

        json_str = config.to_json()

        assert isinstance(json_str, str)
        data = json.loads(json_str)
        assert data["headless"] is True

    def test_from_json(self):
        """测试从 JSON 创建"""
        json_str = '{"headless": false, "browser_type": "firefox"}'

        config = Config.from_json(json_str)

        assert config.headless is False
        assert config.browser_type == "firefox"

    def test_save_and_load_json(self):
        """测试保存和加载 JSON 文件"""
        config = Config(
            headless=False,
            browser_type="firefox",
            default_timeout=45.0,
        )

        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
            temp_path = f.name

        try:
            # 保存
            config.save(temp_path)

            # 加载
            loaded = Config.load(temp_path)

            assert loaded.headless is False
            assert loaded.browser_type == "firefox"
            assert loaded.default_timeout == 45.0
        finally:
            os.unlink(temp_path)

    def test_merge(self):
        """测试合并配置"""
        config = Config(headless=True, browser_type="chromium")

        merged = config.merge(headless=False, default_timeout=60.0)

        # 原配置不变
        assert config.headless is True
        assert config.default_timeout == 30.0

        # 新配置已合并
        assert merged.headless is False
        assert merged.default_timeout == 60.0
        assert merged.browser_type == "chromium"

    def test_copy(self):
        """测试复制配置"""
        config = Config(headless=False)
        config.set_extra("key", "value")

        copied = config.copy()

        assert copied.headless is False
        assert copied.get_extra("key") == "value"

        # 修改副本不影响原配置
        copied.set_extra("key", "new_value")
        assert config.get_extra("key") == "value"


class TestConfigExtraParams:
    """测试 Config 自定义参数"""

    def test_set_and_get_extra(self):
        """测试设置和获取自定义参数"""
        config = Config()

        config.set_extra("api_key", "test123")
        config.set_extra("base_url", "https://api.example.com")

        assert config.get_extra("api_key") == "test123"
        assert config.get_extra("base_url") == "https://api.example.com"

    def test_get_extra_with_default(self):
        """测试获取不存在的参数返回默认值"""
        config = Config()

        result = config.get_extra("nonexistent", "default_value")

        assert result == "default_value"

    def test_get_extra_none_for_missing(self):
        """测试获取不存在的参数返回 None"""
        config = Config()

        result = config.get_extra("nonexistent")

        assert result is None

    def test_update_extra(self):
        """测试批量更新自定义参数"""
        config = Config()

        config.update_extra({
            "key1": "value1",
            "key2": "value2",
            "key3": 123,
        })

        assert config.get_extra("key1") == "value1"
        assert config.get_extra("key2") == "value2"
        assert config.get_extra("key3") == 123

    def test_delete_extra(self):
        """测试删除自定义参数"""
        config = Config()
        config.set_extra("to_delete", "value")

        result = config.delete_extra("to_delete")

        assert result is True
        assert config.get_extra("to_delete") is None

    def test_delete_extra_nonexistent(self):
        """测试删除不存在的参数"""
        config = Config()

        result = config.delete_extra("nonexistent")

        assert result is False

    def test_has_extra(self):
        """测试检查参数是否存在"""
        config = Config()
        config.set_extra("exists", "value")

        assert config.has_extra("exists") is True
        assert config.has_extra("not_exists") is False

    def test_clear_extra(self):
        """测试清空所有自定义参数"""
        config = Config()
        config.set_extra("key1", "value1")
        config.set_extra("key2", "value2")

        config.clear_extra()

        assert config.get_extra("key1") is None
        assert config.get_extra("key2") is None

    def test_extra_params_in_serialization(self):
        """测试自定义参数在序列化中保留"""
        config = Config(headless=False)
        config.set_extra("api_key", "secret123")
        config.set_extra("timeout", 60)

        # 测试 to_dict
        d = config.to_dict()
        assert "extra_params" in d
        assert d["extra_params"]["api_key"] == "secret123"
        assert d["extra_params"]["timeout"] == 60

        # 测试 from_dict
        loaded = Config.from_dict(d)
        assert loaded.get_extra("api_key") == "secret123"
        assert loaded.get_extra("timeout") == 60

    def test_extra_params_in_json(self):
        """测试自定义参数在 JSON 序列化中保留"""
        config = Config()
        config.set_extra("custom_key", "custom_value")

        json_str = config.to_json()

        # 验证 JSON 包含 extra_params
        data = json.loads(json_str)
        assert data["extra_params"]["custom_key"] == "custom_value"

        # 从 JSON 加载
        loaded = Config.from_json(json_str)
        assert loaded.get_extra("custom_key") == "custom_value"

    def test_complex_extra_params(self):
        """测试复杂类型的自定义参数"""
        config = Config()

        # 设置复杂参数
        config.set_extra("headers", {
            "Authorization": "Bearer token",
            "Content-Type": "application/json",
        })
        config.set_extra("retry_config", {
            "max_retries": 3,
            "delay": 1.5,
        })
        config.set_extra("urls", [
            "https://api.example.com/v1",
            "https://api.example.com/v2",
        ])

        # 验证
        headers = config.get_extra("headers")
        assert headers["Authorization"] == "Bearer token"

        retry = config.get_extra("retry_config")
        assert retry["max_retries"] == 3

        urls = config.get_extra("urls")
        assert len(urls) == 2


class TestGlobalConfig:
    """测试全局配置"""

    def test_get_config(self):
        """测试获取全局配置"""
        config = get_config()

        assert isinstance(config, Config)

    def test_set_config(self):
        """测试设置全局配置"""
        custom_config = Config(headless=False)
        custom_config.set_extra("test_key", "test_value")

        set_config(custom_config)

        # 获取的应该是刚设置的配置
        current = get_config()
        assert current.headless is False
        assert current.get_extra("test_key") == "test_value"

        # 恢复默认配置
        set_config(Config())


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
