"""
测试框架配置模块
提供全局配置管理和环境变量加载功能
"""

import os
from pathlib import Path
from typing import Any, Dict, List, Optional
from dataclasses import dataclass, field
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()


@dataclass
class BrowserConfig:
    """浏览器配置类"""
    name: str
    headless: bool = False
    viewport_width: int = 1920
    viewport_height: int = 1080
    device_scale_factor: float = 1.0
    is_mobile: bool = False
    has_touch: bool = False
    locale: str = "zh-CN"
    timezone_id: str = "Asia/Shanghai"


@dataclass
class PerformanceThresholds:
    """性能指标阈值配置"""
    page_load_time: int = 3000  # 毫秒
    first_contentful_paint: int = 1500
    largest_contentful_paint: int = 2500
    time_to_interactive: int = 3000
    first_byte: int = 500
    dom_content_loaded: int = 1000


@dataclass
class ResponsiveBreakpoints:
    """响应式测试断点配置"""
    mobile: Dict[str, int] = field(default_factory=lambda: {"width": 375, "height": 667})
    tablet: Dict[str, int] = field(default_factory=lambda: {"width": 768, "height": 1024})
    desktop: Dict[str, int] = field(default_factory=lambda: {"width": 1920, "height": 1080})
    wide: Dict[str, int] = field(default_factory=lambda: {"width": 2560, "height": 1440})


