//! 设备处理器

use axum::{
    extract::{Path, State},
    http::StatusCode,
    response::IntoResponse,
    Json,
};
use std::sync::Arc;

use crate::models::{ApiResponse, DeviceRegisterRequest, DeviceResponse};
use crate::services::{device::DeviceRepository, AppState};
use super::{api_error, AuthUser, OptionalAuthUser};

/// 注册设备
pub async fn register_device(
    State(state): State<Arc<AppState>>,
    OptionalAuthUser(auth_user): OptionalAuthUser,
    Json(req): Json<DeviceRegisterRequest>,
) -> impl IntoResponse {
    let repo = DeviceRepository::new(&state.db);

    match repo.register(&req.device_id, &req.name, &req.os_type, &req.os_version).await {
        Ok(device) => {
            // 如果用户已登录，绑定设备到用户
            if let Some(ref user) = auth_user {
                tracing::info!("Binding device {} to user {}", req.device_id, user.user_id);
                match repo.bind_to_user(&req.device_id, &user.user_id).await {
                    Ok(_) => tracing::info!("Device {} bound to user {} successfully", req.device_id, user.user_id),
                    Err(e) => tracing::error!("Failed to bind device: {}", e),
                }
            } else {
                tracing::info!("Device {} registered without user (no auth token)", req.device_id);
            }

            // 重新获取设备信息（包含绑定用户）
            let updated_device = repo.find_by_device_id(&req.device_id).await
                .ok()
                .flatten()
                .unwrap_or(device);

            let response: DeviceResponse = updated_device.into();
            (StatusCode::CREATED, Json(ApiResponse::ok(response))).into_response()
        }
        Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    }
}

/// 获取当前用户的设备列表
pub async fn list_devices(
    State(state): State<Arc<AppState>>,
    user: AuthUser,
) -> impl IntoResponse {
    let repo = DeviceRepository::new(&state.db);

    match repo.find_by_user(&user.user_id).await {
        Ok(devices) => {
            // 使用实时 WebSocket 连接状态覆盖数据库中的状态
            let mut response: Vec<DeviceResponse> = Vec::with_capacity(devices.len());
            for device in devices {
                let mut device_resp: DeviceResponse = device.into();
                // 检查实际的 WebSocket 连接状态
                device_resp.is_online = state.is_device_online(&device_resp.device_id).await;
                response.push(device_resp);
            }
            (StatusCode::OK, Json(ApiResponse::ok(response))).into_response()
        }
        Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    }
}

/// 获取单个设备
pub async fn get_device(
    State(state): State<Arc<AppState>>,
    Path(device_id): Path<String>,
    user: AuthUser,
) -> impl IntoResponse {
    let repo = DeviceRepository::new(&state.db);

    match repo.find_by_device_id(&device_id).await {
        Ok(Some(device)) => {
            // 验证设备属于当前用户
            if device.user_id.as_ref() != Some(&user.user_id) && user.role != "admin" {
                return api_error(StatusCode::FORBIDDEN, "无权访问此设备");
            }

            let response: DeviceResponse = device.into();
            (StatusCode::OK, Json(ApiResponse::ok(response))).into_response()
        }
        Ok(None) => api_error(StatusCode::NOT_FOUND, "设备不存在"),
        Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    }
}

/// 移除设备
pub async fn remove_device(
    State(state): State<Arc<AppState>>,
    Path(device_id): Path<String>,
    user: AuthUser,
) -> impl IntoResponse {
    let repo = DeviceRepository::new(&state.db);

    // 验证设备属于当前用户
    match repo.find_by_device_id(&device_id).await {
        Ok(Some(device)) => {
            if device.user_id.as_ref() != Some(&user.user_id) && user.role != "admin" {
                return api_error(StatusCode::FORBIDDEN, "无权操作此设备");
            }
        }
        Ok(None) => return api_error(StatusCode::NOT_FOUND, "设备不存在"),
        Err(e) => return api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    }

    // 解绑设备
    match repo.unbind(&device_id).await {
        Ok(_) => (StatusCode::OK, Json(ApiResponse::ok("设备已移除"))).into_response(),
        Err(e) => api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    }
}

/// 强制设备下线
pub async fn force_offline(
    State(state): State<Arc<AppState>>,
    Path(device_id): Path<String>,
    user: AuthUser,
) -> impl IntoResponse {
    let repo = DeviceRepository::new(&state.db);

    // 验证设备属于当前用户
    match repo.find_by_device_id(&device_id).await {
        Ok(Some(device)) => {
            if device.user_id.as_ref() != Some(&user.user_id) && user.role != "admin" {
                return api_error(StatusCode::FORBIDDEN, "无权操作此设备");
            }
        }
        Ok(None) => return api_error(StatusCode::NOT_FOUND, "设备不存在"),
        Err(e) => return api_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
    }

    // 发送下线命令
    let message = serde_json::json!({
        "type": "force_offline",
        "device_id": device_id,
    });

    if state.send_to_device(&device_id, &message.to_string()).await {
        // 更新数据库状态
        let _ = repo.set_online(&device_id, false).await;
        (StatusCode::OK, Json(ApiResponse::ok("设备已下线"))).into_response()
    } else {
        // 设备可能已经离线
        let _ = repo.set_online(&device_id, false).await;
        (StatusCode::OK, Json(ApiResponse::ok("设备已下线"))).into_response()
    }
}
