#![allow(
    clippy::unwrap_used,
    clippy::expect_used,
    clippy::indexing_slicing,
    clippy::absurd_extreme_comparisons,
    clippy::field_reassign_with_default,
    clippy::manual_flatten,
    clippy::tests_outside_test_module,
    unused_imports,
    unused_variables,
    unused_comparisons,
    dead_code,
)]
//! Unit tests for the database package
//!
//! These tests focus on testing logic without requiring a live database connection.

use config::database::{DatabaseConfig, PoolConfig, TransactionConfig};
use database::{error::ErrorSeverity, DatabaseError, OrderDirection, QueryBuilder};

mod error_tests {
    use super::*;

    #[test]
    fn test_error_is_retryable_connection_pool() {
        let error = DatabaseError::ConnectionPool {
            message: "Pool exhausted".to_string(),
        };
        assert!(
            error.is_retryable(),
            "ConnectionPool errors should be retryable"
        );
    }

    #[test]
    fn test_error_is_retryable_connection() {
        let error = DatabaseError::Connection {
            message: "Connection refused".to_string(),
        };
        assert!(
            error.is_retryable(),
            "Connection errors should be retryable"
        );
    }

    #[test]
    fn test_error_is_retryable_timeout() {
        let error = DatabaseError::Timeout {
            operation: "query".to_string(),
            timeout_secs: 30,
        };
        assert!(error.is_retryable(), "Timeout errors should be retryable");
    }

    #[test]
    fn test_error_is_retryable_query_with_connection_message() {
        let error = DatabaseError::Query {
            query: "SELECT 1".to_string(),
            message: "connection reset".to_string(),
        };
        assert!(
            error.is_retryable(),
            "Query errors with connection issues should be retryable"
        );
    }

    #[test]
    fn test_error_is_not_retryable_validation() {
        let error = DatabaseError::Validation {
            field: "email".to_string(),
            message: "Invalid format".to_string(),
        };
        assert!(
            !error.is_retryable(),
            "Validation errors should not be retryable"
        );
    }

    #[test]
    fn test_error_is_not_retryable_constraint_violation() {
        let error = DatabaseError::ConstraintViolation {
            constraint: "unique_email".to_string(),
            message: "Duplicate key".to_string(),
        };
        assert!(
            !error.is_retryable(),
            "Constraint violations should not be retryable"
        );
    }

    #[test]
    fn test_error_is_not_retryable_not_found() {
        let error = DatabaseError::NotFound {
            resource_type: "user".to_string(),
            identifier: "123".to_string(),
        };
        assert!(
            !error.is_retryable(),
            "NotFound errors should not be retryable"
        );
    }

    #[test]
    fn test_error_category_connection_pool() {
        let error = DatabaseError::ConnectionPool {
            message: "Pool error".to_string(),
        };
        assert_eq!(error.category(), "connection_pool");
    }

    #[test]
    fn test_error_category_connection() {
        let error = DatabaseError::Connection {
            message: "Connection error".to_string(),
        };
        assert_eq!(error.category(), "connection");
    }

    #[test]
    fn test_error_category_query() {
        let error = DatabaseError::Query {
            query: "SELECT 1".to_string(),
            message: "Query error".to_string(),
        };
        assert_eq!(error.category(), "query");
    }

    #[test]
    fn test_error_category_transaction() {
        let error = DatabaseError::Transaction {
            message: "Transaction error".to_string(),
        };
        assert_eq!(error.category(), "transaction");
    }

    #[test]
    fn test_error_category_configuration() {
        let error = DatabaseError::Configuration {
            message: "Config error".to_string(),
        };
        assert_eq!(error.category(), "configuration");
    }

    #[test]
    fn test_error_category_migration() {
        let error = DatabaseError::Migration {
            message: "Migration error".to_string(),
        };
        assert_eq!(error.category(), "migration");
    }

    #[test]
    fn test_error_category_serialization() {
        let error = DatabaseError::Serialization {
            message: "Serialization error".to_string(),
        };
        assert_eq!(error.category(), "serialization");
    }

