"""
MCP 服务器

包含 10 个只读查询工具：
0. get_devices - 列出所有设备
1. get_status - 设备实时状态
2. get_dnd - 勿扰模式设置
3. get_clean_summary - 清洁历史统计
4. get_sound_volume - 音量设置
5. get_rooms - 房间列表
6. get_maps - 地图概览
7. get_map_content - 地图内容
8. get_consumables - 耗材使用状态
9. get_home - 家庭完整布局
"""

from typing import Any

from mcp.server.fastmcp import FastMCP

from .connection import ConnectionManager, lifespan

# 创建 FastMCP 实例
mcp = FastMCP(
    "roborock-mcp",
    lifespan=lifespan,
)


def get_conn() -> ConnectionManager:
    """从 MCP context 获取 ConnectionManager"""
    return mcp.get_context().request_context.lifespan_context["conn"]


# ============================================================================
# 工具定义
# ============================================================================

@mcp.tool()
async def get_devices() -> dict[str, Any]:
    """
    列出所有已发现的设备

    返回设备的名称、型号、DUID 和连接状态。
    """
    conn = get_conn()
    devices = await conn.list_devices()

    result = {
        "count": len(devices),
        "devices": []
    }

    for device in devices:
        info = {
            "name": device.name,
            "duid": device.duid,
            "model": device.product.model if device.product else None,
            "firmware": device.device_info.fv if device.device_info else None,
        }
        result["devices"].append(info)

    return result


@mcp.tool()
async def get_status(device_name: str | None = None) -> dict[str, Any]:
    """
    获取设备实时状态

    包括电量、状态、吸力、拖布湿度、基座信息、错误码等。

    Args:
        device_name: 设备名称（可选，单设备时自动选择）

    Returns:
        设备状态信息，包含 state（charging/cleaning/idle/paused/error 等）、
        battery（电量百分比）、fan_speed（吸力档位）、water_mode（拖布湿度）等
    """
    conn = get_conn()
    device = await conn.get_device(device_name)

    if not device.v1_properties:
        return {"error": "设备不支持 V1 协议"}

    props = device.v1_properties
    await props.status.refresh()
    status = props.status

    return {
        "device_name": device.name,
        "state": status.state.name if status.state else None,
        "state_name": status.state_name,
        "battery": status.battery,
        "error_code": status.error_code.name if status.error_code else None,
        "error_name": status.error_code_name,
        "fan_speed": status.fan_speed_name,
        "water_mode": status.water_mode_name,
        "mop_route": status.mop_route_name,
        "clean_time_seconds": status.clean_time,
        "clean_area_m2": status.square_meter_clean_area,
        "clean_percent": status.clean_percent,
        "dock_type": status.dock_type.name if status.dock_type else None,
        "dock_error": status.dock_error_status.name if status.dock_error_status else None,
        "charge_status": status.charge_status,
        "dnd_enabled": bool(status.dnd_enabled),
        "map_present": bool(status.map_present),
    }


@mcp.tool()
async def get_dnd(device_name: str | None = None) -> dict[str, Any]:
    """
    获取勿扰模式设置

    包括是否开启、开始和结束时间。

    Args:
        device_name: 设备名称（可选，单设备时自动选择）
    """
    conn = get_conn()
    device = await conn.get_device(device_name)

    if not device.v1_properties:
        return {"error": "设备不支持 V1 协议"}

    props = device.v1_properties
    await props.dnd.refresh()
    dnd = props.dnd

    return {
        "device_name": device.name,
        "enabled": dnd.is_on,
        "start_time": f"{dnd.start_hour:02d}:{dnd.start_minute:02d}" if dnd.is_on else None,
        "end_time": f"{dnd.end_hour:02d}:{dnd.end_minute:02d}" if dnd.is_on else None,
    }


@mcp.tool()
async def get_clean_summary(device_name: str | None = None) -> dict[str, Any]:
    """
    获取清洁历史统计

    包括总清洁时长、面积、次数，以及最近一次清洁记录。

    Args:
        device_name: 设备名称（可选，单设备时自动选择）
    """
    conn = get_conn()
    device = await conn.get_device(device_name)

    if not device.v1_properties:
        return {"error": "设备不支持 V1 协议"}

    props = device.v1_properties
    await props.clean_summary.refresh()
    summary = props.clean_summary

    result = {
        "device_name": device.name,
        "total_time_hours": summary.clean_time / 3600 if summary.clean_time else 0,
        "total_area_m2": summary.clean_area / 1_000_000 if summary.clean_area else 0,
        "clean_count": summary.clean_count,
        "record_count": len(summary.records) if summary.records else 0,
    }

    # 最近一次清洁记录
    if summary.last_clean_record:
        record = summary.last_clean_record
        result["last_clean"] = {
            "begin": record.begin_datetime.isoformat() if record.begin_datetime else None,
            "end": record.end_datetime.isoformat() if record.end_datetime else None,
            "duration_seconds": record.duration,
            "area_m2": record.area / 1_000_000 if record.area else 0,
            "start_type": record.start_type.name if record.start_type else None,
            "avoid_count": record.avoid_count,
        }

    return result


@mcp.tool()
async def get_sound_volume(device_name: str | None = None) -> dict[str, Any]:
    """
    获取音量设置

    Args:
        device_name: 设备名称（可选，单设备时自动选择）
    """
    conn = get_conn()
    device = await conn.get_device(device_name)

    if not device.v1_properties:
        return {"error": "设备不支持 V1 协议"}

    props = device.v1_properties
    await props.sound_volume.refresh()
    volume = props.sound_volume

    return {
        "device_name": device.name,
        "volume": volume.volume,
    }


