use axum::{extract::State, response::Json};
use bcrypt;
use serde::Deserialize;
use sqlx::Row;
use tracing::warn;

use super::{ApiResponse, DashboardState};

// Authentication handlers
#[derive(Deserialize)]
pub(super) struct LoginRequest {
    pub(super) username: String,
    pub(super) password: String,
}

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

    let user_result =
        sqlx::query("SELECT username, password_hash, role, must_change_password FROM users WHERE username = ?")
            .bind(&payload.username)
            .fetch_optional(pool)
            .await;

    match user_result {
        Ok(Some(row)) => {
            let hash = row.get::<String, _>("password_hash");
            if bcrypt::verify(&payload.password, &hash).unwrap_or(false) {
                let username = row.get::<String, _>("username");
                let role = row.get::<String, _>("role");
                let must_change_password = row.get::<bool, _>("must_change_password");
                let token = state
                    .session_manager
                    .create_session(username.clone(), role.clone())
                    .await;
                Json(ApiResponse::success(serde_json::json!({
                    "token": token,
                    "must_change_password": must_change_password,
                    "user": {
                        "username": username,
                        "name": "Administrator",
                        "role": role
                    }
                })))
            } else {
                Json(ApiResponse::error("Invalid username or password".to_string()))
            }
        }
        Ok(None) => Json(ApiResponse::error("Invalid username or password".to_string())),
        Err(e) => {
            warn!("Database error during login: {}", e);
            Json(ApiResponse::error("Login failed due to system error".to_string()))
        }
    }
}

pub(super) async fn handle_auth_status(
    State(state): State<DashboardState>,
    headers: axum::http::HeaderMap,
) -> Json<ApiResponse<serde_json::Value>> {
    let token = headers
        .get("Authorization")
        .and_then(|v| v.to_str().ok())
        .and_then(|v| v.strip_prefix("Bearer "));

    if let Some(token) = token
        && let Some(session) = state.session_manager.validate_session(token).await
    {
        return Json(ApiResponse::success(serde_json::json!({
            "authenticated": true,
            "user": {
                "username": session.username,
                "name": "Administrator",
                "role": session.role
            }
        })));
    }

    Json(ApiResponse::error("Not authenticated".to_string()))
}

#[derive(Deserialize)]
pub(super) struct ChangePasswordRequest {
    pub(super) current_password: String,
    pub(super) new_password: String,
}

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

    // For now, always change 'admin' user
    let user_result = sqlx::query("SELECT password_hash FROM users WHERE username = 'admin'")
        .fetch_one(pool)
        .await;

    match user_result {
        Ok(row) => {
            let hash = row.get::<String, _>("password_hash");
            if bcrypt::verify(&payload.current_password, &hash).unwrap_or(false) {
                let new_hash = match bcrypt::hash(&payload.new_password, 12) {
                    Ok(h) => h,
                    Err(_) => return Json(ApiResponse::error("Failed to hash new password".to_string())),
                };

                let update_result = sqlx::query(
                    "UPDATE users SET password_hash = ?, must_change_password = FALSE WHERE username = 'admin'",
                )
                .bind(new_hash)
                .execute(pool)
                .await;

                match update_result {
                    Ok(_) => Json(ApiResponse::success(
                        serde_json::json!({ "message": "Password updated successfully" }),
                    )),
                    Err(e) => Json(ApiResponse::error(format!("Failed to update database: {}", e))),
                }
            } else {
                Json(ApiResponse::error("Current password incorrect".to_string()))
            }
        }
        Err(e) => Json(ApiResponse::error(format!("User not found: {}", e))),
    }
}
