//! Integration tests for directory scanning using real Cassandra 5.0 data
//!
//! These tests validate the directory scanner against actual SSTable files
//! generated by Cassandra 5.0 in various scenarios.

use super::directory::*;
use anyhow::Result;
#[cfg(test)]
use std::path::Path;

/// Test scanning real Cassandra 5.0 SSTable directories
#[cfg(test)]
mod integration_tests {
    use super::*;

    const REAL_DATA_PATH: &str =
        "/Users/patrick/local_projects/cqlite/test-env/cassandra5/sstables";

    fn test_data_available() -> bool {
        Path::new(REAL_DATA_PATH).exists()
    }

    #[test]
    fn test_real_cassandra_sstables() {
        if !test_data_available() {
            println!(
                "Skipping real data test - test data not available at {}",
                REAL_DATA_PATH
            );
            return;
        }

        println!("Testing with real Cassandra 5.0 SSTable data...");

        let test_data =
            std::fs::read_dir(REAL_DATA_PATH).expect("Failed to read test data directory");

        let mut tested_tables = 0;
        let mut successful_scans = 0;

        for entry in test_data {
            let entry = entry.expect("Failed to read directory entry");
            let path = entry.path();

            if path.is_dir() {
                if let Some(dir_name) = path.file_name().and_then(|n| n.to_str()) {
                    println!("Testing directory: {}", dir_name);
                    tested_tables += 1;

                    match SSTableDirectory::scan(&path) {
                        Ok(directory) => {
                            successful_scans += 1;
                            println!("  ✅ Successfully scanned: {}", directory.table_name);
                            println!("     Generations: {}", directory.generations.len());
                            println!(
                                "     Secondary indexes: {}",
                                directory.secondary_indexes.len()
                            );
                            println!("     Valid: {}", directory.is_valid());

                            // Test validation
                            match directory.validate_all_generations() {
                                Ok(report) => {
                                    println!("     Validation: {}", report.summary());
                                    if !report.is_valid() {
                                        println!("     Errors: {:?}", report.validation_errors);
                                        println!(
                                            "     TOC issues: {:?}",
                                            report.toc_inconsistencies
                                        );
                                    }
                                }
                                Err(e) => println!("     Validation failed: {}", e),
                            }

                            // Test secondary indexes
                            for secondary_index in &directory.secondary_indexes {
                                println!(
                                    "     Secondary index: {} with {} generations",
                                    secondary_index.index_name,
                                    secondary_index.generations.len()
                                );
                            }
                        }
                        Err(e) => {
                            println!("  ❌ Failed to scan: {}", e);
                        }
                    }
                    println!();
                }
            }
        }

        println!(
            "Summary: {}/{} directories scanned successfully",
            successful_scans, tested_tables
        );
        assert!(
            successful_scans > 0,
            "No directories were successfully scanned"
        );
        assert!(
            successful_scans as f64 / tested_tables as f64 >= 0.8,
            "Less than 80% success rate: {}/{}",
            successful_scans,
            tested_tables
        );
    }

    #[test]
    fn test_specific_table_directory() {
        if !test_data_available() {
            println!("Skipping specific table test - test data not available");
            return;
        }

        // Test the users table specifically since we know it exists
        let _users_dir_pattern = format!("{}/users-*", REAL_DATA_PATH);
        let users_dirs: Vec<_> = std::fs::read_dir(REAL_DATA_PATH)
            .expect("Failed to read directory")
            .filter_map(|e| e.ok())
            .filter(|e| e.path().is_dir() && e.file_name().to_string_lossy().starts_with("users-"))
            .collect();

        if users_dirs.is_empty() {
            println!("No users table found, checking available tables...");
            let entries: Vec<_> = std::fs::read_dir(REAL_DATA_PATH)
                .unwrap()
                .filter_map(|e| e.ok())
                .filter(|e| e.path().is_dir())
                .map(|e| e.file_name().to_string_lossy().to_string())
                .collect();
            println!("Available tables: {:?}", entries);

            if let Some(first_table) = entries.first() {
                let table_path = Path::new(REAL_DATA_PATH).join(first_table);
                test_table_directory(&table_path);
            }
            return;
        }

        let users_path = users_dirs[0].path();
        test_table_directory(&users_path);
    }

