//! Linux Patch API - Main Entry Point
//!
//! Secure remote package management API for Linux systems.
//!
//! # Configuration
//!
//! Configuration is loaded from `/etc/linux_patch_api/config.yaml` by default.
//! Use `--config` flag to specify a custom configuration path.
//!
//! # Security
//!
//! - mTLS authentication required on port 12443
//! - IP whitelist enforced (deny by default)
//! - Detailed audit logging

use actix_web::middleware::Logger;
use actix_web::{web, App, HttpServer};
use anyhow::Result;
use clap::Parser;
use std::net::TcpListener;
use std::sync::Arc;
use tracing::{error, info, warn};

use linux_patch_api::api::{configure_api_routes, configure_health_route};
use linux_patch_api::auth::{mtls, MtlsMiddleware, WhitelistManager};
use linux_patch_api::packages::create_backend;
use linux_patch_api::{init_logging, AppConfig, JobManager};

/// Linux Patch API CLI arguments
#[derive(Parser, Debug)]
#[command(name = "linux-patch-api")]
#[command(version = env!("CARGO_PKG_VERSION"))]
#[command(about = "Secure remote package management API for Linux systems")]
struct Args {
    /// Path to configuration file
    #[arg(short, long, default_value = "/etc/linux_patch_api/config.yaml")]
    config: String,

    /// Enable verbose logging
    #[arg(short, long)]
    verbose: bool,
}

#[actix_web::main]
async fn main() -> Result<()> {
    // Parse command line arguments
    let args = Args::parse();

    // Initialize logging
    let _guard = init_logging(args.verbose)?;

    info!(
        version = env!("CARGO_PKG_VERSION"),
        config_path = args.config,
        "Linux Patch API starting"
    );

    // Load configuration
    let config = match AppConfig::load(&args.config) {
        Ok(cfg) => {
            info!(
                port = cfg.server.port,
                bind = &cfg.server.bind,
                "Configuration loaded"
            );
            cfg
        }
        Err(e) => {
            error!(error = %e, path = args.config, "Failed to load configuration");
            return Err(anyhow::anyhow!("Configuration error: {}", e));
        }
    };

    // Initialize job manager
    let job_manager = JobManager::new(config.jobs.max_concurrent, config.jobs.timeout_minutes)?;
    info!(
        max_jobs = config.jobs.max_concurrent,
        timeout_minutes = config.jobs.timeout_minutes,
        "Job manager initialized"
    );

    // Initialize package manager backend
    let package_backend = match create_backend() {
        Ok(backend) => {
            info!("Package manager backend initialized");
            backend
        }
        Err(e) => {
            error!(error = %e, "Failed to initialize package manager backend");
            return Err(anyhow::anyhow!("Package backend error: {}", e));
        }
    };

    // Initialize IP whitelist manager
    let whitelist_path = config.whitelist_path();
    info!(
        path = whitelist_path,
        "Initializing IP whitelist enforcement"
    );

    let whitelist_manager = match WhitelistManager::new(whitelist_path) {
        Ok(manager) => {
            info!(
                entries = manager.entry_count(),
                "Whitelist manager initialized"
            );
            Some(Arc::new(manager))
        }
        Err(e) => {
            warn!(error = %e, "Failed to load whitelist - continuing with empty whitelist (all denied)");
            None
        }
    };

    // Store job manager and backend in Arc for sharing
    let job_manager_data = web::Data::new(job_manager);
    let backend_data = web::Data::new(package_backend);

    // Configure bind address
    let bind_address = format!("{}:{}", config.server.bind, config.server.port);
    info!(bind = %bind_address, "Starting HTTP server");

    // Create server
    // Create server builder
    let server_builder = HttpServer::new(move || {
        let mut app = App::new()
            .wrap(Logger::default())
            .app_data(job_manager_data.clone())
            .app_data(backend_data.clone());

        // Configure API routes
        app = app.configure(|cfg| {
            configure_api_routes(cfg, job_manager_data.clone(), backend_data.clone());
        });

        // Configure health route (outside API scope)
        app = app.configure(configure_health_route);

        app
    })
    .workers(4)
    // VULN-004: Configure header size limit to 8KB to prevent DoS via oversized headers
    .client_request_timeout(std::time::Duration::from_secs(5))
    .keep_alive(std::time::Duration::from_secs(15))
    .max_connection_rate(1000);
    info!(
        mtls_enabled = config.tls_config().is_some(),
        whitelist_enabled = whitelist_manager.is_some(),
        "Security layer status"
    );

    info!("Linux Patch API initialized successfully");
    info!("Listening on {}", bind_address);

    // Apply TLS/mTLS configuration if enabled
    if let Some(tls_config) = config.tls_config() {
        info!(
            ca_cert = %tls_config.ca_cert,
            server_cert = %tls_config.server_cert,
            server_key = %tls_config.server_key,
            min_tls_version = %tls_config.min_tls_version,
            "Initializing mTLS authentication with TLS binding"
        );

        let mtls_config = mtls::MtlsConfig {
            ca_cert_path: tls_config.ca_cert.clone(),
            server_cert_path: tls_config.server_cert.clone(),
            server_key_path: tls_config.server_key.clone(),
            min_tls_version: tls_config.min_tls_version.clone(),
        };

        match MtlsMiddleware::new(mtls_config.clone()) {
            Ok(middleware) => {
                // Build rustls server configuration
                let rustls_config = middleware
                    .build_rustls_config()
                    .map_err(|e| anyhow::anyhow!("Failed to build rustls config: {}", e))?;

                info!("mTLS middleware and rustls config initialized successfully");

                // Create TCP listener (std::net for listen_rustls_0_23)
                let tcp_listener = TcpListener::bind(&bind_address)
                    .map_err(|e| anyhow::anyhow!("Failed to bind to {}: {}", bind_address, e))?;

                info!("TCP listener bound to {}", bind_address);

                // Clone the ServerConfig from Arc for listen_rustls_0_23
                let server_config = (*rustls_config).clone();

                info!("Binding server with TLS 1.3 - non-TLS connections will be rejected");

                // Bind with TLS using rustls 0.23 - non-TLS connections fail at handshake
                server_builder
                    .listen_rustls_0_23(tcp_listener, server_config)?
                    .run()
                    .await?;
            }
            Err(e) => {
                error!(error = %e, "Failed to initialize mTLS middleware");
                return Err(anyhow::anyhow!("mTLS initialization failed: {}", e));
            }
        }
    } else {
        warn!("TLS is disabled - running without mTLS authentication (INSECURE)");
        server_builder.bind(&bind_address)?.run().await?;
    }

    info!("Linux Patch API shutting down");
    Ok(())
}
