//! OSTP Server CLI - Stealth VPN Server for Linux
//!
//! Usage:
//!   ostp-server --listen 0.0.0.0:8443 --psk <hex-key>
//!   ostp-server --config /etc/ostp/server.json

use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use ostp::{OstpServer, ServerConfig};
use std::net::SocketAddr;
use std::path::PathBuf;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};

#[derive(Parser)]
#[command(name = "ostp-server")]
#[command(author = "ospab.team")]
#[command(version)]
#[command(about = "OSTP Stealth VPN Server", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,

    /// Listen address (e.g., 0.0.0.0:8443)
    #[arg(short, long, default_value = "0.0.0.0:8443")]
    listen: SocketAddr,

    /// Pre-shared key in hex format (64 hex chars = 32 bytes)
    #[arg(short, long, env = "OSTP_PSK")]
    psk: Option<String>,

    /// Path to config file (JSON)
    #[arg(short, long)]
    config: Option<PathBuf>,

    /// Log level (trace, debug, info, warn, error)
    #[arg(long, default_value = "info")]
    log_level: String,

    /// Max concurrent connections
    #[arg(long, default_value = "1024")]
    max_connections: usize,
}

#[derive(Subcommand)]
enum Commands {
    /// Generate a new random PSK
    GenKey,
    /// Show server status (placeholder)
    Status,
}

#[derive(serde::Deserialize, serde::Serialize)]
struct ConfigFile {
    listen: String,
    psk: String,
    max_connections: Option<usize>,
    log_level: Option<String>,
}

fn setup_logging(level: &str) {
    let filter = EnvFilter::try_from_default_env()
        .unwrap_or_else(|_| EnvFilter::new(level));

    tracing_subscriber::registry()
        .with(fmt::layer().with_target(true).with_thread_ids(false))
        .with(filter)
        .init();
}

fn parse_psk(hex_str: &str) -> Result<[u8; 32]> {
    let bytes = hex::decode(hex_str.trim())
        .context("Invalid hex string for PSK")?;
    
    if bytes.len() != 32 {
        anyhow::bail!("PSK must be exactly 32 bytes (64 hex characters), got {}", bytes.len());
    }
    
    let mut psk = [0u8; 32];
    psk.copy_from_slice(&bytes);
    Ok(psk)
}

fn generate_random_psk() -> String {
    let psk: [u8; 32] = rand::random();
    hex::encode(psk)
}

#[tokio::main]
async fn main() -> Result<()> {
    // ============================================
    // SECURITY CHECK - Detect debuggers/VMs
    // ============================================
    #[cfg(not(debug_assertions))]
    {
        if !ostp_guard::init_protection() {
            eprintln!("0x{:08X}", ostp_guard::error_codes::E_NET_TIMEOUT);
            std::process::exit(1);
        }
        
        // Start background monitor
        ostp_guard::anti_debug::start_background_monitor();
    }
    
    let cli = Cli::parse();

    // Handle subcommands
    if let Some(command) = cli.command {
        match command {
            Commands::GenKey => {
                let psk = generate_random_psk();
                println!("Generated PSK (keep this secret!):");
                println!("{}", psk);
                return Ok(());
            }
            Commands::Status => {
                println!("Server status: Not implemented yet");
                return Ok(());
            }
        }
    }

    // Load config from file if specified
    let (listen, psk, log_level) = if let Some(config_path) = cli.config {
        let content = std::fs::read_to_string(&config_path)
            .with_context(|| format!("Failed to read config file: {:?}", config_path))?;
        let config: ConfigFile = serde_json::from_str(&content)
            .context("Failed to parse config file")?;
        
        let addr: SocketAddr = config.listen.parse()
            .context("Invalid listen address in config")?;
        let psk = parse_psk(&config.psk)?;
        let level = config.log_level.unwrap_or_else(|| cli.log_level.clone());
        
        (addr, psk, level)
    } else {
        // Use CLI args
        let psk_str = cli.psk.ok_or_else(|| {
            anyhow::anyhow!("PSK is required. Use --psk <hex> or OSTP_PSK env var, or run 'ostp-server gen-key' to generate one")
        })?;
        let psk = parse_psk(&psk_str)?;
        
        (cli.listen, psk, cli.log_level)
    };

    setup_logging(&log_level);

    tracing::info!("╔════════════════════════════════════════════════════════╗");
    tracing::info!("║           OSTP Stealth VPN Server v{}            ║", env!("CARGO_PKG_VERSION"));
    tracing::info!("╚════════════════════════════════════════════════════════╝");
    tracing::info!("");
    tracing::info!("  Listen address: {}", listen);
    tracing::info!("  Max connections: {}", cli.max_connections);
    tracing::info!("  PSK: {}...{}", &hex::encode(&psk[..4]), &hex::encode(&psk[28..]));
    tracing::info!("");

    let config = ServerConfig::new(listen, psk);
    let server = OstpServer::new(config);

    tracing::info!("Starting server...");
    server.run().await?;

    Ok(())
}
