mod common;

use chrono::Utc;
use common::*;
use dbpulse::queries::mysql;
use dbpulse::tls::{TlsConfig, TlsMode};

#[tokio::test]
#[ignore = "requires running MariaDB container"]
async fn test_mariadb_basic_connection() {
    if skip_if_no_mariadb() {
        return;
    }

    let table_name = test_table_name("test_mariadb_basic_connection");
    let result = test_mariadb_connection_with_table(MARIADB_DSN, &table_name).await;
    assert!(result.is_ok(), "Failed to connect to MariaDB: {result:?}");

    let health = result.unwrap();
    assert!(!health.version.is_empty(), "Version should not be empty");
    assert!(
        health.version.contains("MariaDB"),
        "Should contain MariaDB in version"
    );
}

#[tokio::test]
#[ignore = "requires running MariaDB container"]
async fn test_mariadb_read_write_operations() {
    if skip_if_no_mariadb() {
        return;
    }

    let dsn = parse_dsn(MARIADB_DSN);
    let now = Utc::now();
    let tls = TlsConfig::default();

    // Run test multiple times to ensure cleanup works
    for i in 0..5 {
        let table_name = test_table_name(&format!("test_mariadb_read_write_operations_{i}"));
        let result = mysql::test_rw_with_table(&dsn, now, 100, &tls, &table_name).await;
        assert!(result.is_ok(), "Iteration {i}: {result:?}");
    }
}

#[tokio::test]
#[ignore = "requires running MariaDB container"]
async fn test_mariadb_transaction_rollback() {
    if skip_if_no_mariadb() {
        return;
    }

    let dsn = parse_dsn(MARIADB_DSN);
    let now = Utc::now();
    let tls = TlsConfig::default();
    let table_name = test_table_name("test_mariadb_transaction_rollback");

    // This tests that transaction rollback works correctly
    let result = mysql::test_rw_with_table(&dsn, now, 100, &tls, &table_name).await;
    assert!(result.is_ok(), "Transaction test failed: {result:?}");
}

#[tokio::test]
#[ignore = "requires running MariaDB container"]
async fn test_mariadb_concurrent_connections() {
    if skip_if_no_mariadb() {
        return;
    }

    // Spawn multiple concurrent health checks with unique table names
    // Each task gets its own table, eliminating all collision possibilities
    let mut handles = vec![];
    for i in 0..10 {
        let table_name = test_table_name(&format!("test_mariadb_concurrent_connections_{i}"));
        let handle = tokio::spawn(async move {
            let dsn = parse_dsn(MARIADB_DSN);
            let tls = TlsConfig::default();
            let now = Utc::now();
            mysql::test_rw_with_table(&dsn, now, 100, &tls, &table_name).await
        });
        handles.push(handle);
    }

    // Wait for all to complete
    for handle in handles {
        let result = handle.await.expect("Task panicked");
        assert!(result.is_ok(), "Concurrent test failed: {result:?}");
    }
}

#[tokio::test]
#[ignore = "requires running MariaDB container"]
async fn test_mariadb_with_different_ranges() {
    if skip_if_no_mariadb() {
        return;
    }

    let dsn = parse_dsn(MARIADB_DSN);
    let now = Utc::now();
    let tls = TlsConfig::default();

    // Test different range values
    for range in [10, 50, 100, 500, 1000] {
        let table_name = test_table_name(&format!("test_mariadb_with_different_ranges_{range}"));
        let result = mysql::test_rw_with_table(&dsn, now, range, &tls, &table_name).await;
        assert!(result.is_ok(), "Range {range} failed: {result:?}");
    }
}

#[tokio::test]
#[ignore = "requires running MariaDB container with TLS"]
async fn test_mariadb_tls_disable() {
    if skip_if_no_mariadb() {
        return;
    }

    let result = test_mariadb_with_tls(MARIADB_DSN, TlsMode::Disable).await;
    assert!(result.is_ok(), "TLS Disable failed: {result:?}");

    let health = result.unwrap();
    assert!(
        health.tls_metadata.is_none(),
        "TLS metadata should be None when disabled"
    );
}

#[tokio::test]
#[ignore = "requires running MariaDB container with TLS enabled"]
async fn test_mariadb_tls_require() {
    if skip_if_no_mariadb() {
        return;
    }

    let result = test_mariadb_with_tls(MARIADB_DSN, TlsMode::Require).await;

    // This may fail if MariaDB doesn't have TLS configured
    // That's expected in local test environments
    match result {
        Ok(health) => {
            println!("TLS connection successful");
            if let Some(ref tls_meta) = health.tls_metadata {
                println!("TLS Version: {:?}", tls_meta.version);
                println!("TLS Cipher: {:?}", tls_meta.cipher);
                assert!(
                    tls_meta.version.is_some() || tls_meta.cipher.is_some(),
                    "Should have TLS metadata when TLS is enabled"
                );
            }
        }
        Err(e) => {
            // Expected if MariaDB doesn't have TLS configured
            println!("TLS test skipped (no TLS configured): {e}");
        }
    }
}

#[tokio::test]
#[ignore = "requires running MariaDB container"]
async fn test_mariadb_database_creation() {
    if skip_if_no_mariadb() {
        return;
    }

    // Test with a non-existent database (should be auto-created)
    // Use root user since dbpulse user doesn't have CREATE DATABASE privilege
    let dsn_str = "mysql://root:secret@tcp(localhost:3306)/dbpulse_test_db";
    let table_name = test_table_name("test_mariadb_database_creation");
    let result = test_mariadb_connection_with_table(dsn_str, &table_name).await;

    // Should succeed by creating the database
    assert!(result.is_ok(), "Database auto-creation failed: {result:?}");
}

#[tokio::test]
#[ignore = "requires running MariaDB container"]
async fn test_mariadb_invalid_credentials() {
    if skip_if_no_mariadb() {
        return;
    }

    let dsn_str = "mysql://invalid:invalid@tcp(localhost:3306)/testdb";
    let result = test_mariadb_connection(dsn_str).await;

    // Should fail with authentication error
    assert!(result.is_err(), "Should fail with invalid credentials");
}

#[tokio::test]
#[ignore = "requires running MariaDB container"]
async fn test_mariadb_version_info() {
    if skip_if_no_mariadb() {
        return;
    }

    let table_name = test_table_name("test_mariadb_version_info");
    let result = test_mariadb_connection_with_table(MARIADB_DSN, &table_name).await;
    assert!(result.is_ok());

    let health = result.unwrap();
    println!("MariaDB version: {}", health.version);

    // Version should contain MariaDB and version number
    assert!(health.version.contains("MariaDB"));
    assert!(
        health.version.chars().any(|c| c.is_ascii_digit()),
        "Version should contain version number"
    );
}

#[tokio::test]
#[ignore = "requires running MariaDB container"]
async fn test_mariadb_read_only_detection() {
    if skip_if_no_mariadb() {
        return;
    }

    // Normal connection should not be in read-only mode
    let table_name = test_table_name("test_mariadb_read_only_detection");
    let result = test_mariadb_connection_with_table(MARIADB_DSN, &table_name).await;
    assert!(result.is_ok());

    let health = result.unwrap();
    assert!(
        !health.version.contains("read-only mode"),
        "Database should not be in read-only mode"
    );
}
