//! HTTP Server implementation for AT-Jet

use {crate::error::{JetError,
                    Result},
     axum::Router,
     std::net::SocketAddr,
     tokio::net::TcpListener,
     tower_http::{compression::CompressionLayer,
                  cors::{Any,
                         CorsLayer},
                  trace::TraceLayer},
     tracing::info};

/// AT-Jet HTTP Server
///
/// A high-performance HTTP server optimized for Protobuf APIs.
///
/// # Example
///
/// ```rust,no_run
/// use at_jet::prelude::*;
///
/// #[tokio::main]
/// async fn main() -> anyhow::Result<()> {
///     let server = JetServer::new()
///         .route("/api/health", get(health_check))
///         .with_cors()
///         .with_compression()
///         .with_tracing();
///
///     server.serve("0.0.0.0:8080").await?;
///     Ok(())
/// }
///
/// async fn health_check() -> &'static str {
///     "OK"
/// }
/// ```
pub struct JetServer {
  router:              Router,
  cors_layer:          Option<CorsLayer>,
  compression_enabled: bool,
  tracing_enabled:     bool,
}

impl JetServer {
  /// Create a new JetServer instance
  pub fn new() -> Self {
    Self {
      router:              Router::new(),
      cors_layer:          None,
      compression_enabled: false,
      tracing_enabled:     false,
    }
  }

  /// Add a route to the server
  ///
  /// # Example
  ///
  /// ```rust,ignore
  /// use at_jet::prelude::*;
  ///
  /// let server = JetServer::new()
  ///     .route("/api/users", get(list_users).post(create_user))
  ///     .route("/api/users/:id", get(get_user).delete(delete_user));
  /// ```
  pub fn route(mut self, path: &str, method_router: axum::routing::MethodRouter) -> Self {
    self.router = self.router.route(path, method_router);
    self
  }

  /// Merge another router into this server
  pub fn merge(mut self, router: Router) -> Self {
    self.router = self.router.merge(router);
    self
  }

  /// Nest a router under a path prefix
  ///
  /// # Example
  ///
  /// ```rust,ignore
  /// use at_jet::prelude::*;
  ///
  /// let api_routes = Router::new()
  ///     .route("/users", get(list_users))
  ///     .route("/posts", get(list_posts));
  ///
  /// let server = JetServer::new()
  ///     .nest("/api/v1", api_routes);
  /// ```
  pub fn nest(mut self, path: &str, router: Router) -> Self {
    self.router = self.router.nest(path, router);
    self
  }

  /// Enable CORS with permissive defaults (suitable for development)
  ///
  /// This allows any origin, method, and header. For production,
  /// use `with_cors_config()` for fine-grained control.
  ///
  /// # Example
  ///
  /// ```rust,ignore
  /// let server = JetServer::new()
  ///     .route("/api/users", get(list_users))
  ///     .with_cors();  // Allow all origins (development only)
  /// ```
  pub fn with_cors(mut self) -> Self {
    self.cors_layer = Some(CorsLayer::new().allow_origin(Any).allow_methods(Any).allow_headers(Any));
    self
  }

  /// Enable CORS with custom configuration (recommended for production)
  ///
  /// # Example
  ///
  /// ```rust,ignore
  /// use tower_http::cors::{CorsLayer, AllowOrigin};
  /// use http::{HeaderValue, Method};
  ///
  /// let cors = CorsLayer::new()
  ///     .allow_origin([
  ///         "https://app.example.com".parse::<HeaderValue>().unwrap(),
  ///         "https://admin.example.com".parse::<HeaderValue>().unwrap(),
  ///     ])
  ///     .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])
  ///     .allow_headers([http::header::CONTENT_TYPE, http::header::AUTHORIZATION])
  ///     .allow_credentials(true)
  ///     .max_age(Duration::from_secs(3600));
  ///
  /// let server = JetServer::new()
  ///     .route("/api/users", get(list_users))
  ///     .with_cors_config(cors);
  /// ```
  pub fn with_cors_config(mut self, cors: CorsLayer) -> Self {
    self.cors_layer = Some(cors);
    self
  }