class Settings:
    """全局配置管理类"""
    
    _instance: Optional['Settings'] = None
    _initialized: bool = False
    
    def __new__(cls) -> 'Settings':
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        if not Settings._initialized:
            self._load_config()
            Settings._initialized = True
    
    def _load_config(self) -> None:
        """加载所有配置"""
        # 基础配置
        self.base_url = self._get_env("TEST_BASE_URL", "http://localhost:3000")
        self.fallback_url = self._get_env("TEST_BASE_URL_FALLBACK", "")
        self.test_env = self._get_env("TEST_ENV", "development")
        
        # 浏览器配置
        self.default_browser = self._get_env("DEFAULT_BROWSER", "chromium")
        self.headless_mode = self._get_env("HEADLESS_MODE", "false").lower() == "true"
        self.viewport_width = int(self._get_env("DEFAULT_VIEWPORT_WIDTH", 1920))
        self.viewport_height = int(self._get_env("DEFAULT_VIEWPORT_HEIGHT", 1080))
        
        # 超时配置
        self.max_retries = int(self._get_env("MAX_RETRIES", 2))
        self.test_timeout = int(self._get_env("TEST_TIMEOUT", 60))
        self.page_load_timeout = int(self._get_env("PAGE_LOAD_TIMEOUT", 30000))
        self.element_timeout = int(self._get_env("ELEMENT_TIMEOUT", 10000))
        
        # 并行配置
        self.parallel_workers = int(self._get_env("PARALLEL_WORKERS", 4))
        
        # 截图和视频
        self.screenshot_on_failure = self._get_env("SCREENSHOT_ON_FAILURE", "true").lower() == "true"
        self.video_recording = self._get_env("VIDEO_RECORDING", "false").lower() == "true"
        self.screenshots_dir = self._get_env("SCREENSHOTS_DIR", "reports/screenshots")
        self.videos_dir = self._get_env("VIDEOS_DIR", "reports/videos")
        
        # 日志配置
        self.log_level = self._get_env("LOG_LEVEL", "INFO")
        self.log_file = self._get_env("LOG_FILE", "reports/e2e_tests.log")
        self.console_log = self._get_env("CONSOLE_LOG", "true").lower() == "true"
        
        # 报告配置
        self.report_title = self._get_env("REPORT_TITLE", "Novalon Website E2E测试报告")
        self.report_description = self._get_env(
            "REPORT_DESCRIPTION", 
            "Novalon Website端到端自动化测试报告"
        )
        self.junit_xml_report = self._get_env("JUNIT_XML_REPORT", "false").lower() == "true"
        self.junit_xml_path = self._get_env("JUNIT_XML_PATH", "reports/test-results.xml")
        
        # 性能阈值
        self._load_performance_thresholds()
        
        # 响应式断点
        self._load_responsive_breakpoints()
        
        # 浏览器列表
        self.browsers_to_test = ["chromium", "firefox", "webkit"]
        
        # 测试数据
        self._load_test_form_data()
        
        # CI/CD配置
        self.ci = self._get_env("CI", "false").lower() == "true"
        self.git_branch = self._get_env("GIT_BRANCH", "")
        self.git_commit = self._get_env("GIT_COMMIT", "")
        self.git_repository = self._get_env("GIT_REPOSITORY", "")
        
        # 创建必要的目录
        self._create_directories()
    
    def _get_env(self, key: str, default: str) -> str:
        """获取环境变量"""
        return os.environ.get(key, default)
    
    def _load_performance_thresholds(self) -> None:
        """加载性能阈值配置"""
        import json
        thresholds_str = self._get_env(
            "PERFORMANCE_THRESHOLDS",
            '{"page_load_time": 3000, "first_contentful_paint": 1500, '
            '"largest_contentful_paint": 2500, "time_to_interactive": 3000, '
            '"first_byte": 500, "dom_content_loaded": 1000}'
        )
        try:
            thresholds = json.loads(thresholds_str)
            self.performance_thresholds = PerformanceThresholds(**thresholds)
        except (json.JSONDecodeError, TypeError):
            self.performance_thresholds = PerformanceThresholds()
    
    def _load_responsive_breakpoints(self) -> None:
        """加载响应式断点配置"""
        import json
        breakpoints_str = self._get_env(
            "RESPONSIVE_BREAKPOINTS",
            '{"mobile": {"width": 375, "height": 667}, '
            '"tablet": {"width": 768, "height": 1024}, '
            '"desktop": {"width": 1920, "height": 1080}, '
            '"wide": {"width": 2560, "height": 1440}}'
        )
        try:
            breakpoints = json.loads(breakpoints_str)
            self.responsive_breakpoints = ResponsiveBreakpoints(**breakpoints)
        except (json.JSONDecodeError, TypeError):
            self.responsive_breakpoints = ResponsiveBreakpoints()
    
    def _load_test_form_data(self) -> None:
        """加载测试表单数据"""
        import json
        form_data_str = self._get_env(
            "TEST_FORM_DATA",
            '{"valid": {"name": "测试用户", "phone": "13800138000", '
            '"email": "test@example.com", "subject": "测试主题", '
            '"message": "这是一条测试消息，用于验证表单功能是否正常。"}, '
            '"invalid": {"email": "invalid-email", "phone": "123"}}'
        )
        try:
            self.test_form_data = json.loads(form_data_str)
        except json.JSONDecodeError:
            self.test_form_data = {
                "valid": {
                    "name": "测试用户",
                    "phone": "13800138000",
                    "email": "test@example.com",
                    "subject": "测试主题",
                    "message": "这是一条测试消息，用于验证表单功能是否正常。"
                },
                "invalid": {
                    "email": "invalid-email",
                    "phone": "123"
                }
            }
    
    def _create_directories(self) -> None:
        """创建必要的目录"""
        base_dirs = [
            self.screenshots_dir,
            self.videos_dir,
            "reports",
            "logs"
        ]
        for dir_path in base_dirs:
            Path(dir_path).mkdir(parents=True, exist_ok=True)
    
    def get_browser_config(self, browser_name: Optional[str] = None) -> BrowserConfig:
        """获取浏览器配置"""
        name = browser_name or self.default_browser
        
        return BrowserConfig(
            name=name,
            headless=self.headless_mode,
            viewport_width=self.viewport_width,
            viewport_height=self.viewport_height
        )
    
    def get_test_data_path(self, filename: str) -> Path:
        """获取测试数据文件路径"""
        return Path(__file__).parent / "test_data" / filename
    
    def get_reports_path(self, filename: str = "") -> Path:
        """获取报告目录路径"""
        reports_dir = Path("reports")
        reports_dir.mkdir(parents=True, exist_ok=True)
        if filename:
            return reports_dir / filename
        return reports_dir
    
    def is_ci_environment(self) -> bool:
        """检查是否为CI环境"""
        return self.ci or os.environ.get("CI", "").lower() in ["true", "1"]
    
    def get_base_url(self) -> str:
        """获取测试基础URL，自动降级到备用URL"""
        # 首先检查基础URL是否可用
        if self._check_url_accessible(self.base_url):
            return self.base_url
        
        # 如果基础URL不可用，尝试备用URL
        if self.fallback_url and self._check_url_accessible(self.fallback_url):
            return self.fallback_url
        
        # 如果都不可用，返回基础URL（测试时会报错）
        return self.base_url
    
    def _check_url_accessible(self, url: str) -> bool:
        """检查URL是否可访问"""
        import requests
        try:
            response = requests.get(url, timeout=5)
            return response.status_code < 500
        except requests.RequestException:
            return False


# 全局配置实例
settings = Settings()


def get_settings() -> Settings:
    """获取全局配置实例"""
    return settings