    fn test_table_directory(table_path: &Path) {
        println!("Testing specific table: {:?}", table_path);

        let directory = SSTableDirectory::scan(table_path).expect("Failed to scan table directory");

        // Comprehensive validation
        assert!(
            !directory.table_name.is_empty(),
            "Table name should not be empty"
        );
        assert!(
            !directory.generations.is_empty(),
            "Should have at least one generation"
        );
        assert!(directory.is_valid(), "Directory should be valid");

        // Check that the latest generation has required components
        let latest = directory
            .latest_generation()
            .expect("Should have latest generation");
        assert!(
            latest.components.contains_key(&SSTableComponent::Data),
            "Missing Data component"
        );
        assert!(
            latest
                .components
                .contains_key(&SSTableComponent::Statistics),
            "Missing Statistics component"
        );

        // Test TOC parsing if available
        if let Ok(toc_components) = directory.parse_toc(latest) {
            println!("TOC components: {:?}", toc_components);
            assert!(!toc_components.is_empty(), "TOC should not be empty");
            assert!(
                toc_components.contains(&SSTableComponent::Data),
                "TOC should list Data component"
            );
        }

        // Test validation report
        let report = directory
            .validate_all_generations()
            .expect("Validation should succeed");
        println!("Validation report: {}", report.summary());

        // Print detailed information
        println!("Table: {}", directory.table_name);
        println!("Generations: {}", directory.generations.len());
        for (i, generation) in directory.generations.iter().enumerate() {
            println!(
                "  Generation {}: gen={}, format={}, components={}",
                i + 1,
                generation.generation,
                generation.format,
                generation.components.len()
            );

            for (component, path) in &generation.components {
                println!(
                    "    {:?}: {} bytes",
                    component,
                    std::fs::metadata(path).map(|m| m.len()).unwrap_or(0)
                );
            }
        }

        println!("Secondary indexes: {}", directory.secondary_indexes.len());
        for idx in &directory.secondary_indexes {
            println!(
                "  {}: {} generations",
                idx.index_name,
                idx.generations.len()
            );
        }
    }

    #[test]
    fn test_toc_consistency_with_real_data() {
        if !test_data_available() {
            println!("Skipping TOC consistency test - test data not available");
            return;
        }

        // Find any table with a TOC.txt file
        let test_data =
            std::fs::read_dir(REAL_DATA_PATH).expect("Failed to read test data directory");

        for entry in test_data.flatten() {
            let path = entry.path();
            if path.is_dir() && SSTableDirectory::scan(&path).is_ok() {
                if let Ok(directory) = SSTableDirectory::scan(&path) {
                    for generation in &directory.generations {
                        if generation.components.contains_key(&SSTableComponent::TOC) {
                            println!("Testing TOC consistency for: {}", directory.table_name);

                            let inconsistencies = validate_toc_consistency(generation)
                                .expect("TOC validation should succeed");

                            if inconsistencies.is_empty() {
                                println!("  ✅ TOC is consistent");
                            } else {
                                println!("  ⚠️ TOC inconsistencies found:");
                                for inconsistency in &inconsistencies {
                                    println!("    - {}", inconsistency);
                                }
                            }

                            // At least one table should have consistent TOC
                            // (this is more of a data quality check than a code test)
                            return;
                        }
                    }
                }
            }
        }

        println!("No TOC files found in test data");
    }
}

