//! Hosting Gateway Server
//!
//! HTTP server that routes requests based on Host header and serves
//! content from Synor Storage.

mod handler;
mod middleware;
mod ssl;

pub use handler::RequestHandler;
pub use middleware::{RateLimiter, CacheControl};
pub use ssl::SslConfig;

use crate::router::HostingRouter;
use crate::error::{Error, Result};
use axum::extract::State;
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::sync::RwLock;

/// Hosting gateway configuration
#[derive(Debug, Clone)]
pub struct GatewayConfig {
    /// Listen address
    pub listen_addr: SocketAddr,
    /// Hosting domain (e.g., "synor.cc")
    pub hosting_domain: String,
    /// Storage gateway URL
    pub storage_gateway_url: String,
    /// Enable HTTPS
    pub https_enabled: bool,
    /// SSL certificate path
    pub ssl_cert_path: Option<String>,
    /// SSL key path
    pub ssl_key_path: Option<String>,
    /// Rate limit (requests per second per IP)
    pub rate_limit: u32,
    /// Max request body size
    pub max_body_size: usize,
    /// Enable request logging
    pub enable_logging: bool,
    /// Cache TTL for static assets (seconds)
    pub cache_ttl: u64,
}

impl Default for GatewayConfig {
    fn default() -> Self {
        Self {
            listen_addr: "0.0.0.0:8080".parse().unwrap(),
            hosting_domain: "synor.cc".to_string(),
            storage_gateway_url: "http://localhost:8180".to_string(),
            https_enabled: false,
            ssl_cert_path: None,
            ssl_key_path: None,
            rate_limit: 100,
            max_body_size: 10 * 1024 * 1024, // 10MB
            enable_logging: true,
            cache_ttl: 3600,
        }
    }
}

/// Gateway server state
pub struct GatewayState {
    /// Configuration
    pub config: GatewayConfig,
    /// Hosting router
    pub router: RwLock<HostingRouter>,
    /// Rate limiter
    pub rate_limiter: RateLimiter,
    /// HTTP client for storage gateway
    pub http_client: reqwest::Client,
}

impl GatewayState {
    /// Create new gateway state
    pub fn new(config: GatewayConfig) -> Self {
        let router = HostingRouter::new(config.hosting_domain.clone());
        let rate_limiter = RateLimiter::new(config.rate_limit);
        let http_client = reqwest::Client::builder()
            .timeout(std::time::Duration::from_secs(30))
            .build()
            .expect("Failed to create HTTP client");

        Self {
            config,
            router: RwLock::new(router),
            rate_limiter,
            http_client,
        }
    }
}

/// Hosting gateway server
pub struct HostingGateway {
    state: Arc<GatewayState>,
}

impl HostingGateway {
    /// Create a new hosting gateway
    pub fn new(config: GatewayConfig) -> Self {
        Self {
            state: Arc::new(GatewayState::new(config)),
        }
    }

    /// Get gateway state
    pub fn state(&self) -> Arc<GatewayState> {
        Arc::clone(&self.state)
    }

    /// Start the gateway server
    pub async fn start(&self) -> Result<()> {
        use axum::{
            Router,
            routing::get,
        };

        let state = Arc::clone(&self.state);
        let addr = state.config.listen_addr;

        // Build router
        let app = Router::new()
            .route("/health", get(health_check))
            .route("/info", get(gateway_info))
            .fallback(handler::handle_request)
            .with_state(state);

        // Start server
        if self.state.config.enable_logging {
            eprintln!("Hosting gateway listening on {}", addr);
        }

        let listener = tokio::net::TcpListener::bind(addr)
            .await
            .map_err(|e| Error::Io(e))?;

        axum::serve(listener, app)
            .await
            .map_err(|e| Error::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))?;

        Ok(())
    }
}

/// Health check endpoint
async fn health_check() -> &'static str {
    "OK"
}

/// Gateway info endpoint
async fn gateway_info(
    State(state): State<Arc<GatewayState>>,
) -> axum::Json<serde_json::Value> {
    axum::Json(serde_json::json!({
        "gateway": "synor-hosting",
        "version": env!("CARGO_PKG_VERSION"),
        "domain": state.config.hosting_domain,
        "https": state.config.https_enabled,
    }))
}

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

    #[test]
    fn test_default_config() {
        let config = GatewayConfig::default();
        assert_eq!(config.hosting_domain, "synor.cc");
        assert_eq!(config.rate_limit, 100);
        assert!(!config.https_enabled);
    }

    #[test]
    fn test_gateway_state() {
        let config = GatewayConfig::default();
        let state = GatewayState::new(config);
        assert_eq!(state.config.hosting_domain, "synor.cc");
    }
}