@mcp.tool()
async def get_rooms(device_name: str | None = None) -> dict[str, Any]:
    """
    获取房间列表

    返回房间 ID（segment_id）与名称的映射。

    Args:
        device_name: 设备名称（可选，单设备时自动选择）
    """
    conn = get_conn()
    device = await conn.get_device(device_name)

    if not device.v1_properties:
        return {"error": "设备不支持 V1 协议"}

    props = device.v1_properties
    await props.rooms.refresh()
    rooms = props.rooms

    room_list = []
    for room in rooms.rooms or []:
        room_list.append({
            "segment_id": room.segment_id,
            "name": room.raw_name or "<未命名>",
        })

    return {
        "device_name": device.name,
        "room_count": len(room_list),
        "rooms": room_list,
    }


@mcp.tool()
async def get_maps(device_name: str | None = None) -> dict[str, Any]:
    """
    获取地图概览

    轻量查询，返回地图列表、当前地图 ID 和房间数。
    如需完整的房间布局，请使用 get_home。

    Args:
        device_name: 设备名称（可选，单设备时自动选择）
    """
    conn = get_conn()
    device = await conn.get_device(device_name)

    if not device.v1_properties:
        return {"error": "设备不支持 V1 协议"}

    props = device.v1_properties
    await props.maps.refresh()
    maps = props.maps

    map_list = []
    for map_info in maps.map_info or []:
        map_list.append({
            "map_flag": map_info.map_flag,
            "name": map_info.name or "<未命名>",
            "room_count": len(map_info.rooms) if map_info.rooms else 0,
            "is_current": map_info.map_flag == maps.current_map,
        })

    return {
        "device_name": device.name,
        "current_map": maps.current_map,
        "map_count": len(map_list),
        "maps": map_list,
    }


@mcp.tool()
async def get_map_content(device_name: str | None = None) -> dict[str, Any]:
    """
    获取地图内容

    返回地图元数据（图片大小、机器人位置、充电座位置）。
    不返回原始图片字节。

    Args:
        device_name: 设备名称（可选，单设备时自动选择）
    """
    conn = get_conn()
    device = await conn.get_device(device_name)

    if not device.v1_properties:
        return {"error": "设备不支持 V1 协议"}

    props = device.v1_properties
    await props.map_content.refresh()
    content = props.map_content

    result = {
        "device_name": device.name,
        "image_size_bytes": len(content.image_content) if content.image_content else 0,
        "has_map_data": content.map_data is not None,
    }

    if content.map_data:
        vacuum_pos = content.map_data.vacuum_position
        charger_pos = content.map_data.charger
        result["vacuum_position"] = {
            "x": vacuum_pos.x if vacuum_pos else None,
            "y": vacuum_pos.y if vacuum_pos else None,
        }
        result["charger_position"] = {
            "x": charger_pos.x if charger_pos else None,
            "y": charger_pos.y if charger_pos else None,
        }

    return result


@mcp.tool()
async def get_consumables(device_name: str | None = None) -> dict[str, Any]:
    """
    获取耗材使用状态

    包括主刷、边刷、滤网、传感器的工作时长（小时）。

    Args:
        device_name: 设备名称（可选，单设备时自动选择）
    """
    conn = get_conn()
    device = await conn.get_device(device_name)

    if not device.v1_properties:
        return {"error": "设备不支持 V1 协议"}

    props = device.v1_properties
    await props.consumables.refresh()
    consumables = props.consumables

    # 工作时长从分钟转换为小时
    HOURS = 60

    return {
        "device_name": device.name,
        "main_brush_hours": consumables.main_brush_work_time / HOURS if consumables.main_brush_work_time else 0,
        "side_brush_hours": consumables.side_brush_work_time / HOURS if consumables.side_brush_work_time else 0,
        "filter_hours": consumables.filter_work_time / HOURS if consumables.filter_work_time else 0,
        "sensor_hours": consumables.sensor_dirty_time / HOURS if consumables.sensor_dirty_time else 0,
    }


@mcp.tool()
async def get_home(device_name: str | None = None) -> dict[str, Any]:
    """
    获取家庭完整布局

    重量查询，返回所有地图的完整房间布局。
    SDK 内部已处理设备忙时的降级逻辑。

    Args:
        device_name: 设备名称（可选，单设备时自动选择）
    """
    conn = get_conn()
    device = await conn.get_device(device_name)

    if not device.v1_properties:
        return {"error": "设备不支持 V1 协议"}

    props = device.v1_properties

    # 直接调用 refresh()，SDK 内部已处理设备忙的降级逻辑
    await props.home.refresh()
    home = props.home

    maps_info = {}
    for map_flag, map_info in (home.home_map_info or {}).items():
        rooms = []
        for room in map_info.rooms or []:
            rooms.append({
                "segment_id": room.segment_id,
                "name": room.raw_name or "<未命名>",
            })
        maps_info[str(map_flag)] = {
            "name": map_info.name or "<未命名>",
            "rooms": rooms,
        }

    # 当前地图的房间
    current_rooms = []
    for room in home.current_rooms or []:
        current_rooms.append({
            "segment_id": room.segment_id,
            "name": room.raw_name or "<未命名>",
        })

    return {
        "device_name": device.name,
        "map_count": len(maps_info),
        "maps": maps_info,
        "current_rooms": current_rooms,
    }
