//! Integration tests for the iterative correction protocol module.
//!
//! Tests cover table typo correction, column typo correction,
//! max-iterations limits, and quality scoring.

use altimate_core::correction::engine::{correct, correct_default};
use altimate_core::correction::types::{CorrectionConfig, CorrectionStatus, IterationResult};
use altimate_core::schema::types::SchemaDefinition;

fn ecommerce_schema() -> SchemaDefinition {
    SchemaDefinition::from_yaml(include_str!(
        "../../../tests/fixtures/schemas/ecommerce.yaml"
    ))
    .expect("Failed to load ecommerce schema")
}

// ═══════════════════════════════════════════════════════════════════════
// Already valid SQL
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_valid_sql_already_valid() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT id, email FROM users", &schema).await;
    assert_eq!(result.status, CorrectionStatus::AlreadyValid);
    assert!(result.corrected_sql.is_none());
    assert!(result.iterations.is_empty());
}

#[tokio::test]
async fn correction_valid_select_star() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT * FROM users", &schema).await;
    assert_eq!(result.status, CorrectionStatus::AlreadyValid);
}

#[tokio::test]
async fn correction_valid_join() {
    let schema = ecommerce_schema();
    let result = correct_default(
        "SELECT u.id, o.id FROM users u JOIN orders o ON u.id = o.user_id",
        &schema,
    )
    .await;
    assert_eq!(result.status, CorrectionStatus::AlreadyValid);
}

#[tokio::test]
async fn correction_valid_has_quality_score() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT id FROM users", &schema).await;
    assert!(result.final_score.syntax_valid);
    assert!(result.final_score.overall > 0.0);
}

// ═══════════════════════════════════════════════════════════════════════
// Fixable errors — table typos
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_misspelled_table_fixed() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT * FROM usrs", &schema).await;
    assert_eq!(result.status, CorrectionStatus::Fixed);
    assert_eq!(result.corrected_sql.as_deref(), Some("SELECT * FROM users"));
}

#[tokio::test]
async fn correction_misspelled_table_records_iteration() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT * FROM usrs", &schema).await;
    assert!(!result.iterations.is_empty());
    assert_eq!(result.iterations[0].iteration, 1);
    assert!(!result.iterations[0].validation_errors.is_empty());
}

#[tokio::test]
async fn correction_misspelled_table_has_fix_description() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT * FROM usrs", &schema).await;
    assert!(result.iterations[0].fix_applied.is_some());
    assert!(result.iterations[0].fix_description.is_some());
}

#[tokio::test]
async fn correction_preserves_original_sql() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT * FROM usrs", &schema).await;
    assert_eq!(result.original_sql, "SELECT * FROM usrs");
}

// ═══════════════════════════════════════════════════════════════════════
// Fixable errors — column typos
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_misspelled_column() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT emal FROM users", &schema).await;
    assert_ne!(result.status, CorrectionStatus::AlreadyValid);
}

// ═══════════════════════════════════════════════════════════════════════
// Unfixable errors
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_syntax_error_unfixable() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECTZ * FROM users", &schema).await;
    assert_eq!(result.status, CorrectionStatus::Unfixable);
    assert!(result.corrected_sql.is_none());
}

#[tokio::test]
async fn correction_empty_sql_unfixable() {
    let schema = ecommerce_schema();
    let result = correct_default("", &schema).await;
    assert_eq!(result.status, CorrectionStatus::Unfixable);
}

#[tokio::test]
async fn correction_garbage_sql_unfixable() {
    let schema = ecommerce_schema();
    let result = correct_default("this is not sql at all", &schema).await;
    assert_eq!(result.status, CorrectionStatus::Unfixable);
}

// ═══════════════════════════════════════════════════════════════════════
// Max iterations
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_respects_max_iterations_one() {
    let schema = ecommerce_schema();
    let config = CorrectionConfig {
        max_iterations: 1,
        ..Default::default()
    };
    let result = correct("SELECT * FROM usrs", &schema, &config).await;
    assert!(result.iterations.len() <= 1);
}

