use std::sync::Arc;

use axum::{
    extract::State,
    http::StatusCode,
    response::{IntoResponse, Json, Response},
    routing::{delete, get, post},
    Router,
};
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
use tracing::{error, info};

use crate::leases::LeaseStore;
use crate::service::KmsService;
use crate::types::{
    DecryptRequest, DecryptResponse, EncryptRequest, EncryptResponse, EncryptionContext,
    GenerateKeyRequest, GenerateKeyResponse, HealthResponse, KmsStatus, RotateKeyRequest,
    RotateKeyResponse,
};

/// API error response
#[derive(Debug, serde::Serialize)]
struct ErrorResponse {
    error: String,
}

impl IntoResponse for ErrorResponse {
    fn into_response(self) -> Response {
        (StatusCode::INTERNAL_SERVER_ERROR, Json(self)).into_response()
    }
}

/// Application state
pub struct AppState {
    pub kms_service: Arc<KmsService>,
    pub lease_store: Arc<LeaseStore>,
}

/// Create API router
pub fn create_router(kms_service: Arc<KmsService>, lease_store: Arc<LeaseStore>) -> Router {
    use super::leases::{get_credential, revoke_lease};

    let state = Arc::new(AppState {
        kms_service,
        lease_store: Arc::clone(&lease_store),
    });

    Router::new()
        .route("/api/v1/kms/health", get(health_handler))
        .route("/api/v1/kms/status", get(status_handler))
        .route("/api/v1/kms/encrypt", post(encrypt_handler))
        .route("/api/v1/kms/decrypt", post(decrypt_handler))
        .route("/api/v1/kms/generate-key", post(generate_key_handler))
        .route("/api/v1/kms/rotate-key", post(rotate_key_handler))
        .with_state(state)
        // Lease endpoints use the store as state directly
        .route(
            "/api/v1/leases/{lease_id}/credential",
            get(get_credential).with_state(lease_store.clone()),
        )
        .route(
            "/api/v1/leases/{lease_id}",
            delete(revoke_lease).with_state(lease_store),
        )
}

/// Health check endpoint
async fn health_handler(
    State(state): State<Arc<AppState>>,
) -> Result<Json<HealthResponse>, ErrorResponse> {
    let healthy = state
        .kms_service
        .health_check()
        .await
        .map_err(|e| ErrorResponse {
            error: e.to_string(),
        })?;

    let response = HealthResponse {
        status: if healthy { "healthy" } else { "unhealthy" }.to_string(),
        backend: state.kms_service.get_backend_name(),
        timestamp: chrono::Utc::now().to_rfc3339(),
    };

    Ok(Json(response))
}

/// Status endpoint
async fn status_handler(
    State(state): State<Arc<AppState>>,
) -> Result<Json<KmsStatus>, ErrorResponse> {
    let version = state
        .kms_service
        .get_version()
        .await
        .map_err(|e| ErrorResponse {
            error: e.to_string(),
        })?;

    let healthy = state
        .kms_service
        .health_check()
        .await
        .map_err(|e| ErrorResponse {
            error: e.to_string(),
        })?;

    let status = KmsStatus {
        backend: state.kms_service.get_backend_name(),
        healthy,
        version,
        uptime: format!("{}s", state.kms_service.get_uptime()),
        operations_count: state.kms_service.get_operations_count().await,
    };

    Ok(Json(status))
}

/// Encrypt endpoint
async fn encrypt_handler(
    State(state): State<Arc<AppState>>,
    Json(request): Json<EncryptRequest>,
) -> Result<Json<EncryptResponse>, ErrorResponse> {
    info!("Encrypt request received");

    // Decode base64 plaintext
    let plaintext = BASE64
        .decode(&request.plaintext)
        .map_err(|e| ErrorResponse {
            error: format!("Invalid base64 plaintext: {}", e),
        })?;

    // Parse context if provided
    let context = if let Some(ctx_str) = request.context {
        ctx_str
            .parse::<EncryptionContext>()
            .map_err(|e| ErrorResponse {
                error: format!("Invalid context: {}", e),
            })?
    } else {
        EncryptionContext::new()
    };

    // Encrypt
    let ciphertext = state
        .kms_service
        .encrypt(&plaintext, &context)
        .await
        .map_err(|e| {
            error!("Encryption failed: {}", e);
            ErrorResponse {
                error: e.to_string(),
            }
        })?;

    let response = EncryptResponse {
        ciphertext: BASE64.encode(&ciphertext),
        key_id: state.kms_service.get_backend_name(),
    };

    Ok(Json(response))
}

/// Decrypt endpoint
async fn decrypt_handler(
    State(state): State<Arc<AppState>>,
    Json(request): Json<DecryptRequest>,
) -> Result<Json<DecryptResponse>, ErrorResponse> {
    info!("Decrypt request received");

    // Decode base64 ciphertext
    let ciphertext = BASE64
        .decode(&request.ciphertext)
        .map_err(|e| ErrorResponse {
            error: format!("Invalid base64 ciphertext: {}", e),
        })?;

    // Parse context if provided
    let context = if let Some(ctx_str) = request.context {
        ctx_str
            .parse::<EncryptionContext>()
            .map_err(|e| ErrorResponse {
                error: format!("Invalid context: {}", e),
            })?
    } else {
        EncryptionContext::new()
    };

    // Decrypt
    let plaintext = state
        .kms_service
        .decrypt(&ciphertext, &context)
        .await
        .map_err(|e| {
            error!("Decryption failed: {}", e);
            ErrorResponse {
                error: e.to_string(),
            }
        })?;

    let response = DecryptResponse {
        plaintext: BASE64.encode(&plaintext),
    };

    Ok(Json(response))
}

/// Generate data key endpoint
async fn generate_key_handler(
    State(state): State<Arc<AppState>>,
    Json(request): Json<GenerateKeyRequest>,
) -> Result<Json<GenerateKeyResponse>, ErrorResponse> {
    info!("Generate key request received: {:?}", request.key_spec);

    let data_key = state
        .kms_service
        .generate_data_key(&request.key_spec)
        .await
        .map_err(|e| {
            error!("Key generation failed: {}", e);
            ErrorResponse {
                error: e.to_string(),
            }
        })?;

    let response = GenerateKeyResponse {
        plaintext: BASE64.encode(&data_key.plaintext),
        ciphertext: BASE64.encode(&data_key.ciphertext),
        key_id: data_key.key_id,
    };

    Ok(Json(response))
}

/// Rotate key endpoint
async fn rotate_key_handler(
    State(state): State<Arc<AppState>>,
    Json(request): Json<RotateKeyRequest>,
) -> Result<Json<RotateKeyResponse>, ErrorResponse> {
    info!("Rotate key request received: {}", request.key_id);

    let new_key_id = state
        .kms_service
        .rotate_key(&request.key_id)
        .await
        .map_err(|e| {
            error!("Key rotation failed: {}", e);
            ErrorResponse {
                error: e.to_string(),
            }
        })?;

    let response = RotateKeyResponse {
        new_key_id,
        success: true,
    };

    Ok(Json(response))
}