    #[test]
    fn test_error_category_timeout() {
        let error = DatabaseError::Timeout {
            operation: "query".to_string(),
            timeout_secs: 30,
        };
        assert_eq!(error.category(), "timeout");
    }

    #[test]
    fn test_error_category_validation() {
        let error = DatabaseError::Validation {
            field: "email".to_string(),
            message: "Invalid".to_string(),
        };
        assert_eq!(error.category(), "validation");
    }

    #[test]
    fn test_error_category_not_found() {
        let error = DatabaseError::NotFound {
            resource_type: "user".to_string(),
            identifier: "123".to_string(),
        };
        assert_eq!(error.category(), "not_found");
    }

    #[test]
    fn test_error_category_constraint_violation() {
        let error = DatabaseError::ConstraintViolation {
            constraint: "pk".to_string(),
            message: "Violation".to_string(),
        };
        assert_eq!(error.category(), "constraint_violation");
    }

    #[test]
    fn test_error_category_unknown() {
        let error = DatabaseError::Unknown {
            message: "Unknown error".to_string(),
        };
        assert_eq!(error.category(), "unknown");
    }

    #[test]
    fn test_error_severity_critical() {
        let config_error = DatabaseError::Configuration {
            message: "Config".to_string(),
        };
        assert_eq!(config_error.severity(), ErrorSeverity::Critical);

        let migration_error = DatabaseError::Migration {
            message: "Migration".to_string(),
        };
        assert_eq!(migration_error.severity(), ErrorSeverity::Critical);
    }

    #[test]
    fn test_error_severity_high() {
        let pool_error = DatabaseError::ConnectionPool {
            message: "Pool".to_string(),
        };
        assert_eq!(pool_error.severity(), ErrorSeverity::High);

        let conn_error = DatabaseError::Connection {
            message: "Connection".to_string(),
        };
        assert_eq!(conn_error.severity(), ErrorSeverity::High);

        let tx_error = DatabaseError::Transaction {
            message: "Transaction".to_string(),
        };
        assert_eq!(tx_error.severity(), ErrorSeverity::High);
    }

    #[test]
    fn test_error_severity_medium() {
        let constraint_error = DatabaseError::ConstraintViolation {
            constraint: "pk".to_string(),
            message: "Violation".to_string(),
        };
        assert_eq!(constraint_error.severity(), ErrorSeverity::Medium);

        let query_error = DatabaseError::Query {
            query: "SELECT 1".to_string(),
            message: "Error".to_string(),
        };
        assert_eq!(query_error.severity(), ErrorSeverity::Medium);

        let timeout_error = DatabaseError::Timeout {
            operation: "query".to_string(),
            timeout_secs: 30,
        };
        assert_eq!(timeout_error.severity(), ErrorSeverity::Medium);

        let unknown_error = DatabaseError::Unknown {
            message: "Unknown".to_string(),
        };
        assert_eq!(unknown_error.severity(), ErrorSeverity::Medium);
    }

    #[test]
    fn test_error_severity_low() {
        let validation_error = DatabaseError::Validation {
            field: "email".to_string(),
            message: "Invalid".to_string(),
        };
        assert_eq!(validation_error.severity(), ErrorSeverity::Low);

        let not_found_error = DatabaseError::NotFound {
            resource_type: "user".to_string(),
            identifier: "123".to_string(),
        };
        assert_eq!(not_found_error.severity(), ErrorSeverity::Low);

        let serialization_error = DatabaseError::Serialization {
            message: "Serialization failed".to_string(),
        };
        assert_eq!(serialization_error.severity(), ErrorSeverity::Low);
    }

    #[test]
    fn test_error_severity_display() {
        assert_eq!(format!("{}", ErrorSeverity::Low), "LOW");
        assert_eq!(format!("{}", ErrorSeverity::Medium), "MEDIUM");
        assert_eq!(format!("{}", ErrorSeverity::High), "HIGH");
        assert_eq!(format!("{}", ErrorSeverity::Critical), "CRITICAL");
    }