#[tokio::test]
async fn correction_max_iterations_zero() {
    let schema = ecommerce_schema();
    let config = CorrectionConfig {
        max_iterations: 0,
        ..Default::default()
    };
    let result = correct("SELECT * FROM usrs", &schema, &config).await;
    assert!(result.iterations.is_empty());
    assert_ne!(result.status, CorrectionStatus::AlreadyValid);
}

#[tokio::test]
async fn correction_large_max_iterations_fixes_quickly() {
    let schema = ecommerce_schema();
    let config = CorrectionConfig {
        max_iterations: 100,
        ..Default::default()
    };
    let result = correct("SELECT * FROM usrs", &schema, &config).await;
    assert!(result.iterations.len() <= 5);
    assert_eq!(result.status, CorrectionStatus::Fixed);
}

// ═══════════════════════════════════════════════════════════════════════
// Confidence threshold
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_low_confidence_threshold() {
    let schema = ecommerce_schema();
    let config = CorrectionConfig {
        min_confidence: 0.1,
        ..Default::default()
    };
    let result = correct("SELECT * FROM usrs", &schema, &config).await;
    assert_eq!(result.status, CorrectionStatus::Fixed);
}

// ═══════════════════════════════════════════════════════════════════════
// Lint integration
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_lint_enabled_affects_score() {
    let schema = ecommerce_schema();
    let config = CorrectionConfig {
        enable_lint_checks: true,
        ..Default::default()
    };
    let result = correct("SELECT * FROM usrs", &schema, &config).await;
    assert!(result.final_score.lint_score <= 1.0);
}

#[tokio::test]
async fn correction_lint_disabled_defaults_to_one() {
    let schema = ecommerce_schema();
    let config = CorrectionConfig {
        enable_lint_checks: false,
        ..Default::default()
    };
    let result = correct("SELECT * FROM usrs", &schema, &config).await;
    assert_eq!(result.final_score.lint_score, 1.0);
}

// ═══════════════════════════════════════════════════════════════════════
// Quality score
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_quality_score_range() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT id FROM users", &schema).await;
    assert!(result.final_score.overall >= 0.0);
    assert!(result.final_score.overall <= 1.0);
}

#[tokio::test]
async fn correction_simple_query_high_complexity_score() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT id FROM users", &schema).await;
    assert!(result.final_score.complexity_score >= 0.8);
}

// ═══════════════════════════════════════════════════════════════════════
// Serialization
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_result_serializes() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT * FROM usrs", &schema).await;
    let json = serde_json::to_string(&result).expect("should serialize");
    assert!(json.contains("status"));
    assert!(json.contains("original_sql"));
}

#[tokio::test]
async fn correction_config_serializes() {
    let config = CorrectionConfig::default();
    let json = serde_json::to_string(&config).expect("should serialize");
    assert!(json.contains("max_iterations"));
}

// ═══════════════════════════════════════════════════════════════════════
// Status and IterationResult display
// ═══════════════════════════════════════════════════════════════════════

#[test]
fn correction_status_display() {
    assert_eq!(CorrectionStatus::AlreadyValid.to_string(), "already_valid");
    assert_eq!(CorrectionStatus::Fixed.to_string(), "fixed");
    assert_eq!(CorrectionStatus::PartialFix.to_string(), "partial_fix");
    assert_eq!(CorrectionStatus::Unfixable.to_string(), "unfixable");
}

#[test]
fn correction_iteration_result_display() {
    assert_eq!(IterationResult::Fixed.to_string(), "fixed");
    assert_eq!(IterationResult::StillInvalid.to_string(), "still_invalid");
    assert_eq!(IterationResult::NewErrors.to_string(), "new_errors");
    assert_eq!(IterationResult::Skipped.to_string(), "skipped");
}

// ═══════════════════════════════════════════════════════════════════════
// Time tracking
// ═══════════════════════════════════════════════════════════════════════

#[tokio::test]
async fn correction_tracks_time() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT * FROM usrs", &schema).await;
    // Should complete in reasonable time
    assert!(result.total_time_ms < 10000);
}

#[tokio::test]
async fn correction_has_final_validation() {
    let schema = ecommerce_schema();
    let result = correct_default("SELECT * FROM usrs", &schema).await;
    assert!(result.final_validation.is_some());
}
