use axum::{
    extract::State,
    http::StatusCode,
    response::Json,
};
use ontoref_derive::onto_api;
use provisioning_orchestrator::{
    audit::{AuditEvent, AuditFilter, AuditQuery, RetentionPolicy, SiemFormat},
    SharedState,
};
use serde::Deserialize;
use tracing::error;

use super::ApiResponse;

/// Query audit logs with filters
#[onto_api(
    method = "POST",
    path = "/api/v1/audit/query",
    description = "Query audit logs with filters",
    auth = "bearer",
    actors = "developer, agent",
    tags = "audit",
    feature = ""
)]
pub async fn query_audit_logs(
    State(state): State<SharedState>,
    Json(query): Json<AuditQuery>,
) -> Result<Json<ApiResponse<Vec<AuditEvent>>>, StatusCode> {
    match state.audit_logger.query(query).await {
        Ok(events) => Ok(Json(ApiResponse::success(events))),
        Err(e) => {
            error!("Failed to query audit logs: {}", e);
            Ok(Json(ApiResponse::error(format!("Query failed: {}", e))))
        }
    }
}

/// Export audit logs to specific format
#[derive(Debug, Deserialize)]
pub struct ExportRequest {
    pub format: SiemFormat,
    pub filter: Option<AuditFilter>,
}

#[onto_api(
    method = "POST",
    path = "/api/v1/audit/export",
    description = "Export audit logs in SIEM format",
    auth = "bearer",
    actors = "developer, agent",
    tags = "audit",
    feature = ""
)]
pub async fn export_audit_logs(
    State(state): State<SharedState>,
    Json(request): Json<ExportRequest>,
) -> Result<axum::response::Response, StatusCode> {
    match state
        .audit_logger
        .export(request.format, request.filter)
        .await
    {
        Ok(data) => {
            let content_type = match request.format {
                SiemFormat::Json
                | SiemFormat::JsonLines
                | SiemFormat::SplunkCim
                | SiemFormat::ElasticEcs => "application/json",
                SiemFormat::Csv => "text/csv",
            };

            Ok(axum::response::Response::builder()
                .status(StatusCode::OK)
                .header("Content-Type", content_type)
                .body(axum::body::Body::from(data))
                .unwrap())
        }
        Err(e) => {
            error!("Failed to export audit logs: {}", e);
            Err(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

/// Get audit logger statistics
#[onto_api(
    method = "GET",
    path = "/api/v1/audit/stats",
    description = "Get audit logger statistics",
    auth = "bearer",
    actors = "developer, agent",
    tags = "audit",
    feature = ""
)]
pub async fn get_audit_stats(
    State(state): State<SharedState>,
) -> Result<Json<ApiResponse<serde_json::Value>>, StatusCode> {
    let stats = state.audit_logger.stats().await;
    Ok(Json(ApiResponse::success(
        serde_json::to_value(stats).unwrap_or_default(),
    )))
}

/// Get audit storage statistics
#[onto_api(
    method = "GET",
    path = "/api/v1/audit/storage-stats",
    description = "Get audit storage statistics",
    auth = "bearer",
    actors = "developer, agent",
    tags = "audit",
    feature = ""
)]
pub async fn get_audit_storage_stats(
    State(_state): State<SharedState>,
) -> Result<Json<ApiResponse<serde_json::Value>>, StatusCode> {
    // Note: This would require access to the storage backend
    // For now, return a placeholder
    Ok(Json(ApiResponse::success(serde_json::json!({
        "total_events": 0,
        "total_size_bytes": 0,
        "oldest_event": null,
        "newest_event": null,
        "note": "Storage stats require direct storage access"
    }))))
}

/// Apply retention policy to audit logs
#[onto_api(
    method = "POST",
    path = "/api/v1/audit/apply-retention",
    description = "Apply retention policy to audit logs",
    auth = "bearer",
    actors = "developer, agent",
    tags = "audit",
    feature = ""
)]
pub async fn apply_audit_retention(
    State(state): State<SharedState>,
    Json(_policy): Json<RetentionPolicy>,
) -> Result<Json<ApiResponse<usize>>, StatusCode> {
    // Temporarily update the audit logger's retention policy
    // In production, this should be done through configuration
    match state.audit_logger.apply_retention().await {
        Ok(deleted) => Ok(Json(ApiResponse::success(deleted))),
        Err(e) => {
            error!("Failed to apply retention policy: {}", e);
            Ok(Json(ApiResponse::error(format!("Retention failed: {}", e))))
        }
    }
}

/// Search audit logs with text query
#[derive(Debug, Deserialize)]
pub struct SearchRequest {
    pub query: String,
    pub field: String,
}

#[onto_api(
    method = "POST",
    path = "/api/v1/audit/search",
    description = "Search audit logs by text query",
    auth = "bearer",
    actors = "developer, agent",
    tags = "audit",
    feature = ""
)]
pub async fn search_audit_logs(
    State(state): State<SharedState>,
    Json(request): Json<SearchRequest>,
) -> Result<Json<ApiResponse<Vec<AuditEvent>>>, StatusCode> {
    // Build filter based on field
    let filter = match request.field.as_str() {
        "user" => AuditFilter {
            user_id: Some(request.query.clone()),
            ..Default::default()
        },
        "resource" => AuditFilter {
            resource: Some(request.query.clone()),
            ..Default::default()
        },
        "workspace" => AuditFilter {
            workspace: Some(request.query.clone()),
            ..Default::default()
        },
        _ => {
            // Search all fields - this is a simple implementation
            // In production, you'd want full-text search
            AuditFilter::default()
        }
    };

    let query = AuditQuery {
        filter,
        limit: Some(100),
        offset: None,
        sort_by: Some("timestamp".to_string()),
        sort_desc: true,
    };

    match state.audit_logger.query(query).await {
        Ok(events) => Ok(Json(ApiResponse::success(events))),
        Err(e) => {
            error!("Failed to search audit logs: {}", e);
            Ok(Json(ApiResponse::error(format!("Search failed: {}", e))))
        }
    }
}