/// Helper function to run the integration tests manually
pub fn run_integration_tests() -> Result<()> {
    use std::path::Path;

    let test_data_path = "/Users/patrick/local_projects/cqlite/test-env/cassandra5/sstables";

    if !Path::new(test_data_path).exists() {
        println!("Test data not available at {}", test_data_path);
        println!(
            "Run 'cd test-env/cassandra5 && ./manage.sh all && ./manage.sh extract-sstables' to generate test data"
        );
        return Ok(());
    }

    println!("🔍 Running directory scanner integration tests with real Cassandra 5.0 data...\n");

    let entries = std::fs::read_dir(test_data_path)?;
    let mut summary = IntegrationTestSummary::default();

    for entry in entries {
        let entry = entry?;
        let path = entry.path();

        if path.is_dir() {
            if let Some(dir_name) = path.file_name().and_then(|n| n.to_str()) {
                summary.total_tables += 1;

                match SSTableDirectory::scan(&path) {
                    Ok(directory) => {
                        summary.successful_scans += 1;
                        print_directory_info(&directory);

                        // Run validation
                        match directory.validate_all_generations() {
                            Ok(report) => {
                                if report.is_valid() {
                                    summary.fully_valid += 1;
                                } else {
                                    summary.validation_issues += 1;
                                    println!("  ⚠️ Validation issues:");
                                    for error in &report.validation_errors {
                                        println!("    - {}", error);
                                    }
                                    for issue in &report.toc_inconsistencies {
                                        println!("    - {}", issue);
                                    }
                                }
                            }
                            Err(e) => {
                                summary.validation_errors += 1;
                                println!("  ❌ Validation error: {}", e);
                            }
                        }
                    }
                    Err(e) => {
                        summary.scan_failures += 1;
                        println!("❌ Failed to scan {}: {}", dir_name, e);
                    }
                }
                println!();
            }
        }
    }

    print_summary(&summary);
    Ok(())
}

#[derive(Default)]
struct IntegrationTestSummary {
    total_tables: usize,
    successful_scans: usize,
    scan_failures: usize,
    fully_valid: usize,
    validation_issues: usize,
    validation_errors: usize,
}

fn print_directory_info(directory: &SSTableDirectory) {
    println!(
        "📁 Table: {} ({})",
        directory.table_name,
        directory.path.file_name().unwrap().to_str().unwrap()
    );
    println!("  📊 Generations: {}", directory.generations.len());
    println!(
        "  🔍 Secondary indexes: {}",
        directory.secondary_indexes.len()
    );
    println!("  ✅ Valid: {}", directory.is_valid());

    for (i, generation) in directory.generations.iter().enumerate() {
        println!(
            "  📄 Generation {} (gen={}, format={}): {} components",
            i + 1,
            generation.generation,
            generation.format,
            generation.components.len()
        );

        // Show component sizes
        for (component, path) in &generation.components {
            let size = std::fs::metadata(path)
                .map(|m| format!("{} bytes", m.len()))
                .unwrap_or_else(|_| "unknown size".to_string());
            println!("    {:?}: {}", component, size);
        }
    }

    for idx in &directory.secondary_indexes {
        println!(
            "  📇 Index '{}': {} generations",
            idx.index_name,
            idx.generations.len()
        );
    }
}

fn print_summary(summary: &IntegrationTestSummary) {
    println!("📈 Integration Test Summary:");
    println!("  Total tables: {}", summary.total_tables);
    println!(
        "  Successful scans: {} ({:.1}%)",
        summary.successful_scans,
        summary.successful_scans as f64 / summary.total_tables as f64 * 100.0
    );
    println!("  Scan failures: {}", summary.scan_failures);
    println!(
        "  Fully valid: {} ({:.1}%)",
        summary.fully_valid,
        summary.fully_valid as f64 / summary.successful_scans as f64 * 100.0
    );
    println!("  Validation issues: {}", summary.validation_issues);
    println!("  Validation errors: {}", summary.validation_errors);

    let success_rate = summary.successful_scans as f64 / summary.total_tables as f64;
    if success_rate >= 0.9 {
        println!(
            "🎉 Excellent compatibility! ({:.1}% success)",
            success_rate * 100.0
        );
    } else if success_rate >= 0.8 {
        println!(
            "✅ Good compatibility ({:.1}% success)",
            success_rate * 100.0
        );
    } else if success_rate >= 0.7 {
        println!(
            "⚠️ Acceptable compatibility ({:.1}% success)",
            success_rate * 100.0
        );
    } else {
        println!(
            "❌ Poor compatibility ({:.1}% success)",
            success_rate * 100.0
        );
    }
}
