"""
配置模块
"""
from dataclasses import dataclass, field, asdict
from typing import Optional, Dict, Any
from loguru import logger
import sys
import json
from pathlib import Path


@dataclass
class Config:
    """Playwright-EZ 配置"""

    # 浏览器配置
    headless: bool = True
    browser_type: str = "chromium"  # chromium, firefox, webkit

    # 窗口配置
    maximize_window: bool = False  # 启动时最大化窗口
    viewport_width: Optional[int] = None  # 视口宽度
    viewport_height: Optional[int] = None  # 视口高度

    # 弹窗配置
    auto_close_popup: bool = False  # 自动关闭弹窗
    popup_close_timeout: float = 5.0  # 弹窗关闭超时（秒）

    # 高亮配置
    highlight_enabled: bool = True
    highlight_color: str = "red"
    highlight_duration: float = 0.5  # 秒
    highlight_style: str = "2px solid {color}"

    # 等待配置
    default_timeout: float = 30.0  # 秒
    poll_interval: float = 0.1  # 轮询间隔
    stability_threshold: int = 3  # 元素稳定性阈值（连续N次检测到才算稳定）

    # 日志配置
    log_enabled: bool = True
    log_level: str = "DEBUG"
    log_format: str = "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"
    log_to_file: bool = True  # 是否保存日志到文件
    log_file_path: str = "playwright_ez.log"  # 日志文件路径
    log_file_rotation: str = "10 MB"  # 日志文件轮转大小
    log_file_retention: str = "7 days"  # 日志文件保留时间

    # 多标签配置
    max_tabs: int = 10  # 最大标签页数量

    # 截图配置
    screenshot_on_error: bool = True
    screenshot_dir: str = "./screenshots"

    # 反检测配置
    stealth_enabled: bool = True  # 默认启用反检测
    stealth_user_agent: Optional[str] = None  # 自定义UA（None则随机）
    stealth_locale: Optional[str] = None  # 自定义语言（None则随机）
    stealth_timezone: Optional[str] = None  # 自定义时区（None则随机）
    stealth_viewport: Optional[dict] = None  # 自定义视口（None则随机）

    # 人类化操作配置
    human_behavior_enabled: bool = False  # 默认关闭人类化操作
    human_type_delay_min: int = 50  # 打字最小延迟(毫秒)
    human_type_delay_max: int = 150  # 打字最大延迟(毫秒)
    human_mouse_steps: int = 15  # 鼠标移动步数
    human_scroll_steps: int = 8  # 滚动步数

    # 自定义参数（全局统一配置存储）
    extra_params: Dict[str, Any] = field(default_factory=dict)

    def setup_logger(self):
        """配置日志器"""
        logger.remove()
        if self.log_enabled:
            # 控制台输出
            logger.add(
                sys.stderr,
                format=self.log_format,
                level=self.log_level,
                colorize=True,
            )
            # 文件输出（可单独控制）
            if self.log_to_file:
                logger.add(
                    self.log_file_path,
                    format=self.log_format,
                    level=self.log_level,
                    rotation=self.log_file_rotation,
                    retention=self.log_file_retention,
                )
        return logger

    # ==================== 序列化方法 ====================

    def to_dict(self) -> Dict[str, Any]:
        """
        导出配置为字典

        Returns:
            Dict[str, Any]: 配置字典
        """
        return asdict(self)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Config":
        """
        从字典创建配置

        Args:
            data: 配置字典

        Returns:
            Config: 配置实例
        """
        # 过滤掉不存在的字段
        valid_fields = {f.name for f in cls.__dataclass_fields__.values()}
        filtered_data = {k: v for k, v in data.items() if k in valid_fields}
        return cls(**filtered_data)

    def to_json(self, indent: int = 2) -> str:
        """
        导出配置为 JSON 字符串

        Args:
            indent: 缩进空格数

        Returns:
            str: JSON 字符串
        """
        return json.dumps(self.to_dict(), indent=indent, ensure_ascii=False)

    @classmethod
    def from_json(cls, json_str: str) -> "Config":
        """
        从 JSON 字符串创建配置

        Args:
            json_str: JSON 字符串

        Returns:
            Config: 配置实例
        """
        data = json.loads(json_str)
        return cls.from_dict(data)

    def save(self, filepath: str) -> None:
        """
        保存配置到文件

        支持的文件格式：
            - .json: JSON 格式
            - .yaml/.yml: YAML 格式（需要安装 PyYAML）

        Args:
            filepath: 文件路径

        Example:
            config.save("config.json")
            config.save("config.yaml")
        """
        path = Path(filepath)
        path.parent.mkdir(parents=True, exist_ok=True)

        if path.suffix in (".yaml", ".yml"):
            try:
                import yaml
                with open(path, "w", encoding="utf-8") as f:
                    yaml.dump(self.to_dict(), f, default_flow_style=False, allow_unicode=True)
            except ImportError:
                raise ImportError("需要安装 PyYAML: pip install pyyaml")
        else:
            # 默认使用 JSON
            with open(path, "w", encoding="utf-8") as f:
                json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)

    @classmethod
    def load(cls, filepath: str) -> "Config":
        """
        从文件加载配置

        Args:
            filepath: 文件路径

        Returns:
            Config: 配置实例

        Example:
            config = Config.load("config.json")
        """
        path = Path(filepath)

        if not path.exists():
            raise FileNotFoundError(f"配置文件不存在: {filepath}")

        if path.suffix in (".yaml", ".yml"):
            try:
                import yaml
                with open(path, "r", encoding="utf-8") as f:
                    data = yaml.safe_load(f)
            except ImportError:
                raise ImportError("需要安装 PyYAML: pip install pyyaml")
        else:
            with open(path, "r", encoding="utf-8") as f:
                data = json.load(f)

        return cls.from_dict(data)

    def merge(self, **kwargs) -> "Config":
        """
        合并配置（创建新实例）

        Args:
            **kwargs: 要合并的配置项

        Returns:
            Config: 新的配置实例

        Example:
            new_config = config.merge(headless=False, browser_type="firefox")
        """
        data = self.to_dict()
        data.update(kwargs)
        return Config.from_dict(data)

    def copy(self) -> "Config":
        """
        复制配置

        Returns:
            Config: 配置副本
        """
        return Config.from_dict(self.to_dict())

    # ==================== 自定义参数方法 ====================

    def get_extra(self, key: str, default: Any = None) -> Any:
        """
        获取自定义参数

        Args:
            key: 参数名
            default: 默认值

        Returns:
            参数值

        Example:
            api_key = config.get_extra('api_key')
            timeout = config.get_extra('custom_timeout', 30)
        """
        return self.extra_params.get(key, default)

    def set_extra(self, key: str, value: Any) -> None:
        """
        设置自定义参数

        Args:
            key: 参数名
            value: 参数值

        Example:
            config.set_extra('api_key', 'xxx')
            config.set_extra('custom_timeout', 60)
        """
        self.extra_params[key] = value

    def update_extra(self, params: Dict[str, Any]) -> None:
        """
        批量更新自定义参数

        Args:
            params: 参数字典

        Example:
            config.update_extra({
                'api_key': 'xxx',
                'base_url': 'https://api.example.com',
            })
        """
        self.extra_params.update(params)

    def delete_extra(self, key: str) -> bool:
        """
        删除自定义参数

        Args:
            key: 参数名

        Returns:
            bool: 是否成功删除
        """
        if key in self.extra_params:
            del self.extra_params[key]
            return True
        return False

    def clear_extra(self) -> None:
        """清空所有自定义参数"""
        self.extra_params.clear()

    def has_extra(self, key: str) -> bool:
        """检查自定义参数是否存在"""
        return key in self.extra_params

    def __repr__(self) -> str:
        return f"Config(browser_type={self.browser_type}, headless={self.headless})"


# 全局配置实例
_global_config: Optional[Config] = None


def get_config() -> Config:
    """获取全局配置"""
    global _global_config
    if _global_config is None:
        _global_config = Config()
        _global_config.setup_logger()
    return _global_config


def set_config(config: Config):
    """设置全局配置"""
    global _global_config
    _global_config = config
    _global_config.setup_logger()