    #[test]
    fn test_error_display_connection_pool() {
        let error = DatabaseError::ConnectionPool {
            message: "Test message".to_string(),
        };
        let display = format!("{}", error);
        assert!(display.contains("Connection pool error"));
        assert!(display.contains("Test message"));
    }

    #[test]
    fn test_error_display_timeout() {
        let error = DatabaseError::Timeout {
            operation: "query_execution".to_string(),
            timeout_secs: 30,
        };
        let display = format!("{}", error);
        assert!(display.contains("Operation timeout"));
        assert!(display.contains("query_execution"));
        assert!(display.contains("30"));
    }

    #[test]
    fn test_error_display_validation() {
        let error = DatabaseError::Validation {
            field: "email".to_string(),
            message: "Invalid format".to_string(),
        };
        let display = format!("{}", error);
        assert!(display.contains("Validation error"));
        assert!(display.contains("email"));
        assert!(display.contains("Invalid format"));
    }

    #[test]
    fn test_error_display_not_found() {
        let error = DatabaseError::NotFound {
            resource_type: "user".to_string(),
            identifier: "id=123".to_string(),
        };
        let display = format!("{}", error);
        assert!(display.contains("Resource not found"));
        assert!(display.contains("user"));
        assert!(display.contains("id=123"));
    }

    #[test]
    fn test_error_display_constraint_violation() {
        let error = DatabaseError::ConstraintViolation {
            constraint: "unique_email".to_string(),
            message: "Duplicate key".to_string(),
        };
        let display = format!("{}", error);
        assert!(display.contains("Constraint violation"));
        assert!(display.contains("unique_email"));
        assert!(display.contains("Duplicate key"));
    }
}

mod query_builder_tests {
    use super::*;

    #[test]
    fn test_query_builder_new() {
        let builder = QueryBuilder::new();
        assert_eq!(builder.sql(), "");
    }

    #[test]
    fn test_query_builder_default() {
        let builder = QueryBuilder::default();
        assert_eq!(builder.sql(), "");
    }

