//! Benchmarks for gas estimation operations.
//!
//! This module contains performance benchmarks for gas cost calculation
//! functions. While gas calculations are typically fast, these benchmarks
//! help track the performance overhead of gas metering across different
//! input sizes and operation types.

use clock_bigint::gas::{
    cost_add, cost_canonicalize, cost_decode, cost_div, cost_encode, cost_frommont, cost_modexp,
    cost_mont_mul, cost_mont_reduce, cost_mul, cost_sqr, cost_sub, cost_tomont,
    validate_limb_count,
};
use criterion::{Criterion, criterion_group, criterion_main};

fn bench_gas_arithmetic(c: &mut Criterion) {
    let mut group = c.benchmark_group("gas_arithmetic");

    // Benchmark basic arithmetic gas costs
    group.bench_function("gas_cost_add", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_add(32)); // 256-bit addition
        });
    });

    group.bench_function("gas_cost_sub", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_sub(32)); // 256-bit subtraction
        });
    });

    group.bench_function("gas_cost_mul", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_mul(32)); // 256-bit multiplication
        });
    });

    group.bench_function("gas_cost_sqr", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_sqr(32)); // 256-bit squaring
        });
    });

    group.bench_function("gas_cost_div", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_div(32)); // 256-bit division
        });
    });

    group.finish();
}

fn bench_gas_cryptographic(c: &mut Criterion) {
    let mut group = c.benchmark_group("gas_cryptographic");

    // Benchmark cryptographic operation gas costs
    group.bench_function("gas_cost_modexp_256", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_modexp(4, 256)); // 256-bit modulus, 256-bit exponent
        });
    });

    group.bench_function("gas_cost_modexp_2048", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_modexp(32, 2048)); // 2048-bit modulus, 2048-bit exponent
        });
    });

    group.bench_function("gas_cost_modexp_4096", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_modexp(64, 4096)); // 4096-bit modulus, 4096-bit exponent
        });
    });

    group.bench_function("gas_cost_mont_mul", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_mont_mul(32)); // 2048-bit Montgomery multiplication
        });
    });

    group.bench_function("gas_cost_mont_reduce", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_mont_reduce(32)); // 2048-bit Montgomery reduction
        });
    });

    group.finish();
}

fn bench_gas_conversion(c: &mut Criterion) {
    let mut group = c.benchmark_group("gas_conversion");

    // Benchmark conversion operation gas costs
    group.bench_function("gas_cost_tomont", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_tomont(32)); // 2048-bit to Montgomery form
        });
    });

    group.bench_function("gas_cost_frommont", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_frommont(32)); // 2048-bit from Montgomery form
        });
    });

    group.bench_function("gas_cost_encode", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_encode(32)); // 2048-bit encoding
        });
    });

    group.bench_function("gas_cost_decode", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_decode(32)); // 2048-bit decoding
        });
    });

    group.bench_function("gas_cost_canonicalize", |bencher| {
        bencher.iter(|| {
            std::hint::black_box(cost_canonicalize(32)); // 2048-bit canonicalization
        });
    });

    group.finish();
}

fn bench_gas_scaling(c: &mut Criterion) {
    let mut group = c.benchmark_group("gas_scaling");

    // Benchmark how gas costs scale with input size
    for &size in [4, 8, 16, 32, 64, 128, 256, 512].iter() {
        group.bench_with_input(
            format!("gas_cost_mul_{}", size * 64),
            &size,
            |bencher, &size| {
                bencher.iter(|| {
                    std::hint::black_box(cost_mul(size));
                });
            },
        );

        group.bench_with_input(
            format!("gas_cost_modexp_{}", size * 64),
            &size,
            |bencher, &size| {
                bencher.iter(|| {
                    std::hint::black_box(cost_modexp(size, size * 64));
                });
            },
        );
    }

    group.finish();
}

fn bench_gas_validation(c: &mut Criterion) {
    let mut group = c.benchmark_group("gas_validation");

    // Benchmark limb count validation
    group.bench_function("validate_limb_count_valid", |bencher| {
        bencher.iter(|| {
            let _ = std::hint::black_box(validate_limb_count(256));
        });
    });

    group.bench_function("validate_limb_count_invalid", |bencher| {
        bencher.iter(|| {
            let _ = std::hint::black_box(validate_limb_count(600)); // Over MAX_LIMBS
        });
    });

    group.bench_function("validate_limb_count_max", |bencher| {
        bencher.iter(|| {
            let _ = std::hint::black_box(validate_limb_count(512)); // Exactly MAX_LIMBS
        });
    });

    group.finish();
}

fn bench_gas_batch(c: &mut Criterion) {
    let mut group = c.benchmark_group("gas_batch");

    // Benchmark calculating gas costs for multiple operations (typical VM scenario)
    group.bench_function("gas_batch_arithmetic", |bencher| {
        bencher.iter(|| {
            let add_cost = cost_add(32);
            let sub_cost = cost_sub(32);
            let mul_cost = cost_mul(32);
            let div_cost = cost_div(32);
            std::hint::black_box((add_cost, sub_cost, mul_cost, div_cost));
        });
    });

    group.bench_function("gas_batch_crypto", |bencher| {
        bencher.iter(|| {
            let modexp_cost = cost_modexp(32, 2048);
            let mont_mul_cost = cost_mont_mul(32);
            let mont_reduce_cost = cost_mont_reduce(32);
            std::hint::black_box((modexp_cost, mont_mul_cost, mont_reduce_cost));
        });
    });

    group.bench_function("gas_batch_mixed", |bencher| {
        bencher.iter(|| {
            // Simulate a typical transaction with multiple operations
            let add = cost_add(4);
            let mul = cost_mul(4);
            let modexp = cost_modexp(4, 256);
            let encode = cost_encode(4);
            let decode = cost_decode(4);
            std::hint::black_box((add, mul, modexp, encode, decode));
        });
    });

    group.finish();
}

criterion_group!(
    benches,
    bench_gas_arithmetic,
    bench_gas_cryptographic,
    bench_gas_conversion,
    bench_gas_scaling,
    bench_gas_validation,
    bench_gas_batch
);
criterion_main!(benches);
