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

use super::{ApiResponse, DashboardState};

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

    // Total stats
    let total_stats = sqlx::query(
        r#"
        SELECT 
            COUNT(*) as total_requests,
            COALESCE(SUM(total_tokens), 0) as total_tokens,
            COALESCE(SUM(cost), 0.0) as total_cost,
            COUNT(DISTINCT client_id) as active_clients
        FROM llm_requests
        "#,
    )
    .fetch_one(pool);

    // Today's stats
    let today = chrono::Utc::now().format("%Y-%m-%d").to_string();
    let today_stats = sqlx::query(
        r#"
        SELECT 
            COUNT(*) as today_requests,
            COALESCE(SUM(total_tokens), 0) as today_tokens,
            COALESCE(SUM(cost), 0.0) as today_cost
        FROM llm_requests
        WHERE strftime('%Y-%m-%d', timestamp) = ?
        "#,
    )
    .bind(today)
    .fetch_one(pool);

    // Error stats
    let error_stats = sqlx::query(
        r#"
        SELECT 
            COUNT(*) as total,
            SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) as errors
        FROM llm_requests
        "#,
    )
    .fetch_one(pool);

    // Average response time
    let avg_response = sqlx::query(
        r#"
        SELECT COALESCE(AVG(duration_ms), 0.0) as avg_duration
        FROM llm_requests
        WHERE status = 'success'
        "#,
    )
    .fetch_one(pool);

    match tokio::join!(total_stats, today_stats, error_stats, avg_response) {
        (Ok(t), Ok(d), Ok(e), Ok(a)) => {
            let total_requests: i64 = t.get("total_requests");
            let total_tokens: i64 = t.get("total_tokens");
            let total_cost: f64 = t.get("total_cost");
            let active_clients: i64 = t.get("active_clients");

            let today_requests: i64 = d.get("today_requests");
            let today_cost: f64 = d.get("today_cost");

            let total_count: i64 = e.get("total");
            let error_count: i64 = e.get("errors");
            let error_rate = if total_count > 0 {
                (error_count as f64 / total_count as f64) * 100.0
            } else {
                0.0
            };

            let avg_response_time: f64 = a.get("avg_duration");

            Json(ApiResponse::success(serde_json::json!({
                "total_requests": total_requests,
                "total_tokens": total_tokens,
                "total_cost": total_cost,
                "active_clients": active_clients,
                "today_requests": today_requests,
                "today_cost": today_cost,
                "error_rate": error_rate,
                "avg_response_time": avg_response_time,
            })))
        }
        _ => Json(ApiResponse::error("Failed to fetch usage statistics".to_string())),
    }
}

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

    let now = chrono::Utc::now();
    let twenty_four_hours_ago = now - chrono::Duration::hours(24);

    let result = sqlx::query(
        r#"
        SELECT 
            strftime('%H:00', timestamp) as hour,
            COUNT(*) as requests,
            SUM(total_tokens) as tokens,
            SUM(cost) as cost
        FROM llm_requests
        WHERE timestamp >= ?
        GROUP BY hour
        ORDER BY hour
        "#,
    )
    .bind(twenty_four_hours_ago)
    .fetch_all(pool)
    .await;

    match result {
        Ok(rows) => {
            let mut series = Vec::new();

            for row in rows {
                let hour: String = row.get("hour");
                let requests: i64 = row.get("requests");
                let tokens: i64 = row.get("tokens");
                let cost: f64 = row.get("cost");

                series.push(serde_json::json!({
                    "time": hour,
                    "requests": requests,
                    "tokens": tokens,
                    "cost": cost,
                }));
            }

            Json(ApiResponse::success(serde_json::json!({
                "series": series,
                "period": "24h"
            })))
        }
        Err(e) => {
            warn!("Failed to fetch time series data: {}", e);
            Json(ApiResponse::error("Failed to fetch time series data".to_string()))
        }
    }
}

