//! REST API handlers for MFA operations

use std::sync::Arc;

use axum::{
    extract::{Path, State},
    http::StatusCode,
    response::IntoResponse,
    Json,
};
use validator::Validate;

use crate::auth::jwt::TokenClaims;
use crate::error::{auth, http, ControlCenterError, Result};
use crate::mfa::service::MfaService;
use crate::mfa::types::*;

/// TOTP enrollment endpoint
///
/// POST /api/v1/mfa/totp/enroll
pub async fn totp_enroll(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;
    let email = claims.email.as_deref().unwrap_or("unknown@example.com");

    let enrollment = mfa_service.enroll_totp(&user_id, email).await?;

    Ok((StatusCode::OK, Json(enrollment)).into_response())
}

/// TOTP verification endpoint
///
/// POST /api/v1/mfa/totp/verify
pub async fn totp_verify(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
    Json(req): Json<TotpVerifyRequest>,
) -> Result<Json<MfaVerification>> {
    req.validate().map_err(|e| {
        ControlCenterError::Http(http::HttpError::BadRequest(format!(
            "Validation error: {}",
            e
        )))
    })?;

    let user_id = claims.sub;
    let email = claims.email.as_deref().unwrap_or("unknown@example.com");

    let result = mfa_service
        .verify_totp(&user_id, email, &req.code, req.device_id.as_deref())
        .await?;

    Ok(Json(result))
}

/// Disable TOTP endpoint
///
/// POST /api/v1/mfa/totp/disable
pub async fn totp_disable(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    mfa_service.disable_totp(&user_id).await?;

    Ok((
        StatusCode::OK,
        Json(serde_json::json!({
            "message": "TOTP disabled successfully"
        })),
    )
        .into_response())
}

/// Get backup codes endpoint
///
/// GET /api/v1/mfa/totp/backup-codes
pub async fn totp_backup_codes(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    let backup_codes = mfa_service.get_backup_codes(&user_id).await?;

    Ok((StatusCode::OK, Json(BackupCodesResponse { backup_codes })).into_response())
}

/// Regenerate backup codes endpoint
///
/// POST /api/v1/mfa/totp/regenerate
pub async fn totp_regenerate_backup_codes(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    let backup_codes = mfa_service.regenerate_backup_codes(&user_id).await?;

    Ok((StatusCode::OK, Json(BackupCodesResponse { backup_codes })).into_response())
}

/// Start WebAuthn registration endpoint
///
/// POST /api/v1/mfa/webauthn/register/start
pub async fn webauthn_register_start(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;
    let email = claims.email.as_deref().unwrap_or("unknown@example.com");

    let challenge = mfa_service
        .start_webauthn_registration(&user_id, email, email)
        .await?;

    Ok((StatusCode::OK, Json(challenge)).into_response())
}

/// Finish WebAuthn registration endpoint
///
/// POST /api/v1/mfa/webauthn/register/finish
pub async fn webauthn_register_finish(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
    Json(req): Json<WebAuthnRegistrationResponse>,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    let device = mfa_service
        .finish_webauthn_registration(&user_id, &req)
        .await?;

    Ok((StatusCode::OK, Json(device)).into_response())
}

/// Start WebAuthn authentication endpoint
///
/// POST /api/v1/mfa/webauthn/auth/start
pub async fn webauthn_auth_start(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    let challenge = mfa_service.start_webauthn_authentication(&user_id).await?;

    Ok((StatusCode::OK, Json(challenge)).into_response())
}

/// Finish WebAuthn authentication endpoint
///
/// POST /api/v1/mfa/webauthn/auth/finish
pub async fn webauthn_auth_finish(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
    Json(req): Json<WebAuthnAuthenticationResponse>,
) -> Result<Json<MfaVerification>> {
    let user_id = claims.sub;

    let result = mfa_service.verify_webauthn(&user_id, &req).await?;

    Ok(Json(result))
}

/// List WebAuthn devices endpoint
///
/// GET /api/v1/mfa/webauthn/devices
pub async fn webauthn_list_devices(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    let devices = mfa_service.list_webauthn_devices(&user_id).await?;

    Ok((StatusCode::OK, Json(devices)).into_response())
}

/// Remove WebAuthn device endpoint
///
/// DELETE /api/v1/mfa/webauthn/devices/{device_id}
pub async fn webauthn_remove_device(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
    Path(device_id): Path<String>,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    mfa_service
        .remove_webauthn_device(&user_id, &device_id)
        .await?;

    Ok((
        StatusCode::OK,
        Json(serde_json::json!({
            "message": "Device removed successfully"
        })),
    )
        .into_response())
}

/// Get MFA status endpoint
///
/// GET /api/v1/mfa/status
pub async fn mfa_status(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    let status = mfa_service.get_mfa_status(&user_id).await?;

    Ok((StatusCode::OK, Json(status)).into_response())
}

/// Disable all MFA endpoint
///
/// POST /api/v1/mfa/disable
pub async fn mfa_disable_all(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    mfa_service.disable_all_mfa(&user_id).await?;

    Ok((
        StatusCode::OK,
        Json(serde_json::json!({
            "message": "All MFA methods disabled successfully"
        })),
    )
        .into_response())
}

/// List all MFA devices endpoint
///
/// GET /api/v1/mfa/devices
pub async fn mfa_list_devices(
    State(mfa_service): State<Arc<MfaService>>,
    claims: TokenClaims,
) -> Result<axum::response::Response> {
    let user_id = claims.sub;

    let status = mfa_service.get_mfa_status(&user_id).await?;

    Ok((
        StatusCode::OK,
        Json(serde_json::json!({
            "totp_devices": status.totp_devices,
            "webauthn_devices": status.webauthn_devices
        })),
    )
        .into_response())
}

#[cfg(test)]
mod tests {
    use super::*;

    // Integration tests would go here
    // These require a full service setup with database, etc.
}
