//! 设备指令下发 HTTP API。
//!
//! 提供 HTTP 端点供后台系统调用，通过设备连接池向在线设备发送指令。

use axum::extract::{Path, State};
use axum::Json;
use serde::Deserialize;
use serde_json::{json, Value};

use super::connection::ConnectionPool;
use super::protocol::DeviceCommand;
use crate::error::AppError;
use crate::middleware::auth::{self, CurrentUser};

/// HTTP 请求体：包含要下发的指令内容。
#[derive(Debug, Deserialize)]
pub struct CommandRequest {
    pub act: String,
    #[serde(default)]
    pub msg_id: u32,
    pub sub_device_id: Option<u8>,
    #[serde(flatten)]
    pub params: Option<Value>,
}

/// 应用共享状态（与 main.rs 联动）。
#[allow(dead_code)]
#[derive(Clone)]
pub struct AppState {
    pub device_pool: ConnectionPool,
    pub redis: redis::aio::ConnectionManager,
    pub mysql: sqlx::MySqlPool,
}

/// POST /api/devices/:dev_id/command
///
/// 向指定设备下发实时指令。设备不在线时返回错误。
/// 需要 `device:operate` 权限。
pub async fn send_command(
    user: CurrentUser,
    State(state): State<AppState>,
    Path(dev_id): Path<String>,
    Json(req): Json<CommandRequest>,
) -> Result<Json<Value>, AppError> {
    auth::check_permission(&user, "device:operate")?;

    if !state.device_pool.is_online(&dev_id).await {
        return Ok(Json(json!({ "suc": 0, "err": "设备不在线" })));
    }

    let cmd = DeviceCommand {
        act: req.act,
        msg_id: req.msg_id,
        dev_id: Some(dev_id.clone()),
        sub_device_id: req.sub_device_id,
        params: req.params,
    };

    let json = cmd.to_json();
    match state.device_pool.send_command(&dev_id, &json).await {
        Ok(()) => {
            tracing::info!("[command] 已下发 dev_id={} act={}", dev_id, cmd.act);
            Ok(Json(json!({ "suc": 1 })))
        }
        Err(e) => Ok(Json(json!({ "suc": 0, "err": e }))),
    }
}

/// GET /api/devices/stats — 在线设备统计。
/// 需要 `device:view` 权限。
pub async fn device_stats(
    user: CurrentUser,
    State(state): State<AppState>,
) -> Result<Json<Value>, AppError> {
    auth::check_permission(&user, "device:view")?;
    let count = state.device_pool.online_count().await;
    Ok(Json(json!({ "online_count": count })))
}