  /// Enable response compression (gzip)
  pub fn with_compression(mut self) -> Self {
    self.compression_enabled = true;
    self
  }

  /// Enable request/response tracing
  ///
  /// This adds detailed logging for HTTP requests including:
  /// - Request method, URI, and version
  /// - Response status code
  /// - Request duration
  ///
  /// Requires a tracing subscriber to be initialized.
  ///
  /// # Example
  ///
  /// ```rust,ignore
  /// use tracing_subscriber::EnvFilter;
  ///
  /// // Initialize tracing subscriber
  /// tracing_subscriber::fmt()
  ///     .with_env_filter(EnvFilter::from_default_env())
  ///     .init();
  ///
  /// let server = JetServer::new()
  ///     .route("/api/users", get(list_users))
  ///     .with_tracing();
  /// ```
  pub fn with_tracing(mut self) -> Self {
    self.tracing_enabled = true;
    self
  }

  /// Add a custom middleware layer to the server
  ///
  /// This method allows you to add any tower-compatible middleware layer.
  ///
  /// # Example - Request Timeout
  ///
  /// ```rust,ignore
  /// use std::time::Duration;
  /// use tower_http::timeout::TimeoutLayer;
  ///
  /// let server = JetServer::new()
  ///     .route("/api/users", get(list_users))
  ///     .layer(TimeoutLayer::new(Duration::from_secs(30)));
  /// ```
  ///
  /// # Example - Custom Authentication Middleware
  ///
  /// ```rust,ignore
  /// use axum::{middleware, http::Request, response::Response};
  ///
  /// async fn auth_middleware<B>(
  ///     request: Request<B>,
  ///     next: axum::middleware::Next<B>,
  /// ) -> Response {
  ///     // Check authentication here
  ///     next.run(request).await
  /// }
  ///
  /// let server = JetServer::new()
  ///     .route("/api/users", get(list_users))
  ///     .layer(middleware::from_fn(auth_middleware));
  /// ```
  pub fn layer<L>(mut self, layer: L) -> Self
  where
    L: tower::Layer<axum::routing::Route> + Clone + Send + 'static,
    L::Service: tower::Service<
        axum::extract::Request,
        Response = axum::response::Response,
        Error = std::convert::Infallible,
      > + Clone
      + Send
      + 'static,
    <L::Service as tower::Service<axum::extract::Request>>::Future: Send + 'static, {
    self.router = self.router.layer(layer);
    self
  }

  /// Get the router for advanced customization
  pub fn into_router(self) -> Router {
    self.router
  }

  /// Start the server
  ///
  /// # Arguments
  ///
  /// * `addr` - Address to bind to (e.g., "0.0.0.0:8080")
  ///
  /// # Example
  ///
  /// ```rust,no_run
  /// use at_jet::prelude::*;
  ///
  /// #[tokio::main]
  /// async fn main() -> anyhow::Result<()> {
  ///     let server = JetServer::new()
  ///         .route("/health", get(|| async { "OK" }));
  ///
  ///     server.serve("0.0.0.0:8080").await?;
  ///     Ok(())
  /// }
  /// ```
  pub async fn serve(self, addr: &str) -> Result<()> {
    let mut router = self.router;

    // Apply middleware layers
    if let Some(cors) = self.cors_layer {
      router = router.layer(cors);
    }

    if self.compression_enabled {
      router = router.layer(CompressionLayer::new());
    }

    if self.tracing_enabled {
      router = router.layer(TraceLayer::new_for_http());
    }

    let addr: SocketAddr = addr
      .parse()
      .map_err(|e| JetError::ServerBind(format!("Invalid address: {}", e)))?;

    let listener = TcpListener::bind(addr)
      .await
      .map_err(|e| JetError::ServerBind(format!("Failed to bind: {}", e)))?;

    info!("AT-Jet server listening on {}", addr);

    axum::serve(listener, router)
      .await
      .map_err(|e| JetError::ServerBind(format!("Server error: {}", e)))?;

    Ok(())
  }
}

impl Default for JetServer {
  fn default() -> Self {
    Self::new()
  }
}