pub(super) async fn handle_clients_usage(State(state): State<DashboardState>) -> Json<ApiResponse<serde_json::Value>> {
    // Query database for client usage statistics
    let pool = &state.app_state.db_pool;

    let result = sqlx::query(
        r#"
        SELECT 
            client_id,
            COUNT(*) as requests,
            SUM(total_tokens) as tokens,
            SUM(cost) as cost,
            MAX(timestamp) as last_request
        FROM llm_requests
        GROUP BY client_id
        ORDER BY requests DESC
        "#,
    )
    .fetch_all(pool)
    .await;

    match result {
        Ok(rows) => {
            let mut client_usage = Vec::new();

            for row in rows {
                let client_id: String = row.get("client_id");
                let requests: i64 = row.get("requests");
                let tokens: i64 = row.get("tokens");
                let cost: f64 = row.get("cost");
                let last_request: Option<chrono::DateTime<chrono::Utc>> = row.get("last_request");

                client_usage.push(serde_json::json!({
                    "client_id": client_id,
                    "client_name": client_id,
                    "requests": requests,
                    "tokens": tokens,
                    "cost": cost,
                    "last_request": last_request,
                }));
            }

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

pub(super) async fn handle_providers_usage(
    State(state): State<DashboardState>,
) -> Json<ApiResponse<serde_json::Value>> {
    // Query database for provider usage statistics
    let pool = &state.app_state.db_pool;

    let result = sqlx::query(
        r#"
        SELECT 
            provider,
            COUNT(*) as requests,
            COALESCE(SUM(total_tokens), 0) as tokens,
            COALESCE(SUM(cost), 0.0) as cost
        FROM llm_requests
        GROUP BY provider
        ORDER BY requests DESC
        "#,
    )
    .fetch_all(pool)
    .await;

    match result {
        Ok(rows) => {
            let mut provider_usage = Vec::new();

            for row in rows {
                let provider: String = row.get("provider");
                let requests: i64 = row.get("requests");
                let tokens: i64 = row.get("tokens");
                let cost: f64 = row.get("cost");

                provider_usage.push(serde_json::json!({
                    "provider": provider,
                    "requests": requests,
                    "tokens": tokens,
                    "cost": cost,
                }));
            }

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

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

    let result = sqlx::query(
        r#"
        SELECT 
            strftime('%Y-%m-%d', timestamp) as date,
            client_id,
            provider,
            model,
            COUNT(*) as requests,
            SUM(total_tokens) as tokens,
            SUM(cost) as cost
        FROM llm_requests
        GROUP BY date, client_id, provider, model
        ORDER BY date DESC
        LIMIT 100
        "#,
    )
    .fetch_all(pool)
    .await;

    match result {
        Ok(rows) => {
            let usage: Vec<serde_json::Value> = rows
                .into_iter()
                .map(|row| {
                    serde_json::json!({
                        "date": row.get::<String, _>("date"),
                        "client": row.get::<String, _>("client_id"),
                        "provider": row.get::<String, _>("provider"),
                        "model": row.get::<String, _>("model"),
                        "requests": row.get::<i64, _>("requests"),
                        "tokens": row.get::<i64, _>("tokens"),
                        "cost": row.get::<f64, _>("cost"),
                    })
                })
                .collect();

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

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

    // Model breakdown
    let models =
        sqlx::query("SELECT model as label, COUNT(*) as value FROM llm_requests GROUP BY model ORDER BY value DESC")
            .fetch_all(pool);

    // Client breakdown
    let clients = sqlx::query(
        "SELECT client_id as label, COUNT(*) as value FROM llm_requests GROUP BY client_id ORDER BY value DESC",
    )
    .fetch_all(pool);

    match tokio::join!(models, clients) {
        (Ok(m_rows), Ok(c_rows)) => {
            let model_breakdown: Vec<serde_json::Value> = m_rows
                .into_iter()
                .map(|r| serde_json::json!({ "label": r.get::<String, _>("label"), "value": r.get::<i64, _>("value") }))
                .collect();

            let client_breakdown: Vec<serde_json::Value> = c_rows
                .into_iter()
                .map(|r| serde_json::json!({ "label": r.get::<String, _>("label"), "value": r.get::<i64, _>("value") }))
                .collect();

            Json(ApiResponse::success(serde_json::json!({
                "models": model_breakdown,
                "clients": client_breakdown
            })))
        }
        _ => Json(ApiResponse::error("Failed to fetch analytics breakdown".to_string())),
    }
}
