#![allow(clippy::integer_division)]

use anyhow::Result;
use clap::{Parser, Subcommand};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

mod clients;
mod config;
mod metrics;
mod orchestrator;
mod reporting;
mod scenarios;

#[derive(Parser)]
#[command(name = "load_test_runner")]
#[command(about = "API Gateway Load Testing Framework", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Run normal load test (1K concurrent clients for 60s)
    Normal {
        #[arg(long, default_value = "http://localhost:50050")]
        gateway_url: String,
        #[arg(long, default_value = "1000")]
        num_clients: usize,
        #[arg(long, default_value = "60")]
        duration_secs: u64,
    },
    /// Run spike load test (0→10K clients in 10s, sustain 60s)
    Spike {
        #[arg(long, default_value = "http://localhost:50050")]
        gateway_url: String,
        #[arg(long, default_value = "10000")]
        target_clients: usize,
        #[arg(long, default_value = "10")]
        ramp_up_secs: u64,
        #[arg(long, default_value = "60")]
        sustain_secs: u64,
    },
    /// Run sustained load test (100 clients for 24h)
    Sustained {
        #[arg(long, default_value = "http://localhost:50050")]
        gateway_url: String,
        #[arg(long, default_value = "100")]
        num_clients: usize,
        #[arg(long, default_value = "86400")]
        duration_secs: u64,
    },
    /// Run stress test (incrementally increase until failure)
    Stress {
        #[arg(long, default_value = "http://localhost:50050")]
        gateway_url: String,
        #[arg(long, default_value = "100")]
        initial_clients: usize,
        #[arg(long, default_value = "100")]
        increment: usize,
        #[arg(long, default_value = "60")]
        increment_interval_secs: u64,
        #[arg(long, default_value = "50.0")]
        max_p99_latency_ms: f64,
        #[arg(long, default_value = "5.0")]
        max_error_rate_pct: f64,
    },
    /// Run all scenarios sequentially
    All {
        #[arg(long, default_value = "http://localhost:50050")]
        gateway_url: String,
    },
}

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize tracing
    tracing_subscriber::registry()
        .with(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| "info,load_test_runner=debug".into()),
        )
        .with(tracing_subscriber::fmt::layer())
        .init();

    let cli = Cli::parse();

    match cli.command {
        Commands::Normal {
            gateway_url,
            num_clients,
            duration_secs,
        } => {
            tracing::info!(
                "Running NORMAL load test: {} clients for {}s",
                num_clients,
                duration_secs
            );
            let report =
                scenarios::normal_load::run(gateway_url, num_clients, duration_secs).await?;
            reporting::generate_html_report("normal_load_report.html", report)?;
        },
        Commands::Spike {
            gateway_url,
            target_clients,
            ramp_up_secs,
            sustain_secs,
        } => {
            tracing::info!(
                "Running SPIKE load test: 0→{} clients in {}s, sustain {}s",
                target_clients,
                ramp_up_secs,
                sustain_secs
            );
            let report =
                scenarios::spike_load::run(gateway_url, target_clients, ramp_up_secs, sustain_secs)
                    .await?;
            reporting::generate_html_report("spike_load_report.html", report)?;
        },
        Commands::Sustained {
            gateway_url,
            num_clients,
            duration_secs,
        } => {
            tracing::info!(
                "Running SUSTAINED load test: {} clients for {}s ({}h)",
                num_clients,
                duration_secs,
                duration_secs / 3600
            );
            let report =
                scenarios::sustained_load::run(gateway_url, num_clients, duration_secs).await?;
            reporting::generate_html_report("sustained_load_report.html", report)?;
        },
        Commands::Stress {
            gateway_url,
            initial_clients,
            increment,
            increment_interval_secs,
            max_p99_latency_ms,
            max_error_rate_pct,
        } => {
            tracing::info!(
                "Running STRESS test: start {} clients, increment by {} every {}s",
                initial_clients,
                increment,
                increment_interval_secs
            );
            let report = scenarios::stress_test::run(
                gateway_url,
                initial_clients,
                increment,
                increment_interval_secs,
                max_p99_latency_ms,
                max_error_rate_pct,
            )
            .await?;
            reporting::generate_html_report("stress_test_report.html", report)?;
        },
        Commands::All { gateway_url } => {
            tracing::info!("Running ALL load test scenarios sequentially");

            // Normal load
            let normal_report =
                scenarios::normal_load::run(gateway_url.clone(), 1000_usize, 60).await?;
            reporting::generate_html_report("normal_load_report.html", normal_report)?;

            // Wait between tests
            tokio::time::sleep(tokio::time::Duration::from_secs(30)).await;

            // Spike load
            let spike_report =
                scenarios::spike_load::run(gateway_url.clone(), 10000_usize, 10_u64, 60).await?;
            reporting::generate_html_report("spike_load_report.html", spike_report)?;

            // Wait between tests
            tokio::time::sleep(tokio::time::Duration::from_secs(30)).await;

            // Stress test (short version)
            let stress_report = scenarios::stress_test::run(
                gateway_url.clone(),
                100_usize,
                100_usize,
                60_u64,
                50.0,
                5.0,
            )
            .await?;
            reporting::generate_html_report("stress_test_report.html", stress_report)?;

            tracing::info!("All scenarios complete! Reports generated.");
        },
    }

    Ok(())
}
