"""
页面对象基类
提供页面对象模式的基础框架
"""

from typing import Any, Dict, List, Optional, Tuple, Union
from urllib.parse import urljoin, urlparse

from playwright.sync_api import Page, Locator, FrameLocator
from playwright.sync_api import Error as PlaywrightError, TimeoutError as PlaywrightTimeoutError

from config.settings import get_settings
from utils.logger import get_logger
from utils.helpers import ElementHelper, PageHelper, AssertionHelper, UrlHelper


class BasePage:
    """页面对象基类"""
    
    def __init__(self, page: Page, base_url: Optional[str] = None):
        """
        初始化页面对象
        
        Args:
            page: Playwright Page实例
            base_url: 基础URL
        """
        self.page = page
        self.base_url = base_url or get_settings().get_base_url()
        self.logger = get_logger()
        
        # 初始化辅助类
        self.element = ElementHelper(page)
        self.page_helper = PageHelper(page)
        self.assertion = AssertionHelper(page)
        self.url_helper = UrlHelper()
        
        # 页面URL路径（子类覆盖）
        self.path: Optional[str] = None
        
        # 页面标题（子类覆盖）
        self.title: Optional[str] = None
        
        # 页面元素选择器（子类覆盖）
        self.selectors: Dict[str, str] = {}
    
    def _resolve_selector(self, selector: str) -> str:
        """解析选择器名称为实际选择器字符串"""
        if selector in self.selectors:
            return self.selectors[selector]
        return selector
    
    def _get_full_url(self, path: str) -> str:
        """获取完整URL"""
        if self.url_helper.is_absolute_url(path):
            return path
        return urljoin(self.base_url, path)
    
    def navigate(self, path: Optional[str] = None, **kwargs) -> 'BasePage':
        """
        导航到页面
        
        Args:
            path: 页面路径，如果为None则使用self.path
            **kwargs: 传递给page.goto的参数
            
        Returns:
            self
        """
        path = path or self.path
        if not path:
            raise ValueError("页面路径未指定")
        
        url = self._get_full_url(path)
        self.logger.log_action(f"导航到页面: {url}")
        
        self.page_helper.navigate(url, **kwargs)
        
        return self
    
    def reload(self) -> 'BasePage':
        """刷新页面"""
        self.page_helper.reload_page()
        return self
    
    def go_back(self) -> 'BasePage':
        """返回上一页"""
        self.page_helper.go_back()
        return self
    
    def go_forward(self) -> 'BasePage':
        """前进到下一页"""
        self.page_helper.go_forward()
        return self
    
    def get_url(self) -> str:
        """获取当前URL"""
        return self.page_helper.get_current_url()
    
    def get_title(self) -> str:
        """获取页面标题"""
        return self.page_helper.get_page_title()
    
    def wait_for_load(self, state: str = "networkidle") -> 'BasePage':
        """等待页面加载完成"""
        self.page_helper.wait_for_load_state(state)
        return self
    
    def wait_for_selector(
        self,
        selector: str,
        timeout: Optional[int] = None,
        state: str = "visible"
    ) -> Locator:
        """等待选择器"""
        return self.element.wait_for_selector(selector, timeout, state)
    
    def scroll_to_top(self) -> 'BasePage':
        """滚动到页面顶部"""
        self.page_helper.scroll_to_top()
        return self
    
    def scroll_to_bottom(self) -> 'BasePage':
        """滚动到页面底部"""
        self.page_helper.scroll_to_bottom()
        return self
    
    def scroll_to_element(self, selector: str) -> 'BasePage':
        """滚动到指定元素"""
        self.page_helper.scroll_to_element(selector)
        return self
    
    def take_screenshot(
        self,
        name: str,
        full_page: bool = False
    ) -> str:
        """截取截图"""
        return self.page_helper.take_screenshot(
            f"{name}_{self._get_timestamp()}.png",
            full_page=full_page
        )
    
    def execute_js(self, script: str, *args) -> Any:
        """执行JavaScript"""
        return self.page_helper.execute_javascript(script, *args)
    
    def _get_timestamp(self) -> str:
        """获取时间戳"""
        from datetime import datetime
        return datetime.now().strftime("%Y%m%d_%H%M%S")
    
    def _find(self, selector: str, timeout: Optional[int] = None) -> Locator:
        """查找元素"""
        resolved_selector = self._resolve_selector(selector)
        return self.element.find_element(resolved_selector, timeout)
    
    def _find_all(self, selector: str) -> List[Locator]:
        """查找所有匹配的元素"""
        resolved_selector = self._resolve_selector(selector)
        return self.element.find_elements(resolved_selector)
    
    def _click(self, selector: str, **kwargs) -> 'BasePage':
        """点击元素"""
        resolved_selector = self._resolve_selector(selector)
        self.element.click_element(resolved_selector, **kwargs)
        return self
    
    def _fill(self, selector: str, value: str, **kwargs) -> 'BasePage':
        """填充输入框"""
        resolved_selector = self._resolve_selector(selector)
        self.element.fill_input(resolved_selector, value, **kwargs)
        return self
    
    def _type(self, selector: str, text: str, **kwargs) -> 'BasePage':
        """输入文本"""
        resolved_selector = self._resolve_selector(selector)
        self.element.type_text(resolved_selector, text, **kwargs)
        return self
    
    def _get_text(self, selector: str, **kwargs) -> str:
        """获取元素文本"""
        resolved_selector = self._resolve_selector(selector)
        return self.element.get_element_text(resolved_selector, **kwargs)
    
    def _get_attr(self, selector: str, attribute: str, **kwargs) -> Optional[str]:
        """获取元素属性"""
        resolved_selector = self._resolve_selector(selector)
        return self.element.get_element_attribute(resolved_selector, attribute, **kwargs)
    
    def _is_visible(self, selector: str, **kwargs) -> bool:
        """检查元素是否可见"""
        resolved_selector = self._resolve_selector(selector)
        return self.element.is_element_visible(resolved_selector, **kwargs)
    
    def _is_enabled(self, selector: str, **kwargs) -> bool:
        """检查元素是否可用"""
        resolved_selector = self._resolve_selector(selector)
        return self.element.is_element_enabled(resolved_selector, **kwargs)
    
    # 断言方法
    def assert_title_contains(self, expected: str, message: Optional[str] = None) -> 'BasePage':
        """断言标题包含预期文本"""
        self.assertion.assert_page_title_contains(expected, message)
        return self
    
    def assert_url_contains(self, expected: str, message: Optional[str] = None) -> 'BasePage':
        """断言URL包含预期文本"""
        self.assertion.assert_url_contains(expected, message)
        return self
    
    def assert_url_equals(self, expected: str, message: Optional[str] = None) -> 'BasePage':
        """断言URL等于预期URL"""
        self.assertion.assert_url_equals(expected, message)
        return self
    
    def assert_element_visible(self, selector: str, **kwargs) -> 'BasePage':
        """断言元素可见"""
        resolved_selector = self._resolve_selector(selector)
        self.assertion.assert_element_visible(resolved_selector, **kwargs)
        return self
    
    def assert_element_hidden(self, selector: str, **kwargs) -> 'BasePage':
        """断言元素隐藏"""
        self.assertion.assert_element_hidden(selector, **kwargs)
        return self
    
    def assert_element_text_contains(
        self,
        selector: str,
        expected: str,
        **kwargs
    ) -> 'BasePage':
        """断言元素文本包含预期文本"""
        self.assertion.assert_element_text_contains(selector, expected, **kwargs)
        return self
    
    def assert_element_text_equals(
        self,
        selector: str,
        expected: str,
        **kwargs
    ) -> 'BasePage':
        """断言元素文本等于预期文本"""
        self.assertion.assert_element_text_equals(selector, expected, **kwargs)
        return self
    
    def assert_element_count(
        self,
        selector: str,
        expected: int,
        message: Optional[str] = None
    ) -> 'BasePage':
        """断言元素数量"""
        self.assertion.assert_element_count(selector, expected, message)
        return self
    
    def assert_element_attribute_equals(
        self,
        selector: str,
        attribute: str,
        expected: str,
        **kwargs
    ) -> 'BasePage':
        """断言元素属性等于预期值"""
        self.assertion.assert_element_attribute_equals(
            selector, attribute, expected, **kwargs
        )
        return self
    
    def should_have_url(self, url: str, **kwargs) -> 'BasePage':
        """检查URL"""
        self.assert_url_equals(url, **kwargs)
        return self
    
    def should_have_title(self, title: str, **kwargs) -> 'BasePage':
        """检查标题"""
        self.assert_title_contains(title, **kwargs)
        return self
    
    def should_contain_text(self, text: str, **kwargs) -> 'BasePage':
        """检查页面包含文本"""
        self.page.wait_for_load_state("domcontentloaded")
        content = self.page_helper.get_page_source()
        assert text in content, f"页面不包含文本: {text}"
        return self
    
    def __repr__(self) -> str:
        return f"<{self.__class__.__name__}: {self.path or 'unknown'}>"


class PageRegistry:
    """页面注册表，用于管理页面对象"""
    
    _instance: Optional['PageRegistry'] = None
    _pages: Dict[str, BasePage] = {}
    
    def __new__(cls) -> 'PageRegistry':
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def register(self, name: str, page: BasePage) -> None:
        """注册页面"""
        self._pages[name] = page
    
    def get(self, name: str) -> Optional[BasePage]:
        """获取页面"""
        return self._pages.get(name)
    
    def clear(self) -> None:
        """清空注册表"""
        self._pages.clear()


def get_page_registry() -> PageRegistry:
    """获取页面注册表"""
    return PageRegistry()
