"""
连接管理模块

负责：
- 从 JSON 缓存加载 UserData
- 创建 DeviceManager
- 设备发现和模糊匹配
- 连接生命周期管理
"""

import json
import os
from contextlib import asynccontextmanager
from pathlib import Path
from typing import Any

from roborock.data import UserData
from roborock.devices.device_manager import create_device_manager, UserParams
from roborock.devices.file_cache import FileCache


class AuthExpiredError(Exception):
    """认证已过期，需要重新运行 setup_auth"""

    def __init__(self):
        super().__init__("认证已过期，请重新运行 `roborock-mcp auth`")


class NoDeviceError(Exception):
    """未发现设备"""

    def __init__(self):
        super().__init__("未发现任何设备，请确认设备已绑定到账户")


class AmbiguousDeviceError(Exception):
    """设备名称匹配到多个设备"""

    def __init__(self, name: str, matches: list[str]):
        self.name = name
        self.matches = matches
        super().__init__(
            f"设备名称 '{name}' 匹配到多个设备: {matches}，请使用更精确的名称"
        )


class DeviceNotFoundError(Exception):
    """设备名称未匹配到任何设备"""

    def __init__(self, name: str, available: list[str]):
        self.name = name
        self.available = available
        super().__init__(
            f"未找到设备 '{name}'，可用设备: {available}"
        )


class ConnectionManager:
    """连接管理器"""

    def __init__(self, auth_cache_path: Path, device_cache_path: Path):
        self._auth_cache_path = auth_cache_path
        self._device_cache_path = device_cache_path
        self._manager: Any = None  # DeviceManager
        self._cache: FileCache | None = None
        self._user_params: UserParams | None = None

    @classmethod
    def from_env(cls) -> "ConnectionManager":
        """从环境变量创建连接管理器"""
        auth_cache = Path(
            os.environ.get(
                "ROBOROCK_AUTH_CACHE",
                Path.home() / ".cache" / "roborock-mcp" / "user_data.json"
            )
        )
        device_cache = Path(
            os.environ.get(
                "ROBOROCK_DEVICE_CACHE",
                Path.home() / ".cache" / "roborock-mcp" / "device_cache.pkl"
            )
        )
        return cls(auth_cache, device_cache)

    async def ensure_connected(self) -> None:
        """确保已连接，如果未连接则建立连接"""
        if self._manager is not None:
            return

        # 1. 从 JSON 文件加载 UserData
        if not self._auth_cache_path.exists():
            raise AuthExpiredError()

        try:
            with open(self._auth_cache_path) as f:
                data = json.load(f)
            email = data["email"]
            user_data = UserData.from_dict(data["user_data"])
        except (json.JSONDecodeError, KeyError) as e:
            raise AuthExpiredError() from e

        # 2. 构建 UserParams（不传 base_url，让 SDK 自动发现）
        self._user_params = UserParams(
            username=email,
            user_data=user_data,
        )

        # 3. 创建缓存目录
        self._device_cache_path.parent.mkdir(parents=True, exist_ok=True)

        # 4. 创建 FileCache
        self._cache = FileCache(self._device_cache_path)

        # 5. 创建 DeviceManager（内部已调用 discover_devices）
        self._manager = await create_device_manager(
            self._user_params,
            cache=self._cache
        )

        # 6. 检查设备列表
        devices = await self._manager.get_devices()
        if not devices:
            raise NoDeviceError()

    async def list_devices(self) -> list[Any]:
        """返回所有已发现设备"""
        if self._manager is None:
            await self.ensure_connected()
        return await self._manager.get_devices()

    async def get_device(self, device_name: str | None = None) -> Any:
        """
        获取指定设备

        Args:
            device_name: 设备名称（模糊匹配），为 None 时自动选择单设备

        Returns:
            RoborockDevice

        Raises:
            NoDeviceError: 无设备
            AmbiguousDeviceError: 名称匹配到多个设备
            DeviceNotFoundError: 名称未匹配到任何设备
        """
        devices = await self.list_devices()

        # 单设备且未指定名称时，自动选择
        if device_name is None:
            if len(devices) == 1:
                return devices[0]
            else:
                available = [d.name for d in devices]
                raise ValueError(
                    f"发现 {len(devices)} 个设备，请指定 device_name。可用设备: {available}"
                )

        # 模糊匹配
        matches = []
        for device in devices:
            if device_name.lower() in device.name.lower():
                matches.append(device)

        if len(matches) == 0:
            available = [d.name for d in devices]
            raise DeviceNotFoundError(device_name, available)

        if len(matches) > 1:
            raise AmbiguousDeviceError(
                device_name,
                [d.name for d in matches]
            )

        return matches[0]

    async def close(self) -> None:
        """关闭连接，先 flush 缓存再关闭"""
        if self._cache is not None:
            await self._cache.flush()
        if self._manager is not None:
            await self._manager.close()


@asynccontextmanager
async def lifespan(server: Any):
    """MCP server lifespan 管理"""
    conn = ConnectionManager.from_env()
    await conn.ensure_connected()
    yield {"conn": conn}
    await conn.close()
