use axum::{
    extract::{Path, State},
    response::Json,
};
use serde::Deserialize;
use serde_json;
use sqlx::Row;
use std::collections::HashMap;

use super::{ApiResponse, DashboardState};

#[derive(Deserialize)]
pub(super) struct UpdateModelRequest {
    pub(super) enabled: bool,
    pub(super) prompt_cost: Option<f64>,
    pub(super) completion_cost: Option<f64>,
    pub(super) mapping: Option<String>,
}

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

    // Load overrides from database
    let db_models_result =
        sqlx::query("SELECT id, enabled, prompt_cost_per_m, completion_cost_per_m, mapping FROM model_configs")
            .fetch_all(pool)
            .await;

    let mut db_models = HashMap::new();
    if let Ok(rows) = db_models_result {
        for row in rows {
            let id: String = row.get("id");
            db_models.insert(id, row);
        }
    }

    let mut models_json = Vec::new();

    for (p_id, p_info) in &registry.providers {
        for (m_id, m_meta) in &p_info.models {
            let mut enabled = true;
            let mut prompt_cost = m_meta.cost.as_ref().map(|c| c.input).unwrap_or(0.0);
            let mut completion_cost = m_meta.cost.as_ref().map(|c| c.output).unwrap_or(0.0);
            let mut mapping = None::<String>;

            if let Some(row) = db_models.get(m_id) {
                enabled = row.get("enabled");
                if let Some(p) = row.get::<Option<f64>, _>("prompt_cost_per_m") {
                    prompt_cost = p;
                }
                if let Some(c) = row.get::<Option<f64>, _>("completion_cost_per_m") {
                    completion_cost = c;
                }
                mapping = row.get("mapping");
            }

            models_json.push(serde_json::json!({
                "id": m_id,
                "provider": p_id,
                "name": m_meta.name,
                "enabled": enabled,
                "prompt_cost": prompt_cost,
                "completion_cost": completion_cost,
                "mapping": mapping,
                "context_limit": m_meta.limit.as_ref().map(|l| l.context).unwrap_or(0),
            }));
        }
    }

    Json(ApiResponse::success(serde_json::json!(models_json)))
}

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

    // Find provider_id for this model in registry
    let provider_id = state
        .app_state
        .model_registry
        .providers
        .iter()
        .find(|(_, p)| p.models.contains_key(&id))
        .map(|(id, _)| id.clone())
        .unwrap_or_else(|| "unknown".to_string());

    let result = sqlx::query(
        r#"
        INSERT INTO model_configs (id, provider_id, enabled, prompt_cost_per_m, completion_cost_per_m, mapping)
        VALUES (?, ?, ?, ?, ?, ?)
        ON CONFLICT(id) DO UPDATE SET
            enabled = excluded.enabled,
            prompt_cost_per_m = excluded.prompt_cost_per_m,
            completion_cost_per_m = excluded.completion_cost_per_m,
            mapping = excluded.mapping,
            updated_at = CURRENT_TIMESTAMP
        "#,
    )
    .bind(&id)
    .bind(provider_id)
    .bind(payload.enabled)
    .bind(payload.prompt_cost)
    .bind(payload.completion_cost)
    .bind(payload.mapping)
    .execute(pool)
    .await;

    match result {
        Ok(_) => Json(ApiResponse::success(serde_json::json!({ "message": "Model updated" }))),
        Err(e) => Json(ApiResponse::error(format!("Failed to update model: {}", e))),
    }
}
