"""CLI 入口 - 命令行运行测试"""

import argparse
import sys
from pathlib import Path
from typing import Optional, List

from ..product import __version__
from ..core.browser_manager import BrowserManager
from ..core.config_loader import ConfigLoader
from ..action.key_retrieval import KeyRetrieval
from ..cases.case_collector import CaseCollector
from ..cases.case_executor import CaseExecutor
from ..cases.read.cell_handler import CellHandler
from ..plugins.plugin_loader import PluginLoader
from ..reference import GSTORE, GSDSTORE, INFO
from ..utils.log.html_report import HtmlReporter


class KDTestRunner:
    """KDTest Playwright 测试运行器"""

    def __init__(self, config_path: Optional[str] = None):
        """初始化运行器

        Args:
            config_path: 配置文件路径
        """
        self._config_loader: Optional[ConfigLoader] = None
        self._browser_manager: Optional[BrowserManager] = None
        self._key_retrieval: Optional[KeyRetrieval] = None
        self._plugin_loader: Optional[PluginLoader] = None
        self._case_collector: Optional[CaseCollector] = None
        self._case_executor: Optional[CaseExecutor] = None
        self._reporter: Optional[HtmlReporter] = None

        if config_path:
            self.load_config(config_path)

    def load_config(self, config_path: str) -> None:
        """加载配置文件

        Args:
            config_path: 配置文件路径
        """
        self._config_loader = ConfigLoader(config_path)
        INFO(f"配置已加载: {config_path}")

    def setup(self) -> None:
        """初始化测试环境"""
        if not self._config_loader:
            raise RuntimeError("请先加载配置文件")

        config = self._config_loader.config

        # 初始化浏览器管理器
        self._browser_manager = BrowserManager()

        # 启动浏览器
        page = self._browser_manager.launch(
            browser_type=self._config_loader.browser,
            headless=self._config_loader.headless,
            slow_mo=self._config_loader.slow_mo,
            trace=self._config_loader.trace,
            video=self._config_loader.video,
            timeout=self._config_loader.timeout,
        )

        # 初始化关键字分发器
        self._key_retrieval = KeyRetrieval(page)

        # 初始化插件加载器
        self._plugin_loader = PluginLoader(page)
        self._plugin_loader.load_builtin_plugins()

        # 合并插件关键字和元素数据
        self._key_retrieval.register_plugin_keywords(
            self._plugin_loader.get_all_keywords()
        )
        self._key_retrieval.set_element_data(
            self._plugin_loader.get_all_element_data()
        )

        # 初始化单元格处理器
        cell_handler = CellHandler(
            self._config_loader.self_defined_parameters
        )

        # 初始化用例执行器
        self._case_executor = CaseExecutor(
            key_retrieval=self._key_retrieval,
            cell_handler=cell_handler,
            retry_count=self._config_loader.retry_count if self._config_loader.retry_switch else 0,
            screenshot_on_fail=True,
        )

        # 初始化用例收集器
        self._case_collector = CaseCollector(config)

        # 初始化报告生成器
        self._reporter = HtmlReporter()

        # 导航到起始 URL
        if self._config_loader.url:
            page.goto(self._config_loader.url)

        INFO("测试环境初始化完成")

    def run(
        self,
        include_sheets: List[str] = None,
        exclude_sheets: List[str] = None,
        case_ids: List[str] = None,
        case_pattern: str = None,
    ) -> dict:
        """运行测试

        Args:
            include_sheets: 只执行这些 Sheet
            exclude_sheets: 排除这些 Sheet
            case_ids: 只执行这些用例 ID
            case_pattern: 用例名称匹配模式

        Returns:
            dict: 执行摘要
        """
        # 收集用例
        all_cases = self._case_collector.collect()

        # 过滤用例
        cases = self._case_collector.filter_cases(
            include_sheets=include_sheets,
            exclude_sheets=exclude_sheets,
            include_ids=case_ids,
            name_pattern=case_pattern,
        )

        INFO(f"过滤后用例数: {len(cases)}")

        # 执行用例
        results = self._case_executor.execute_cases(cases)

        # 生成报告
        if self._reporter:
            report_path = self._reporter.generate(results)
            INFO(f"测试报告: {report_path}")

        return self._case_executor.summary

    def teardown(self, save_trace: str = None) -> None:
        """清理测试环境

        Args:
            save_trace: trace 文件保存路径
        """
        # 卸载插件
        if self._plugin_loader:
            self._plugin_loader.unload_all()

        # 关闭浏览器
        if self._browser_manager:
            trace_path = save_trace or (
                'result/trace/trace.zip' if self._config_loader and self._config_loader.trace else None
            )
            self._browser_manager.close(save_trace=trace_path)

        INFO("测试环境已清理")

    def __enter__(self) -> 'KDTestRunner':
        self.setup()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        self.teardown()


