//! Database Gateway HTTP Server.

use crate::gateway::auth::{AuthConfig, AuthMiddleware};
use crate::gateway::router::{create_router, AppState};
use crate::{DatabaseConfig, DatabaseManager};

use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::net::TcpListener;

/// Gateway server configuration.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GatewayConfig {
    /// Listen address.
    pub host: String,
    /// Listen port.
    pub port: u16,
    /// Authentication configuration.
    pub auth: AuthConfig,
    /// Maximum request body size (bytes).
    pub max_body_size: usize,
    /// Request timeout (seconds).
    pub request_timeout: u64,
    /// Enable CORS.
    pub cors_enabled: bool,
    /// Allowed origins for CORS.
    pub cors_origins: Vec<String>,
}

impl Default for GatewayConfig {
    fn default() -> Self {
        Self {
            host: "0.0.0.0".to_string(),
            port: 8484,
            auth: AuthConfig::default(),
            max_body_size: 10 * 1024 * 1024, // 10 MB
            request_timeout: 30,
            cors_enabled: true,
            cors_origins: vec!["*".to_string()],
        }
    }
}

/// Database Gateway Server.
pub struct GatewayServer {
    /// Configuration.
    config: GatewayConfig,
    /// Database manager.
    db_manager: Arc<DatabaseManager>,
    /// Auth middleware.
    auth: Arc<AuthMiddleware>,
}

impl GatewayServer {
    /// Creates a new gateway server.
    pub fn new(config: GatewayConfig) -> Self {
        let auth = Arc::new(AuthMiddleware::new(config.auth.clone()));
        let db_manager = Arc::new(DatabaseManager::new());

        Self {
            config,
            db_manager,
            auth,
        }
    }

    /// Creates a server with an existing database manager.
    pub fn with_db_manager(config: GatewayConfig, db_manager: Arc<DatabaseManager>) -> Self {
        let auth = Arc::new(AuthMiddleware::new(config.auth.clone()));

        Self {
            config,
            db_manager,
            auth,
        }
    }

    /// Returns the database manager.
    pub fn db_manager(&self) -> Arc<DatabaseManager> {
        self.db_manager.clone()
    }

    /// Returns the auth middleware.
    pub fn auth(&self) -> Arc<AuthMiddleware> {
        self.auth.clone()
    }

    /// Creates a default database for convenience.
    pub fn ensure_default_database(&self) -> Result<(), crate::error::DatabaseError> {
        let config = DatabaseConfig {
            name: "default".to_string(),
            owner: [0u8; 32],
            vector_enabled: true,
            vector_dimensions: 1536, // OpenAI embedding size
            ..Default::default()
        };

        match self.db_manager.create(config) {
            Ok(_) => Ok(()),
            Err(crate::error::DatabaseError::AlreadyExists(_)) => Ok(()), // Already exists is fine
            Err(e) => Err(e),
        }
    }

    /// Starts the HTTP server.
    pub async fn run(&self) -> Result<(), std::io::Error> {
        let addr: SocketAddr = format!("{}:{}", self.config.host, self.config.port)
            .parse()
            .expect("Invalid address");

        // Ensure default database exists
        if let Err(e) = self.ensure_default_database() {
            tracing::error!("Failed to create default database: {}", e);
        }

        let state = Arc::new(AppState::new(
            self.db_manager.clone(),
            self.auth.clone(),
        ));

        let app = create_router(state);

        tracing::info!("Synor Database Gateway listening on http://{}", addr);

        let listener = TcpListener::bind(addr).await?;
        axum::serve(listener, app).await
    }

    /// Creates a test server (for integration tests).
    #[cfg(test)]
    pub fn for_testing() -> Self {
        let config = GatewayConfig {
            host: "127.0.0.1".to_string(),
            port: 0, // Random port
            auth: AuthConfig {
                required: false,
                allow_anonymous_read: true,
                ..Default::default()
            },
            ..Default::default()
        };

        Self::new(config)
    }
}

impl std::fmt::Debug for GatewayServer {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("GatewayServer")
            .field("config", &self.config)
            .finish()
    }
}

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

    #[test]
    fn test_gateway_config_default() {
        let config = GatewayConfig::default();
        assert_eq!(config.port, 8484);
        assert!(config.cors_enabled);
    }

    #[test]
    fn test_gateway_server_creation() {
        let server = GatewayServer::new(GatewayConfig::default());
        assert!(server.ensure_default_database().is_ok());
    }

    #[tokio::test]
    async fn test_ensure_default_database() {
        let server = GatewayServer::for_testing();
        assert!(server.ensure_default_database().is_ok());

        // Should not error on second call
        assert!(server.ensure_default_database().is_ok());
    }
}
