use std::sync::Arc;

use axum::{
    extract::State,
    http::StatusCode,
    routing::post,
    Json, Router,
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::db::{licenses, player_sessions};
use crate::models::error::{ApiError, ApiResult};
use crate::AppState;

pub fn router() -> Router<Arc<AppState>> {
    Router::new()
        .route("/checkin", post(checkin))
        .route("/player-event", post(player_event))
}

/// Plugin check-in payload (from uMod plugin on server start).
#[derive(Debug, Deserialize)]
struct CheckinRequest {
    license_key: String,
    server_name: String,
    server_description: Option<String>,
    server_url: Option<String>,
    max_players: Option<i32>,
    world_size: Option<i32>,
    seed: Option<i32>,
    plugin_version: Option<String>,
    server_version: Option<String>,
}

/// POST /api/plugin/checkin
/// Plugin sends this on server startup to register with the control plane.
async fn checkin(
    State(state): State<Arc<AppState>>,
    Json(req): Json<CheckinRequest>,
) -> ApiResult<Json<serde_json::Value>> {
    // Validate license key
    let license = licenses::get_license_by_key(&state.db, &req.license_key)
        .await
        .map_err(|_| ApiError::Unauthorized)?
        .ok_or(ApiError::Unauthorized)?;

    // TODO: Update server_connections.plugin_last_seen
    // TODO: Update server_config with server_name, world_size, seed, etc.

    tracing::info!(
        "Plugin check-in: license {} ({})",
        license.id,
        req.server_name
    );

    Ok(Json(serde_json::json!({
        "status": "ok",
        "license_id": license.id,
        "message": "Check-in successful"
    })))
}

/// Player event payload from uMod plugin.
#[derive(Debug, Deserialize)]
struct PlayerEventRequest {
    license_key: String,
    event: String, // "player_connected" or "player_disconnected"
    player_id: String, // SteamID
    player_name: String,
    timestamp: Option<i64>, // Unix timestamp
}

/// Response for player event tracking.
#[derive(Debug, Serialize)]
struct PlayerEventResponse {
    status: String,
    session_id: Option<Uuid>,
}

/// POST /api/plugin/player-event
/// Plugin sends this on player join/leave to track sessions for retention analytics.
async fn player_event(
    State(state): State<Arc<AppState>>,
    Json(req): Json<PlayerEventRequest>,
) -> Result<Json<PlayerEventResponse>, (StatusCode, Json<serde_json::Value>)> {
    // Validate license key
    let license = licenses::get_license_by_key(&state.db, &req.license_key)
        .await
        .map_err(|e| {
            tracing::error!("License lookup failed: {}", e);
            (
                StatusCode::UNAUTHORIZED,
                Json(serde_json::json!({
                    "error": "Invalid license key"
                })),
            )
        })?
        .ok_or_else(|| {
            (
                StatusCode::UNAUTHORIZED,
                Json(serde_json::json!({
                    "error": "Invalid license key"
                })),
            )
        })?;

    match req.event.as_str() {
        "player_connected" => {
            // Track join event
            let session_id = player_sessions::track_player_join(
                &state.db,
                license.id,
                &req.player_id,
                &req.player_name,
            )
            .await
            .map_err(|e| {
                tracing::error!("Failed to track player join: {}", e);
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    Json(serde_json::json!({
                        "error": "Failed to track player join"
                    })),
                )
            })?;

            tracing::debug!(
                "Player joined: {} ({}) on license {}",
                req.player_name,
                req.player_id,
                license.id
            );

            Ok(Json(PlayerEventResponse {
                status: "ok".to_string(),
                session_id: Some(session_id),
            }))
        }
        "player_disconnected" => {
            // Track leave event
            player_sessions::track_player_leave(&state.db, license.id, &req.player_id)
                .await
                .map_err(|e| {
                    tracing::error!("Failed to track player leave: {}", e);
                    (
                        StatusCode::INTERNAL_SERVER_ERROR,
                        Json(serde_json::json!({
                            "error": "Failed to track player leave"
                        })),
                    )
                })?;

            tracing::debug!(
                "Player left: {} ({}) on license {}",
                req.player_name,
                req.player_id,
                license.id
            );

            Ok(Json(PlayerEventResponse {
                status: "ok".to_string(),
                session_id: None,
            }))
        }
        _ => Err((
            StatusCode::BAD_REQUEST,
            Json(serde_json::json!({
                "error": format!("Unknown event type: {}", req.event)
            })),
        )),
    }
}
