use axum::{
    extract::{Path, State},
    response::Json,
};
use chrono;
use serde::Deserialize;
use serde_json;
use sqlx::Row;
use tracing::warn;
use uuid;

use super::{ApiResponse, DashboardState};

#[derive(Deserialize)]
pub(super) struct CreateClientRequest {
    pub(super) name: String,
    pub(super) client_id: Option<String>,
}

pub(super) async fn handle_get_clients(State(state): State<DashboardState>) -> Json<ApiResponse<serde_json::Value>> {
    let pool = &state.app_state.db_pool;

    let result = sqlx::query(
        r#"
        SELECT 
            client_id as id,
            name,
            created_at,
            total_requests,
            total_tokens,
            total_cost,
            is_active
        FROM clients
        ORDER BY created_at DESC
        "#,
    )
    .fetch_all(pool)
    .await;

    match result {
        Ok(rows) => {
            let clients: Vec<serde_json::Value> = rows
                .into_iter()
                .map(|row| {
                    serde_json::json!({
                        "id": row.get::<String, _>("id"),
                        "name": row.get::<Option<String>, _>("name").unwrap_or_else(|| "Unnamed".to_string()),
                        "created_at": row.get::<chrono::DateTime<chrono::Utc>, _>("created_at"),
                        "requests_count": row.get::<i64, _>("total_requests"),
                        "total_tokens": row.get::<i64, _>("total_tokens"),
                        "total_cost": row.get::<f64, _>("total_cost"),
                        "status": if row.get::<bool, _>("is_active") { "active" } else { "inactive" },
                    })
                })
                .collect();

            Json(ApiResponse::success(serde_json::json!(clients)))
        }
        Err(e) => {
            warn!("Failed to fetch clients: {}", e);
            Json(ApiResponse::error("Failed to fetch clients".to_string()))
        }
    }
}

pub(super) async fn handle_create_client(
    State(state): State<DashboardState>,
    Json(payload): Json<CreateClientRequest>,
) -> Json<ApiResponse<serde_json::Value>> {
    let pool = &state.app_state.db_pool;

    let client_id = payload
        .client_id
        .unwrap_or_else(|| format!("client-{}", &uuid::Uuid::new_v4().to_string()[..8]));

    let result = sqlx::query(
        r#"
        INSERT INTO clients (client_id, name, is_active)
        VALUES (?, ?, TRUE)
        RETURNING *
        "#,
    )
    .bind(&client_id)
    .bind(&payload.name)
    .fetch_one(pool)
    .await;

    match result {
        Ok(row) => Json(ApiResponse::success(serde_json::json!({
            "id": row.get::<String, _>("client_id"),
            "name": row.get::<Option<String>, _>("name"),
            "created_at": row.get::<chrono::DateTime<chrono::Utc>, _>("created_at"),
            "status": "active",
        }))),
        Err(e) => {
            warn!("Failed to create client: {}", e);
            Json(ApiResponse::error(format!("Failed to create client: {}", e)))
        }
    }
}

pub(super) async fn handle_get_client(
    State(state): State<DashboardState>,
    Path(id): Path<String>,
) -> Json<ApiResponse<serde_json::Value>> {
    let pool = &state.app_state.db_pool;

    let result = sqlx::query(
        r#"
        SELECT 
            c.client_id as id,
            c.name,
            c.is_active,
            c.created_at,
            COALESCE(c.total_tokens, 0) as total_tokens,
            COALESCE(c.total_cost, 0.0) as total_cost,
            COUNT(r.id) as total_requests,
            MAX(r.timestamp) as last_request
        FROM clients c
        LEFT JOIN llm_requests r ON c.client_id = r.client_id
        WHERE c.client_id = ?
        GROUP BY c.client_id
        "#,
    )
    .bind(&id)
    .fetch_optional(pool)
    .await;

    match result {
        Ok(Some(row)) => Json(ApiResponse::success(serde_json::json!({
            "id": row.get::<String, _>("id"),
            "name": row.get::<Option<String>, _>("name").unwrap_or_else(|| "Unnamed".to_string()),
            "is_active": row.get::<bool, _>("is_active"),
            "created_at": row.get::<chrono::DateTime<chrono::Utc>, _>("created_at"),
            "total_tokens": row.get::<i64, _>("total_tokens"),
            "total_cost": row.get::<f64, _>("total_cost"),
            "total_requests": row.get::<i64, _>("total_requests"),
            "last_request": row.get::<Option<chrono::DateTime<chrono::Utc>>, _>("last_request"),
            "status": if row.get::<bool, _>("is_active") { "active" } else { "inactive" },
        }))),
        Ok(None) => Json(ApiResponse::error(format!("Client '{}' not found", id))),
        Err(e) => {
            warn!("Failed to fetch client: {}", e);
            Json(ApiResponse::error(format!("Failed to fetch client: {}", e)))
        }
    }
}

pub(super) async fn handle_delete_client(
    State(state): State<DashboardState>,
    Path(id): Path<String>,
) -> Json<ApiResponse<serde_json::Value>> {
    let pool = &state.app_state.db_pool;

    // Don't allow deleting the default client
    if id == "default" {
        return Json(ApiResponse::error("Cannot delete default client".to_string()));
    }

    let result = sqlx::query("DELETE FROM clients WHERE client_id = ?")
        .bind(id)
        .execute(pool)
        .await;

    match result {
        Ok(_) => Json(ApiResponse::success(serde_json::json!({ "message": "Client deleted" }))),
        Err(e) => Json(ApiResponse::error(format!("Failed to delete client: {}", e))),
    }
}

pub(super) async fn handle_client_usage(
    State(state): State<DashboardState>,
    Path(id): Path<String>,
) -> Json<ApiResponse<serde_json::Value>> {
    let pool = &state.app_state.db_pool;

    // Get per-model breakdown for this client
    let result = sqlx::query(
        r#"
        SELECT 
            model,
            provider,
            COUNT(*) as request_count,
            SUM(prompt_tokens) as prompt_tokens,
            SUM(completion_tokens) as completion_tokens,
            SUM(total_tokens) as total_tokens,
            SUM(cost) as total_cost,
            AVG(duration_ms) as avg_duration_ms
        FROM llm_requests
        WHERE client_id = ?
        GROUP BY model, provider
        ORDER BY total_cost DESC
        "#,
    )
    .bind(&id)
    .fetch_all(pool)
    .await;

    match result {
        Ok(rows) => {
            let breakdown: Vec<serde_json::Value> = rows
                .into_iter()
                .map(|row| {
                    serde_json::json!({
                        "model": row.get::<String, _>("model"),
                        "provider": row.get::<String, _>("provider"),
                        "request_count": row.get::<i64, _>("request_count"),
                        "prompt_tokens": row.get::<i64, _>("prompt_tokens"),
                        "completion_tokens": row.get::<i64, _>("completion_tokens"),
                        "total_tokens": row.get::<i64, _>("total_tokens"),
                        "total_cost": row.get::<f64, _>("total_cost"),
                        "avg_duration_ms": row.get::<f64, _>("avg_duration_ms"),
                    })
                })
                .collect();

            Json(ApiResponse::success(serde_json::json!({
                "client_id": id,
                "breakdown": breakdown,
            })))
        }
        Err(e) => {
            warn!("Failed to fetch client usage: {}", e);
            Json(ApiResponse::error(format!("Failed to fetch client usage: {}", e)))
        }
    }
}