def parse_args() -> argparse.Namespace:
    """解析命令行参数"""
    parser = argparse.ArgumentParser(
        prog='kdtest-pw',
        description='KDTest Playwright - 关键字驱动测试框架',
    )

    parser.add_argument(
        '-v', '--version',
        action='version',
        version=f'kdtest-pw {__version__}'
    )

    parser.add_argument(
        '-c', '--config',
        type=str,
        default='data/parameters.json',
        help='配置文件路径 (默认: data/parameters.json)'
    )

    parser.add_argument(
        '-s', '--sheets',
        type=str,
        nargs='+',
        help='只执行指定的 Sheet'
    )

    parser.add_argument(
        '-x', '--exclude',
        type=str,
        nargs='+',
        help='排除指定的 Sheet'
    )

    parser.add_argument(
        '-i', '--ids',
        type=str,
        nargs='+',
        help='只执行指定的用例 ID'
    )

    parser.add_argument(
        '-p', '--pattern',
        type=str,
        help='用例名称匹配模式 (支持通配符)'
    )

    parser.add_argument(
        '--browser',
        type=str,
        choices=['chromium', 'firefox', 'webkit'],
        help='覆盖配置中的浏览器类型'
    )

    parser.add_argument(
        '--headless',
        action='store_true',
        help='无头模式运行'
    )

    parser.add_argument(
        '--trace',
        action='store_true',
        help='开启 trace 录制'
    )

    parser.add_argument(
        '--video',
        action='store_true',
        help='开启视频录制'
    )

    parser.add_argument(
        '--slow-mo',
        type=int,
        help='操作延迟 (毫秒)'
    )

    return parser.parse_args()


def main() -> int:
    """主入口函数"""
    args = parse_args()

    # 检查配置文件
    config_path = Path(args.config)
    if not config_path.exists():
        print(f"错误: 配置文件不存在: {config_path}")
        return 1

    runner = KDTestRunner(str(config_path))

    # 覆盖配置
    if args.browser:
        runner._config_loader.set('browser', args.browser)
    if args.headless:
        runner._config_loader.set('headless', True)
    if args.trace:
        runner._config_loader.set('trace', True)
    if args.video:
        runner._config_loader.set('video', True)
    if args.slow_mo:
        runner._config_loader.set('slowMo', args.slow_mo)

    try:
        runner.setup()
        summary = runner.run(
            include_sheets=args.sheets,
            exclude_sheets=args.exclude,
            case_ids=args.ids,
            case_pattern=args.pattern,
        )

        # 输出摘要
        print("\n" + "=" * 50)
        print("测试执行摘要")
        print("=" * 50)
        print(f"总用例数: {summary['total']}")
        print(f"通过: {summary['passed']}")
        print(f"失败: {summary['failed']}")
        print(f"跳过: {summary['skipped']}")
        print(f"通过率: {summary['pass_rate']:.1f}%")
        print(f"执行时间: {summary['duration']:.2f}s")
        print("=" * 50)

        return 0 if summary['failed'] == 0 else 1

    except KeyboardInterrupt:
        print("\n测试被中断")
        return 130
    except Exception as e:
        print(f"执行错误: {e}")
        import traceback
        traceback.print_exc()
        return 1
    finally:
        runner.teardown()


if __name__ == '__main__':
    sys.exit(main())
