"""登录子 driver：登录态检测 / 等待登录 / 二维码定位。

从 xdotool_driver.py 单类中拆出的登录域方法，继承 BaseDriver 复用公共能力。
find_wechat_window 归属 WindowDriver，本 driver 通过构造函数注入
window_driver 引用调用。

方法清单：
- detect_login_state() -> str                            （与原 XdotoolDriver 一致）
- wait_for_login(timeout_sec=120.0) -> bool              （新增，轮询 detect_login_state）
- get_qr_rect() -> Optional[tuple[int, int, int, int]]   （新增占位，未实现返回 None）
"""

from __future__ import annotations

import asyncio
import logging
import time
from typing import Optional, TYPE_CHECKING

from woc_bridge.models import BridgeError, LoginState
from woc_bridge.ui.drivers.base import BaseDriver

if TYPE_CHECKING:
    from woc_bridge.ui.drivers.window import WindowDriver

logger = logging.getLogger("woc-bridge")


class LoginDriver(BaseDriver):
    """登录子 driver。"""

    def __init__(
        self,
        display: str,
        backend=None,
        window_driver: Optional["WindowDriver"] = None,
    ) -> None:
        super().__init__(display, backend)
        # 注入兄弟 driver：detect_login_state / is_wechat_running 依赖
        # WindowDriver.find_wechat_window
        self._window_driver = window_driver

    # ------------------------------------------------------------------
    # 命令执行包装（保持与原 XdotoolDriver._run 语义一致）
    # ------------------------------------------------------------------
    async def _run(
        self,
        args: list[str],
        *,
        input_bytes: Optional[bytes] = None,
    ) -> tuple[int, bytes, bytes]:
        """执行一条命令并返回 (returncode, stdout, stderr)。

        委托 BaseDriver._run_managed，TimeoutError 转 BridgeError(code=SEND_FAILED)。
        """
        try:
            return await self._run_managed(args)
        except asyncio.TimeoutError as exc:
            logger.error("[ui] command timeout: %s", args[0] if args else "?")
            raise BridgeError(
                code="SEND_FAILED",
                message=f"命令超时: {args[0] if args else '?'}",
            ) from exc

    async def is_wechat_running(self) -> bool:
        """判断微信进程是否运行。

        用 pgrep -x 精确匹配进程名 wechat（避免 -f 子串匹配误中
        bridge 自身命令行里的 /config/.config/xwechat 路径）。
        若 pgrep 不可用，回落到 xdotool search（窗口存在即视为进程运行）。
        """
        # 用 -x 精确进程名匹配，避免 -f 子串误中 bridge 自身
        for name in ("wechat", "WeChat"):
            returncode, stdout, _ = await self._run(["pgrep", "-x", name])
            if returncode == 0 and stdout.decode(errors="ignore").strip():
                return True
        # 回落：窗口存在即视为运行（委托 WindowDriver）
        if self._window_driver is not None:
            window_id = await self._window_driver.find_wechat_window()
            return window_id is not None
        return False

    # ------------------------------------------------------------------
    # 登录态检测
    # ------------------------------------------------------------------
    async def detect_login_state(self) -> str:
        """检测登录态（启发式）。

        MVP 阶段判定逻辑：
        - 微信进程未运行 → not_running
        - 进程运行但窗口未找到 → not_logged_in
        - 窗口存在 → logged_in

        Returns:
            LoginState 枚举值（字符串）
        """
        running = await self.is_wechat_running()
        if not running:
            return LoginState.NOT_RUNNING.value
        if self._window_driver is None:
            return LoginState.NOT_LOGGED_IN.value
        window_id = await self._window_driver.find_wechat_window()
        if window_id is None:
            return LoginState.NOT_LOGGED_IN.value
        # MVP：窗口存在即视为已登录
        return LoginState.LOGGED_IN.value

    async def wait_for_login(self, timeout_sec: float = 120.0) -> bool:
        """轮询等待微信登录完成。

        新增方法：原 XdotoolDriver 无 wait_for_login。本方法周期性调用
        detect_login_state，检测到 logged_in 即返回 True，超时返回 False。

        Args:
            timeout_sec: 最大等待秒数，默认 120

        Returns:
            True 表示已登录；False 表示超时仍未登录
        """
        deadline = time.monotonic() + timeout_sec
        while time.monotonic() < deadline:
            try:
                state = await self._step(
                    self.detect_login_state(),
                    "检测登录态",
                    deadline,
                )
            except asyncio.TimeoutError:
                logger.warning("[login] detect_login_state 步骤超时，继续轮询")
                await asyncio.sleep(1.0)
                continue
            if state == LoginState.LOGGED_IN.value:
                logger.info("[login] 检测到已登录")
                return True
            # 未登录，间隔 2s 后重试（避免高频 pgrep/xdotool 抢占 X 资源）
            await asyncio.sleep(2.0)
        logger.warning("[login] 等待登录超时 (%.0fs)", timeout_sec)
        return False

    async def get_qr_rect(self) -> Optional[tuple[int, int, int, int]]:
        """定位登录二维码在屏幕上的矩形区域 (x, y, w, h)。

        新增占位方法：原 XdotoolDriver 无 get_qr_rect。当前版本未实现图像
        识别定位，返回 None。后续可结合 screenshot() + 图像匹配或固定几何
        估算（微信 4.x 登录二维码通常居中）实现。

        Returns:
            (x, y, width, height) 元组，未实现时返回 None
        """
        # TODO: 结合 screenshot() 与图像匹配定位二维码区域
        logger.warning("[login] get_qr_rect 未实现，返回 None")
        return None
