#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：device_sim.py
模块描述：设备模拟模块 API 路由

作者：czj
创建日期：2026-07-29
最后修改：2026-07-29
"""

import logging
from datetime import datetime
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_db
from app.schemas.device_sim import (
    EnvConfigCreate, EnvConfigUpdate, EnvConfigResponse, EnvConfigListResponse,
    SimulatorCreate, SimulatorUpdate, SimulatorResponse, SimulatorListResponse,
    ReportLogResponse, ReportLogListResponse,
    ManualReportRequest, TestConnectionResponse,
)
from app.services.device_sim_service import DeviceSimService

logger = logging.getLogger(__name__)

# 创建路由实例
router = APIRouter()


def get_device_sim_service(db: AsyncSession = Depends(get_db)) -> DeviceSimService:
    """
    获取设备模拟服务实例（依赖注入）

    Args:
        db: 数据库会话

    Returns:
        DeviceSimService: 设备模拟服务实例
    """
    return DeviceSimService(db)


# ==================== 环境配置 API ====================


@router.get("/env-configs", response_model=EnvConfigListResponse)
async def list_env_configs(
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(100, ge=1, le=500, description="返回记录数上限"),
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    获取环境配置列表

    支持分页查询，按创建时间倒序返回。
    """
    try:
        items, total = await service.list_env_configs(skip=skip, limit=limit)
        return EnvConfigListResponse(
            items=[EnvConfigResponse.model_validate(item) for item in items],
            total=total
        )
    except Exception as e:
        logger.error(f"获取环境配置列表失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取环境配置列表失败: {str(e)}")


