use actix_web::http::StatusCode;
use athena_rs::error::{ErrorCategory, ProcessedError};
use athena_rs::error::{
    sql_sanitizer::{extract_metadata, sanitize_and_extract, sanitize_error_message},
    sqlx_parser::process_sqlx_error,
};
use serde_json::json;

#[test]
fn sql_sanitizer_sanitize_select_query() {
    let error = "failed to execute select query: SELECT id, name FROM users WHERE email = $1: column 'email' does not exist";
    let sanitized = sanitize_error_message(error);

    assert!(!sanitized.contains("SELECT"));
    assert!(!sanitized.contains("users"));
    assert!(sanitized.contains("column"));
}

#[test]
fn sql_sanitizer_sanitize_insert_query() {
    let error = "INSERT INTO users (name, email) VALUES ($1, $2): duplicate key value violates unique constraint \"users_email_key\"";
    let sanitized = sanitize_error_message(error);

    assert!(!sanitized.contains("INSERT INTO"));
    assert!(!sanitized.contains("VALUES"));
    assert!(sanitized.contains("constraint"));
}

#[test]
fn sql_sanitizer_sanitize_update_query() {
    let error = "UPDATE users SET name = $1 WHERE id = $2: permission denied";
    let sanitized = sanitize_error_message(error);

    assert!(!sanitized.contains("UPDATE"));
    assert!(!sanitized.contains("SET"));
    assert!(sanitized.contains("permission"));
}

#[test]
fn sql_sanitizer_extract_constraint_name() {
    let error = "duplicate key value violates unique constraint \"users_email_key\"";
    let info = extract_metadata(error);

    assert_eq!(info.constraint_name, Some("users_email_key".to_string()));
}

#[test]
fn sql_sanitizer_extract_column_name() {
    let error = "column \"email\" does not exist";
    let info = extract_metadata(error);

    assert_eq!(info.column_name, Some("email".to_string()));
}

#[test]
fn sql_sanitizer_extract_table_name() {
    let error = "relation \"users\" does not exist";
    let info = extract_metadata(error);

    assert_eq!(info.table_name, Some("users".to_string()));
}

#[test]
fn sql_sanitizer_sanitize_and_extract() {
    let error = "SELECT * FROM users WHERE email = $1: column \"email\" does not exist";
    let (sanitized, info) = sanitize_and_extract(error);

    assert!(!sanitized.contains("SELECT"));
    assert_eq!(info.column_name, Some("email".to_string()));
}

#[test]
fn sql_sanitizer_empty_sql_only_message() {
    let error = "SELECT * FROM users";
    let sanitized = sanitize_error_message(error);

    assert_eq!(sanitized, "Database query execution failed");
}

#[test]
fn sql_sanitizer_multiple_sql_statements() {
    let error = "failed: SELECT * FROM users; INSERT INTO logs VALUES ($1)";
    let sanitized = sanitize_error_message(error);

    assert!(!sanitized.contains("SELECT"));
    assert!(!sanitized.contains("INSERT"));
    assert!(sanitized.contains("failed"));
}

#[test]
fn error_category_serialization() {
    let category = ErrorCategory::DatabaseConstraint;
    let json = serde_json::to_string(&category).unwrap();
    assert_eq!(json, "\"database_constraint\"");
}

#[test]
fn processed_error_builder() {
    let error = ProcessedError::new(
        ErrorCategory::QuerySyntax,
        StatusCode::BAD_REQUEST,
        "invalid_query",
        "Invalid query syntax",
        "trace123",
    )
    .with_hint("Check your column names")
    .with_metadata("table", json!("users"));

    assert_eq!(error.category, ErrorCategory::QuerySyntax);
    assert_eq!(error.status_code, StatusCode::BAD_REQUEST);
    assert_eq!(error.error_code, "invalid_query");
    assert_eq!(error.hint, Some("Check your column names".to_string()));
    assert_eq!(error.metadata.get("table").unwrap(), "users");
}

#[test]
fn processed_error_to_json() {
    let error = ProcessedError::new(
        ErrorCategory::DatabaseConstraint,
        StatusCode::CONFLICT,
        "unique_violation",
        "A record with this value already exists",
        "abc123",
    )
    .with_hint("Try a different value")
    .with_metadata("constraint", json!("users_email_key"));

    let json = error.to_json();
    assert_eq!(json["status"], "error");
    assert_eq!(json["code"], "unique_violation");
    assert_eq!(json["hint"], "Try a different value");
    assert_eq!(json["trace_id"], "abc123");
    assert_eq!(json["details"]["category"], "database_constraint");
    assert_eq!(json["details"]["constraint"], "users_email_key");
}

#[test]
fn generate_trace_id() {
    let trace_id = athena_rs::error::generate_trace_id();
    assert!(!trace_id.is_empty());
    assert!(trace_id.len() <= 16);
}

#[test]
fn sqlx_parser_row_not_found_error() {
    let err = sqlx::Error::RowNotFound;
    let processed = process_sqlx_error(&err);

    assert_eq!(processed.category, ErrorCategory::NotFound);
    assert_eq!(processed.status_code, StatusCode::NOT_FOUND);
    assert_eq!(processed.error_code, "row_not_found");
    assert!(processed.hint.is_some());
}

#[test]
fn sqlx_parser_pool_timeout_error() {
    let err = sqlx::Error::PoolTimedOut;
    let processed = process_sqlx_error(&err);

    assert_eq!(processed.category, ErrorCategory::DatabaseConnection);
    assert_eq!(processed.status_code, StatusCode::SERVICE_UNAVAILABLE);
    assert_eq!(processed.error_code, "pool_timeout");
}

#[test]
fn sqlx_parser_column_not_found_error() {
    let err = sqlx::Error::ColumnNotFound("email".to_string());
    let processed = process_sqlx_error(&err);

    assert_eq!(processed.category, ErrorCategory::QuerySyntax);
    assert_eq!(processed.error_code, "column_not_found");
    assert_eq!(processed.metadata.get("column").unwrap(), "email");
}
