//! Server initialization and startup
//!
//! This module handles environment setup, configuration loading, logging setup,
//! Leptos configuration, and the final server startup process.

use rustelo_core_lib::routing::get_routing_config;
use rustelo_core_lib::routing::tracker::{init_navigation_tracker, NavigationTrackingConfig};
use tracing;

use crate::config::{Config, Protocol};
use crate::run::SiteOptions;

/// Set up environment variables, logging, and panic handling
pub async fn setup_environment() -> Result<(), Box<dyn std::error::Error>> {
    // Load environment variables
    dotenv::dotenv().ok();

    Ok(())
}

/// Load and validate server configuration
pub async fn load_and_validate_config() -> Result<Config, Box<dyn std::error::Error>> {
    // Load configuration from TOML file with environment overrides
    let config = match Config::load() {
        Ok(config) => config,
        Err(e) => {
            eprintln!("Failed to load configuration: {e}");
            std::process::exit(1);
        }
    };

    tracing::info!("Configuration loaded successfully");

    // Expose the configured site name (brand) to functions without Config access
    // (SSR shell, route title builder) — config-driven, no env var.
    crate::utils::set_site_name(config.app.name.clone());

    tracing::info!("Server: {}:{}", config.server.host, config.server.port);
    tracing::info!("Environment: {:?}", config.server.environment);
    tracing::info!("Protocol: {:?}", config.server.protocol);

    // Export the resolved (absolute) nav_log_dir so server functions can read it
    // via std::env::var("RUSTELO_NAV_LOG_DIR") without access to Config.
    // Priority already applied: RUSTELO_NAV_LOG_DIR env > logs.ncl > default.
    #[allow(unsafe_code)]
    // SAFETY: single-threaded at this point — no other threads have been spawned yet.
    unsafe {
        std::env::set_var("RUSTELO_NAV_LOG_DIR", &config.logs.nav_log_dir);
    }
    tracing::info!("Navigation logs: {}", config.logs.nav_log_dir);

    Ok(config)
}

/// Initialize logging and panic handling after config is loaded
pub fn setup_logging_and_panic_handling(config: &Config) -> Result<(), Box<dyn std::error::Error>> {
    // Set up tracing subscriber with configured log level
    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(&config.server.log_level)),
        )
        .init();

    std::panic::set_hook(Box::new(|info| {
        let backtrace = std::backtrace::Backtrace::force_capture();
        tracing::error!("PANIC: {}\nBacktrace:\n{}", info, backtrace);
    }));

    Ok(())
}

/// Initialize navigation tracking system
pub fn initialize_navigation_tracking(config: &Config) -> Result<(), Box<dyn std::error::Error>> {
    // Create navigation tracking configuration from server config
    let tracking_config = NavigationTrackingConfig {
        enabled: config.routing.enable_tracking.unwrap_or(true),
        log_path: config.routing.tracking_log_path.clone(),
        max_events_in_memory: config.routing.max_events_in_memory.unwrap_or(1000),
        slow_threshold_ms: config.routing.slow_resolution_threshold_ms.unwrap_or(10),
        enable_console_debug: config
            .routing
            .enable_console_debug
            .unwrap_or(cfg!(debug_assertions)),
    };

    // Initialize the global navigation tracker
    init_navigation_tracker(tracking_config);

    tracing::info!("Navigation tracking system initialized");
    tracing::debug!(
        "Tracking config: enabled={}, max_events={}, slow_threshold={}ms",
        config.routing.enable_tracking.unwrap_or(true),
        config.routing.max_events_in_memory.unwrap_or(1000),
        config.routing.slow_resolution_threshold_ms.unwrap_or(10)
    );

    Ok(())
}

/// Build `SiteOptions` from server config.
///
/// Contains the minimum info needed by the shell renderers and static-file
/// serving (listen address and site root). When `leptos-hydration` is active
/// the full `LeptosOptions` is derived from `SiteOptions` via the `From` impl.
pub fn setup_site_options(config: &Config) -> Result<SiteOptions, Box<dyn std::error::Error>> {
    let site_addr = config
        .server_address()
        .parse()
        .map_err(|e| format!("Invalid server address: {e}"))?;
    let site_root = std::env::var("LEPTOS_SITE_ROOT").unwrap_or_else(|_| "site".to_string());

    let routing_config = get_routing_config();
    tracing::info!(
        "SSR routing configuration loaded with {} routes",
        routing_config.routes.len()
    );

    Ok(SiteOptions {
        site_addr,
        site_root,
    })
}