@router.post("/env-configs", response_model=EnvConfigResponse, status_code=201)
async def create_env_config(
    data: EnvConfigCreate,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    新增环境配置

    创建 MQTT Broker 连接配置。
    """
    try:
        config = await service.create_env_config(data)
        return EnvConfigResponse.model_validate(config)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"创建环境配置失败: {e}")
        raise HTTPException(status_code=500, detail=f"创建环境配置失败: {str(e)}")


@router.get("/env-configs/{config_id}", response_model=EnvConfigResponse)
async def get_env_config(
    config_id: str,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    获取环境配置详情
    """
    config = await service.get_env_config(config_id)
    if not config:
        raise HTTPException(status_code=404, detail="环境配置不存在")
    return EnvConfigResponse.model_validate(config)


@router.put("/env-configs/{config_id}", response_model=EnvConfigResponse)
async def update_env_config(
    config_id: str,
    data: EnvConfigUpdate,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    更新环境配置
    """
    config = await service.update_env_config(config_id, data)
    if not config:
        raise HTTPException(status_code=404, detail="环境配置不存在")
    return EnvConfigResponse.model_validate(config)


@router.delete("/env-configs/{config_id}")
async def delete_env_config(
    config_id: str,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    删除环境配置

    有关联模拟设备时禁止删除。
    """
    try:
        success = await service.delete_env_config(config_id)
        if not success:
            raise HTTPException(status_code=404, detail="环境配置不存在")
        return {"message": "环境配置已删除", "id": config_id}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"删除环境配置失败: {e}")
        raise HTTPException(status_code=500, detail=f"删除环境配置失败: {str(e)}")


@router.post("/env-configs/{config_id}/test", response_model=TestConnectionResponse)
async def test_env_connection(
    config_id: str,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    测试 MQTT 连接

    测试指定环境配置的 MQTT Broker 连接是否正常。
    """
    try:
        result = await service.test_env_connection(config_id)
        return result
    except Exception as e:
        logger.error(f"测试连接失败: {e}")
        raise HTTPException(status_code=500, detail=f"测试连接失败: {str(e)}")


# ==================== 模拟设备 API ====================


@router.get("/devices", response_model=SimulatorListResponse)
async def list_simulators(
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(100, ge=1, le=500, description="返回记录数上限"),
    device_type: Optional[str] = Query(None, description="设备类型筛选"),
    env_config_id: Optional[str] = Query(None, description="环境配置筛选"),
    status: Optional[str] = Query(None, description="状态筛选"),
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    获取模拟设备列表

    支持按设备类型、环境配置、状态筛选。
    """
    try:
        items, total = await service.list_simulators(
            skip=skip, limit=limit,
            device_type=device_type,
            env_config_id=env_config_id,
            status=status,
        )
        return SimulatorListResponse(
            items=[SimulatorResponse.model_validate(item) for item in items],
            total=total
        )
    except Exception as e:
        logger.error(f"获取模拟设备列表失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取模拟设备列表失败: {str(e)}")


@router.post("/devices", response_model=SimulatorResponse, status_code=201)
async def create_simulator(
    data: SimulatorCreate,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    创建模拟设备

    支持 5 种设备类型：door(门口屏)、paperless(无纸化)、central(中控)、client(集控客户端)
    """
    try:
        device = await service.create_simulator(data)
        return SimulatorResponse.model_validate(device)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"创建模拟设备失败: {e}")
        raise HTTPException(status_code=500, detail=f"创建模拟设备失败: {str(e)}")


@router.get("/devices/{device_id}", response_model=SimulatorResponse)
async def get_simulator(
    device_id: str,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    获取模拟设备详情
    """
    device = await service.get_simulator(device_id)
    if not device:
        raise HTTPException(status_code=404, detail="模拟设备不存在")
    return SimulatorResponse.model_validate(device)


@router.put("/devices/{device_id}", response_model=SimulatorResponse)
async def update_simulator(
    device_id: str,
    data: SimulatorUpdate,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    更新模拟设备配置
    """
    device = await service.update_simulator(device_id, data)
    if not device:
        raise HTTPException(status_code=404, detail="模拟设备不存在")
    return SimulatorResponse.model_validate(device)


@router.delete("/devices/{device_id}")
async def delete_simulator(
    device_id: str,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    删除模拟设备

    会先停止设备，再删除关联上报记录。
    """
    try:
        success = await service.delete_simulator(device_id)
        if not success:
            raise HTTPException(status_code=404, detail="模拟设备不存在")
        return {"message": "模拟设备已删除", "id": device_id}
    except Exception as e:
        logger.error(f"删除模拟设备失败: {e}")
        raise HTTPException(status_code=500, detail=f"删除模拟设备失败: {str(e)}")


@router.post("/devices/{device_id}/start")
async def start_simulator(
    device_id: str,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    启动模拟设备

    连接 MQTT Broker，发送注册消息，开始定时上报。
    """
    try:
        success = await service.start_simulator(device_id)
        return {"message": "模拟设备已启动", "id": device_id, "status": "running"}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except ConnectionError as e:
        raise HTTPException(status_code=502, detail=str(e))
    except Exception as e:
        logger.error(f"启动模拟设备失败: {e}")
        raise HTTPException(status_code=500, detail=f"启动模拟设备失败: {str(e)}")


@router.post("/devices/{device_id}/stop")
async def stop_simulator(
    device_id: str,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    停止模拟设备

    发送离线状态消息，停止定时上报。
    """
    try:
        success = await service.stop_simulator(device_id)
        return {"message": "模拟设备已停止", "id": device_id, "status": "stopped"}
    except Exception as e:
        logger.error(f"停止模拟设备失败: {e}")
        raise HTTPException(status_code=500, detail=f"停止模拟设备失败: {str(e)}")


@router.post("/devices/{device_id}/report")
async def manual_report(
    device_id: str,
    data: ManualReportRequest,
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    手动触发上报

    指定主题和数据内容，手动触发设备上报。
    """
    try:
        success = await service.manual_report(device_id, data.topic, data.payload)
        return {"message": "上报成功", "success": success}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"手动上报失败: {e}")
        raise HTTPException(status_code=500, detail=f"手动上报失败: {str(e)}")


# ==================== 上报记录 API ====================


@router.get("/report-logs", response_model=ReportLogListResponse)
async def list_report_logs(
    device_id: Optional[str] = Query(None, description="设备 ID 筛选"),
    direction: Optional[str] = Query(None, description="方向筛选：publish(上报)/subscribe(接收)"),
    skip: int = Query(0, ge=0, description="跳过的记录数"),
    limit: int = Query(100, ge=1, le=500, description="返回记录数上限"),
    start_time: Optional[datetime] = Query(None, description="开始时间"),
    end_time: Optional[datetime] = Query(None, description="结束时间"),
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    获取上报记录列表

    支持按设备、方向、时间范围筛选和分页。
    """
    try:
        items, total = await service.list_report_logs(
            device_id=device_id,
            direction=direction,
            skip=skip,
            limit=limit,
            start_time=start_time,
            end_time=end_time,
        )
        return ReportLogListResponse(
            items=[ReportLogResponse.model_validate(item) for item in items],
            total=total
        )
    except Exception as e:
        logger.error(f"获取上报记录失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取上报记录失败: {str(e)}")


@router.delete("/report-logs/cleanup")
async def cleanup_report_logs(
    days: int = Query(7, ge=1, le=30, description="保留天数"),
    service: DeviceSimService = Depends(get_device_sim_service)
):
    """
    清理过期上报记录

    默认保留 7 天，可配置保留天数（1-30天）。
    """
    try:
        count = await service.cleanup_report_logs(days=days)
        return {"message": f"已清理 {count} 条过期记录", "cleaned_count": count}
    except Exception as e:
        logger.error(f"清理上报记录失败: {e}")
        raise HTTPException(status_code=500, detail=f"清理上报记录失败: {str(e)}")