"""微信登录状态守卫：后台检测登录状态，提供同步属性与事件通知。

独立后台协程定期调用 detect_login_state()，维护 asyncio.Event 标记当前
登录状态。状态变化时记录日志（避免每轮都输出噪音）。

设计目标：
- 后台任务（如 FriendRequestWatcher）在执行 UI 操作前检查 is_logged_in，
  未登录时跳过操作，等待登录恢复后自然从上次位置继续处理。
- 游标 / 状态不推进，登录后 DB 中积累的数据自然被重新读取，不丢数据。
- 不替代路由层的登录守卫（routes/send.py 等已有 detect_login_state 前置检查），
  仅用于后台长轮询任务的登录前提保护。
"""

from __future__ import annotations

import asyncio
import logging
from typing import Optional

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


class LoginGuard:
    """微信登录状态守卫。

    Attributes:
        _xdotool: XdotoolDriver 实例（调用 detect_login_state）
        _check_interval: 检测间隔秒数（默认 5.0s）
        _logged_in_event: asyncio.Event，set 表示当前已登录
        _watcher: 后台检测协程
        _current_state: 最近一次检测到的登录状态字符串
        _last_logged_in: 上次是否登录（用于检测状态变化）
    """

    def __init__(
        self,
        xdotool_driver,
        check_interval: float = 5.0,
    ) -> None:
        self._xdotool = xdotool_driver
        self._check_interval = check_interval
        self._logged_in_event: asyncio.Event = asyncio.Event()
        self._watcher: Optional[asyncio.Task] = None
        self._current_state: str = "unknown"
        self._last_logged_in: bool = False

    @property
    def is_logged_in(self) -> bool:
        """当前是否已登录（同步属性，取最近一次检测结果）。"""
        return self._logged_in_event.is_set()

    @property
    def current_state(self) -> str:
        """最近一次检测到的登录状态字符串。"""
        return self._current_state

    async def wait_for_login(self, timeout: Optional[float] = None) -> bool:
        """等待登录状态变为已登录。

        Args:
            timeout: 超时秒数，None 表示无限等待

        Returns:
            True 表示已登录；False 表示超时仍未登录
        """
        if self._logged_in_event.is_set():
            return True
        try:
            await asyncio.wait_for(
                self._logged_in_event.wait(), timeout=timeout
            )
            return True
        except asyncio.TimeoutError:
            return False

    async def start(self) -> None:
        """启动后台检测协程。"""
        if self._watcher is None or self._watcher.done():
            self._watcher = asyncio.create_task(self._check_loop())
            logger.info("LoginGuard 已启动 (check_interval=%.1fs)", self._check_interval)

    async def stop(self) -> None:
        """停止后台检测协程。"""
        if self._watcher is not None and not self._watcher.done():
            self._watcher.cancel()
            try:
                await self._watcher
            except asyncio.CancelledError:
                pass
        self._watcher = None
        logger.info("LoginGuard 已停止")

    async def _check_loop(self) -> None:
        """后台检测循环：定期调用 detect_login_state 并维护事件状态。"""
        while True:
            try:
                state = await self._xdotool.detect_login_state()
                logged_in = (state == "logged_in")

                # 仅在状态变化时记录日志，避免每轮噪音
                if logged_in != self._last_logged_in:
                    if logged_in:
                        logger.info(
                            "[LoginGuard] 微信已登录 (state=%s)，恢复后台任务",
                            state,
                        )
                    else:
                        logger.warning(
                            "[LoginGuard] 微信未登录 (state=%s)，暂停需要登录的后台任务",
                            state,
                        )
                    self._last_logged_in = logged_in

                if logged_in:
                    self._logged_in_event.set()
                else:
                    self._logged_in_event.clear()

                self._current_state = state
            except asyncio.CancelledError:
                raise
            except Exception as e:
                logger.warning("[LoginGuard] 登录状态检测异常: %s", e)
                self._logged_in_event.clear()
                self._current_state = "error"

            await asyncio.sleep(self._check_interval)