/// Start the server with the configured protocol (HTTP or HTTPS)
pub async fn start_server(
    app: axum::Router,
    config: &Config,
) -> Result<(), Box<dyn std::error::Error>> {
    let addr = config.server_address();
    tracing::info!("Server starting on {}", addr);
    tracing::info!("Environment: {:?}", config.server.environment);
    tracing::info!("Log level: {}", config.server.log_level);
    tracing::info!("Security features enabled: CSRF, Rate Limiting, Security Headers");
    tracing::info!("Application: {} v{}", config.app.name, config.app.version);

    #[cfg(any(feature = "auth", feature = "content-db"))]
    tracing::info!("Database URL: {}", config.database.url);

    tracing::info!("Server directories:");
    tracing::info!("  Public: {}", config.server_dirs.public_dir);
    tracing::info!("  Uploads: {}", config.server_dirs.uploads_dir);
    tracing::info!("  Logs: {}", config.server_dirs.logs_dir);
    tracing::info!("  Cache: {}", config.server_dirs.cache_dir);

    // Health check endpoints
    tracing::info!("Health check endpoints available:");
    tracing::info!("  /health - Comprehensive health check");
    tracing::info!("  /health/live - Liveness probe");
    tracing::info!("  /health/ready - Readiness probe");

    // Feature-specific logging
    #[cfg(feature = "metrics")]
    if config.app.enable_metrics {
        tracing::info!("Metrics collection enabled");
        tracing::info!("Metrics endpoints available:");
        tracing::info!("  /metrics - Prometheus metrics");
        tracing::info!("  /metrics/health - Health metrics (JSON)");
    }

    #[cfg(feature = "auth")]
    tracing::info!("Authentication endpoints available at: /api/auth/*");

    #[cfg(feature = "content-db")]
    tracing::info!("Content management endpoints available at: /api/content/*");

    #[cfg(feature = "email")]
    tracing::info!("Email service endpoints available at: /api/email/*");

    #[cfg(not(feature = "auth"))]
    tracing::info!("Authentication disabled - no auth endpoints available");

    #[cfg(not(feature = "content-db"))]
    tracing::info!("Database content disabled - using static content only");

    #[cfg(not(feature = "email"))]
    tracing::info!("Email service disabled - no email functionality available");

    match config.server.protocol {
        Protocol::Http => {
            let listener = match tokio::net::TcpListener::bind(&addr).await {
                Ok(listener) => listener,
                Err(e) => {
                    tracing::error!("Failed to bind to address {}: {}", addr, e);
                    std::process::exit(1);
                }
            };
            tracing::info!("Listening on http://{}", &addr);
            if let Err(e) = axum::serve(listener, app).await {
                tracing::error!("Server failed: {}", e);
                std::process::exit(1);
            }
        }
        Protocol::Https => {
            #[cfg(feature = "tls")]
            {
                let tls_config = config
                    .server
                    .tls
                    .as_ref()
                    .ok_or("TLS configuration is required for HTTPS but not provided")?;
                let rustls_config = match crate::config::create_tls_config(
                    &tls_config.cert_path,
                    &tls_config.key_path,
                )
                .await
                {
                    Ok(config) => config,
                    Err(e) => {
                        tracing::error!("Failed to create TLS config: {}", e);
                        std::process::exit(1);
                    }
                };

                tracing::info!("Listening on https://{}", &addr);
                tracing::info!("TLS certificate: {}", tls_config.cert_path.display());
                tracing::info!("TLS private key: {}", tls_config.key_path.display());

                let socket_addr = addr
                    .parse()
                    .map_err(|e| format!("Invalid socket address '{}': {}", addr, e))?;
                if let Err(e) = axum_rustelo_server::bind_rustls(socket_addr, rustls_config)
                    .serve(app.into_make_service())
                    .await
                {
                    tracing::error!("HTTPS server failed: {}", e);
                    std::process::exit(1);
                }
            }
            #[cfg(not(feature = "tls"))]
            {
                tracing::error!("HTTPS protocol requested but TLS feature is not enabled");
                tracing::error!("Please enable the 'tls' feature or use HTTP protocol");
                std::process::exit(1);
            }
        }
    }

    Ok(())
}
