//! Generic database abstraction for SQLite

use sqlx::{Pool, Sqlite, SqlitePool};

use crate::error::{infrastructure, ControlCenterError, Result};

/// Database configuration
#[derive(Debug, Clone)]
pub struct DatabaseConfig {
    /// Database URL (e.g., "sqlite:control-center.db" or ":memory:")
    pub url: String,
    /// Maximum number of connections in the pool
    pub max_connections: u32,
}

impl Default for DatabaseConfig {
    fn default() -> Self {
        Self {
            url: "sqlite:control-center.db".to_string(),
            max_connections: 5,
        }
    }
}

/// Database connection pool wrapper
#[derive(Clone)]
pub struct Database {
    pool: Pool<Sqlite>,
}

impl Database {
    /// Create new database connection pool
    pub async fn new(config: DatabaseConfig) -> Result<Self> {
        let pool = SqlitePool::connect_with(
            sqlx::sqlite::SqliteConnectOptions::new()
                .filename(&config.url)
                .create_if_missing(true),
        )
        .await
        .map_err(|e| {
            ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Internal(
                format!("Failed to connect to database: {}", e),
            ))
        })?;

        Ok(Self { pool })
    }

    /// Get pool reference
    pub fn pool(&self) -> &Pool<Sqlite> {
        &self.pool
    }

    /// Health check
    pub async fn health_check(&self) -> Result<()> {
        sqlx::query("SELECT 1")
            .execute(&self.pool)
            .await
            .map_err(|e| {
                ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Internal(
                    format!("Database health check failed: {}", e),
                ))
            })?;

        Ok(())
    }

    /// Close database connections
    pub async fn close(self) {
        self.pool.close().await;
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_database_creation() {
        let config = DatabaseConfig {
            url: ":memory:".to_string(),
            max_connections: 5,
        };

        let db = Database::new(config).await;
        assert!(db.is_ok());
    }

    #[tokio::test]
    async fn test_health_check() {
        let config = DatabaseConfig {
            url: ":memory:".to_string(),
            max_connections: 5,
        };

        let db = Database::new(config).await.unwrap();
        let result = db.health_check().await;
        assert!(result.is_ok());
    }
}
