//! Server layer - HTTP transport
//!
//! This module provides the HTTP server implementation using Hyper.
//! It handles:
//!
//! - TCP connection management
//! - HTTP/1.1 protocol handling
//! - Request/response conversion
//! - Graceful shutdown
//!
//! # Architecture
//!
//! - `Server` - Main server struct with configuration
//! - `RuxnoService` - Bridges Hyper and domain layer
//! - `TcpListener` - TCP connection abstraction
//! - `ServerConfig` - Server configuration
//! - `GracefulShutdown` - Shutdown coordination
//! - `accept_loop` - `ConnectionLimiter`, `ConnectionTracker`, `ConnectionTask`

mod accept_loop;
mod config;
mod listener;
mod service;
mod shutdown;

pub use config::{ServerConfig, TlsConfig};
pub use listener::TcpListener;
pub use service::RuxnoService;
pub use shutdown::GracefulShutdown;

use crate::app::App;
use crate::core::CoreError;
use accept_loop::{ConnectionLimiter, ConnectionTask, ConnectionTracker};
use std::sync::Arc;
use tokio::sync::broadcast;

/// HTTP Server
///
/// Wraps a Ruxno App and provides HTTP server functionality using Hyper.
/// Supports configuration through builder pattern and graceful shutdown.
///
/// # Examples
///
/// ```rust,ignore
/// use ruxno::app::App;
/// use ruxno::server::Server;
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
///     let mut app = App::new();
///     app.get("/", |ctx| async move { Ok(ctx.text("Hello!")) });
///     Server::new(app).listen("127.0.0.1:3000").await?;
///     Ok(())
/// }
/// ```
pub struct Server<E = ()> {
    app: Arc<App<E>>,
    config: ServerConfig,
}

impl<E> Server<E>
where
    E: Send + Sync + 'static + Clone,
{
    /// Create new server from an App.
    pub fn new(app: App<E>) -> Self {
        Self {
            app: Arc::new(app),
            config: ServerConfig::default(),
        }
    }

    /// Configure server with custom settings.
    pub fn with_config(mut self, config: ServerConfig) -> Self {
        self.config = config;
        self
    }

    /// Get a reference to the server configuration.
    pub fn config(&self) -> &ServerConfig {
        &self.config
    }

    /// Get a reference to the app.
    pub fn app(&self) -> &Arc<App<E>> {
        &self.app
    }

    /// Start listening for connections (Ctrl+C shutdown).
    pub async fn listen(self, addr: &str) -> Result<(), CoreError> {
        let shutdown = async {
            tokio::signal::ctrl_c()
                .await
                .expect("Failed to install Ctrl+C handler");
            println!("\n👋 Shutting down gracefully...");
        };
        self.listen_with_shutdown(addr, shutdown).await
    }

    /// Start listening with a custom shutdown signal.
    ///
    /// Implements graceful shutdown:
    /// - Stops accepting new connections when `shutdown` resolves.
    /// - Broadcasts a signal to all in-flight connections so they finish their
    ///   current request before closing.
    /// - Waits up to `config.shutdown_timeout()` for all connections to drain.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// let (tx, rx) = tokio::sync::oneshot::channel();
    /// tokio::spawn(async move {
    ///     Server::new(app)
    ///         .listen_with_shutdown("127.0.0.1:3000", async { rx.await.ok(); })
    ///         .await
    /// });
    /// tx.send(()).ok(); // trigger shutdown
    /// ```
    pub async fn listen_with_shutdown<F>(self, addr: &str, shutdown: F) -> Result<(), CoreError>
    where
        F: std::future::Future<Output = ()> + Send + 'static,
    {
        // ── Bind ──────────────────────────────────────────────────────────────
        let listener = TcpListener::bind(addr)
            .await
            .map_err(|e| CoreError::Internal(format!("Failed to bind to {}: {}", addr, e)))?;

        let local_addr = listener
            .local_addr()
            .map_err(|e| CoreError::Internal(format!("Failed to get local address: {}", e)))?;

        println!("🚀 Ruxno server listening on http://{}", local_addr);

        // ── Infrastructure ────────────────────────────────────────────────────
        let service = RuxnoService::new(Arc::clone(&self.app), self.config.production_mode());
        let limiter =
            ConnectionLimiter::new(self.config.max_connections(), self.config.production_mode());
        let tracker = ConnectionTracker::new();
        let (shutdown_tx, _) = broadcast::channel::<()>(1);

        if let Some(max) = self.config.max_connections() {
            println!("📊 Connection limit: {} concurrent connections", max);
        } else {
            println!("⚠️  No connection limit (unlimited connections)");
        }

        let max_body_size = self.config.max_body_size();
        let max_headers = self.config.max_headers();
        let shutdown_timeout = self.config.shutdown_timeout();

        tokio::pin!(shutdown);

        // ── Accept loop ───────────────────────────────────────────────────────
        loop {
            tokio::select! {
                result = listener.accept() => {
                    let (stream, peer_addr) = result.map_err(|e| {
                        CoreError::Internal(format!("Failed to accept connection: {}", e))
                    })?;

                    // Enforce connection limit.
                    let permit = match limiter.try_acquire() {
                        Ok(p) => p,
                        Err(()) => {
                            limiter.reject_connection(stream, peer_addr);
                            continue;
                        }
                    };

                    tracker.increment();
                    ConnectionTask::builder()
                        .stream(stream)
                        .peer_addr(peer_addr)
                        .service(service.clone())
                        .max_body_size(max_body_size)
                        .max_headers(max_headers)
                        .permit(permit)
                        .tracker(tracker.clone())
                        .shutdown_rx(shutdown_tx.subscribe())
                        .build()
                        .spawn();
                }

                _ = &mut shutdown => {
                    println!("🛑 Shutdown signal received");
                    println!("📡 Stopped accepting new connections");

                    // Signal all in-flight connections to finish gracefully.
                    let _ = shutdown_tx.send(());

                    let active = tracker.active();
                    if active > 0 {
                        println!("⏳ Waiting for {} active connection(s) to complete...", active);
                        if tracker.drain(shutdown_timeout).await {
                            println!("✅ All connections closed gracefully");
                        } else {
                            println!(
                                "⚠️  Shutdown timeout reached after {:?}; {} connection(s) forcefully closed",
                                shutdown_timeout,
                                tracker.active()
                            );
                        }
                    } else {
                        println!("✅ No active connections");
                    }

                    println!("👋 Server stopped");
                    break;
                }
            }
        }

        Ok(())
    }
}

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

    #[test]
    fn test_server_creation() {
        let app = App::new();
        let server = Server::new(app);
        assert!(Arc::strong_count(server.app()) >= 1);
    }

    #[test]
    fn test_server_with_config() {
        let app = App::new();
        let config = ServerConfig::new().with_port(8080);
        let server = Server::new(app).with_config(config);
        assert_eq!(server.config().bind_addr(), "127.0.0.1:8080");
    }

    #[test]
    fn test_server_config_accessor() {
        let app = App::new();
        let server = Server::new(app);
        assert_eq!(server.config().bind_addr(), "127.0.0.1:3000");
    }

    #[test]
    fn test_server_app_accessor() {
        let app = App::new();
        let server = Server::new(app);
        assert!(Arc::strong_count(server.app()) >= 1);
    }

    #[test]
    fn test_server_default_config() {
        let app = App::new();
        let server = Server::new(app);
        let config = server.config();
        assert_eq!(config.bind_addr(), "127.0.0.1:3000");
        assert_eq!(config.max_body_size(), 1024 * 1024);
    }
}