    #[test]
    fn test_select_builder_basic() {
        let query = QueryBuilder::select(&["id", "name"])
            .from("users")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("SELECT id, name"));
        assert!(sql.contains("FROM users"));
    }

    #[test]
    fn test_select_builder_with_where() {
        let query = QueryBuilder::select(&["*"])
            .from("users")
            .where_eq("active", true)
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("WHERE active = $1"));
    }

    #[test]
    fn test_select_builder_with_order_by() {
        let query = QueryBuilder::select(&["*"])
            .from("users")
            .order_by("created_at", OrderDirection::Desc)
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("ORDER BY created_at DESC"));
    }

    #[test]
    fn test_select_builder_with_limit_offset() {
        let query = QueryBuilder::select(&["*"])
            .from("users")
            .limit(10)
            .offset(20)
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("LIMIT 10"));
        assert!(sql.contains("OFFSET 20"));
    }

    #[test]
    fn test_select_builder_with_group_by() {
        let query = QueryBuilder::select(&["status", "COUNT(*)"])
            .from("users")
            .group_by("status")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("GROUP BY status"));
    }

    #[test]
    fn test_select_builder_with_having() {
        let query = QueryBuilder::select(&["status", "COUNT(*)"])
            .from("users")
            .group_by("status")
            .having("COUNT(*) > 10")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("HAVING COUNT(*) > 10"));
    }

    #[test]
    fn test_select_builder_with_inner_join() {
        let query = QueryBuilder::select(&["u.name", "p.title"])
            .from("users u")
            .inner_join("posts p", "u.id = p.user_id")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("INNER JOIN posts p ON u.id = p.user_id"));
    }

    #[test]
    fn test_select_builder_with_left_join() {
        let query = QueryBuilder::select(&["u.name", "p.title"])
            .from("users u")
            .left_join("posts p", "u.id = p.user_id")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("LEFT JOIN posts p ON u.id = p.user_id"));
    }

    #[test]
    fn test_select_builder_missing_from() {
        let result = QueryBuilder::select(&["id", "name"]).build();
        assert!(result.is_err(), "SELECT without FROM should fail");
    }

    #[test]
    fn test_insert_builder_basic() {
        let query = QueryBuilder::insert("users")
            .values(&[("name", "John"), ("email", "john@example.com")])
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("INSERT INTO users"));
        assert!(sql.contains("(name, email)"));
        assert!(sql.contains("VALUES ($1, $2)"));
    }

    #[test]
    fn test_insert_builder_with_returning() {
        let query = QueryBuilder::insert("users")
            .values(&[("name", "John")])
            .returning("id")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("RETURNING id"));
    }

    #[test]
    fn test_insert_builder_with_on_conflict() {
        let query = QueryBuilder::insert("users")
            .values(&[("email", "test@example.com")])
            .on_conflict("(email) DO NOTHING")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("ON CONFLICT (email) DO NOTHING"));
    }

    #[test]
    fn test_update_builder_basic() {
        let query = QueryBuilder::update("users")
            .set("name", "Jane")
            .where_eq("id", 1)
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("UPDATE users"));
        assert!(sql.contains("SET name = $1"));
        assert!(sql.contains("WHERE id = $2"));
    }

    #[test]
    fn test_update_builder_with_returning() {
        let query = QueryBuilder::update("users")
            .set("name", "Jane")
            .where_eq("id", 1)
            .returning("*")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("RETURNING *"));
    }

    #[test]
    fn test_update_builder_missing_set() {
        let result = QueryBuilder::update("users").where_eq("id", 1).build();

        assert!(result.is_err(), "UPDATE without SET should fail");
    }

    #[test]
    fn test_delete_builder_basic() {
        let query = QueryBuilder::delete("users")
            .where_eq("id", 1)
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("DELETE FROM users"));
        assert!(sql.contains("WHERE id = $1"));
    }

    #[test]
    fn test_delete_builder_with_where_raw() {
        let query = QueryBuilder::delete("users")
            .where_raw("created_at < NOW() - INTERVAL '1 year'")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("WHERE created_at < NOW() - INTERVAL '1 year'"));
    }

    #[test]
    fn test_delete_builder_with_returning() {
        let query = QueryBuilder::delete("users")
            .where_eq("id", 1)
            .returning("name")
            .build()
            .unwrap();

        let sql = query.sql();
        assert!(sql.contains("RETURNING name"));
    }

    #[test]
    fn test_order_direction_display() {
        assert_eq!(format!("{}", OrderDirection::Asc), "ASC");
        assert_eq!(format!("{}", OrderDirection::Desc), "DESC");
    }
}

mod config_tests {
    use super::*;

    #[test]
    fn test_database_config_new() {
        let config = DatabaseConfig::new();
        assert!(config.application_name.is_some());
        assert!(!config.enable_query_logging);
        assert!(!config.url.is_empty());
    }

    #[test]
    fn test_database_config_validation_empty_url() {
        let mut config = DatabaseConfig::new();
        config.url = String::new();

        let result = config.validate();
        assert!(result.is_err(), "Empty URL should fail validation");
    }

    #[test]
    fn test_pool_config_default() {
        let config = PoolConfig::default();
        assert!(config.max_connections > 0);
        assert!(config.min_connections > 0);
        assert!(config.min_connections <= config.max_connections);
        assert!(config.health_check_enabled);
        assert!(config.test_before_acquire);
    }

    #[test]
    fn test_transaction_config_default() {
        let config = TransactionConfig::default();
        assert!(config.max_retries > 0);
        assert!(config.enable_retry);
        assert!(config.default_timeout_secs > 0);
        assert!(config.max_savepoints > 0);
        assert!(!config.isolation_level.is_empty());
    }
}
