"""
服务基类模块

定义所有业务服务需要继承的基类，提供统一的 run 方法接口。
"""

from abc import ABC, abstractmethod
from contextlib import asynccontextmanager
from typing import Any

class BaseService(ABC):
    """
    业务服务基类

    所有业务服务都需要继承此类，实现 run 方法。
    执行器会实例化此类并调用 _run_with_context 方法。
    """

    def __init__(self):
        """初始化服务"""
        self.browser = None

    @asynccontextmanager
    async def use_browser_manager(self, manager_class=None, **kwargs):
        """
        使用 BrowserManager 的上下文管理器（自动管理实例属性）
        
        自动将 BrowserManager 实例赋值给 self.browser，
        在异常处理时可以直接使用 self._build_error_data() 而无需传参。
        
        Args:
            manager_class: BrowserManager 类，不传则默认使用 BrowserCDPManager
            **kwargs: 传递给 BrowserManager 的参数（如 record_video、record_trace 等）
            
        Yields:
            BrowserManager: BrowserManager 实例
            
        Examples:
            # 方式1：使用默认的 BrowserCDPManager（推荐）
            async with self.use_browser_manager(record_video=True, record_trace=True) as browser:
                page = await browser.new_page()
                await page.navigate("https://example.com")
            
            # 方式2：显式指定 BrowserManager 类型
            from executor.playwright import BrowserManager
            async with self.use_browser_manager(BrowserManager, record_video=True) as browser:
                page = await browser.new_page()
        """
        # 默认使用 BrowserCDPManager
        if manager_class is None:
            from executor.playwright import BrowserCDPManager
            manager_class = BrowserCDPManager
        
        async with manager_class(**kwargs) as browser:
            self.browser = browser
            yield browser

    def _set_job_context(self, job_id: int, task_batch_id: int):
        """
        设置日志上下文

        统一设置所有需要的日志上下文，包括：
        - app 自己的日志上下文
        - SnailJob 的日志上下文（如果可用）

        Args:
            job_id: 任务ID
            task_batch_id: 任务批次ID
        """
        # 设置日志上下文
        try:
            from executor.logger import _job_context_var
            _job_context_var.set((job_id, task_batch_id))
        except ImportError:
            # 如果包不可用，跳过设置
            pass

    async def _run_with_context(self, job_id: int, task_batch_id: int, extra_params: dict = None) -> Any:
        """
        带日志上下文的运行方法

        这个方法会自动设置日志上下文，然后调用子类的 run 方法。
        """
        # 设置日志上下文
        self._set_job_context(job_id, task_batch_id)

        # 调用子类的 run 方法
        return await self.run(job_id, task_batch_id, extra_params)

    @abstractmethod
    async def run(self, job_id: int, task_batch_id: int, extra_params: dict = None) -> Any:
        """
        执行业务逻辑的抽象方法

        Args:
            job_id: 任务ID
            task_batch_id: 任务批次ID
            extra_params: 从任务参数传递的额外参数

        Returns:
            Any: 执行结果，可以是任意类型

        注意：
            子类可以重写 _set_job_context 方法来自定义日志上下文设置。
        """
        pass
