//! Performance benchmarks for skim transformations
//!
//! Run with: cargo bench

#![allow(clippy::unwrap_used, clippy::expect_used)] // Unwrapping/expect is acceptable in benchmarks

use criterion::{BenchmarkId, Criterion, black_box, criterion_group, criterion_main};
use rskim_core::{Language, Mode, transform, truncate_to_token_budget};

// ============================================================================
// Benchmark Fixtures
// ============================================================================

const SMALL_TS: &str = include_str!("../../../tests/fixtures/typescript/simple.ts");
const SMALL_PY: &str = include_str!("../../../tests/fixtures/python/simple.py");
const SMALL_RS: &str = include_str!("../../../tests/fixtures/rust/simple.rs");
const SMALL_GO: &str = include_str!("../../../tests/fixtures/go/simple.go");
const SMALL_JAVA: &str = include_str!("../../../tests/fixtures/java/Simple.java");
const SMALL_C: &str = include_str!("../../../tests/fixtures/c/simple.c");
const SMALL_CPP: &str = include_str!("../../../tests/fixtures/cpp/simple.cpp");
const SMALL_TOML: &str = include_str!("../../../tests/fixtures/toml/simple.toml");
const SMALL_CS: &str = include_str!("../../../tests/fixtures/csharp/simple.cs");
const SMALL_RB: &str = include_str!("../../../tests/fixtures/ruby/simple.rb");
const SMALL_SQL: &str = include_str!("../../../tests/fixtures/sql/simple.sql");
const SMALL_KT: &str = include_str!("../../../tests/fixtures/kotlin/Simple.kt");
const SMALL_SWIFT: &str = include_str!("../../../tests/fixtures/swift/Simple.swift");

// Medium complexity TypeScript
const MEDIUM_TS: &str = include_str!("../../../tests/fixtures/typescript/types.ts");

// Generate large file for stress testing
fn generate_large_typescript(num_functions: usize) -> String {
    let mut result = String::with_capacity(num_functions * 100);
    for i in 0..num_functions {
        result.push_str(&format!(
            "export function func{i}(a: number, b: number): number {{\n    return a + b;\n}}\n\n",
        ));
    }
    result
}

// ============================================================================
// Structure Mode Benchmarks
// ============================================================================

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

    // TypeScript
    group.bench_function("typescript_small", |b| {
        b.iter(|| transform(black_box(SMALL_TS), Language::TypeScript, Mode::Structure).unwrap())
    });

    group.bench_function("typescript_medium", |b| {
        b.iter(|| transform(black_box(MEDIUM_TS), Language::TypeScript, Mode::Structure).unwrap())
    });

    // Python
    group.bench_function("python_small", |b| {
        b.iter(|| transform(black_box(SMALL_PY), Language::Python, Mode::Structure).unwrap())
    });

    // Rust
    group.bench_function("rust_small", |b| {
        b.iter(|| transform(black_box(SMALL_RS), Language::Rust, Mode::Structure).unwrap())
    });

    // Go
    group.bench_function("go_small", |b| {
        b.iter(|| transform(black_box(SMALL_GO), Language::Go, Mode::Structure).unwrap())
    });

    // Java
    group.bench_function("java_small", |b| {
        b.iter(|| transform(black_box(SMALL_JAVA), Language::Java, Mode::Structure).unwrap())
    });

    // C
    group.bench_function("c_small", |b| {
        b.iter(|| transform(black_box(SMALL_C), Language::C, Mode::Structure).unwrap())
    });

    // C++
    group.bench_function("cpp_small", |b| {
        b.iter(|| transform(black_box(SMALL_CPP), Language::Cpp, Mode::Structure).unwrap())
    });

    // TOML
    group.bench_function("toml_small", |b| {
        b.iter(|| transform(black_box(SMALL_TOML), Language::Toml, Mode::Structure).unwrap())
    });

    // C#
    group.bench_function("csharp_small", |b| {
        b.iter(|| transform(black_box(SMALL_CS), Language::CSharp, Mode::Structure).unwrap())
    });

    // Ruby
    group.bench_function("ruby_small", |b| {
        b.iter(|| transform(black_box(SMALL_RB), Language::Ruby, Mode::Structure).unwrap())
    });

    // SQL
    group.bench_function("sql_small", |b| {
        b.iter(|| transform(black_box(SMALL_SQL), Language::Sql, Mode::Structure).unwrap())
    });

    // Kotlin
    group.bench_function("kotlin_small", |b| {
        b.iter(|| transform(black_box(SMALL_KT), Language::Kotlin, Mode::Structure).unwrap())
    });

    // Swift
    group.bench_function("swift_small", |b| {
        b.iter(|| transform(black_box(SMALL_SWIFT), Language::Swift, Mode::Structure).unwrap())
    });

    group.finish();
}

// ============================================================================
// Signatures Mode Benchmarks
// ============================================================================

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

    group.bench_function("typescript_small", |b| {
        b.iter(|| transform(black_box(SMALL_TS), Language::TypeScript, Mode::Signatures).unwrap())
    });

    group.bench_function("python_small", |b| {
        b.iter(|| transform(black_box(SMALL_PY), Language::Python, Mode::Signatures).unwrap())
    });

    group.bench_function("rust_small", |b| {
        b.iter(|| transform(black_box(SMALL_RS), Language::Rust, Mode::Signatures).unwrap())
    });

    group.finish();
}

// ============================================================================
// Types Mode Benchmarks
// ============================================================================

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

    group.bench_function("typescript_medium", |b| {
        b.iter(|| transform(black_box(MEDIUM_TS), Language::TypeScript, Mode::Types).unwrap())
    });

    group.bench_function("rust_small", |b| {
        b.iter(|| transform(black_box(SMALL_RS), Language::Rust, Mode::Types).unwrap())
    });

    group.finish();
}

// ============================================================================
// Scaling Benchmarks (File Size)
// ============================================================================

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

    for size in [10, 50, 100, 500, 1000] {
        let large_ts = generate_large_typescript(size);

        group.bench_with_input(
            BenchmarkId::new("functions", size),
            &large_ts,
            |b, input| {
                b.iter(|| {
                    transform(black_box(input), Language::TypeScript, Mode::Structure).unwrap()
                })
            },
        );
    }

    group.finish();
}

// ============================================================================
// Mode Comparison Benchmarks
// ============================================================================

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

    for mode in [
        Mode::Structure,
        Mode::Signatures,
        Mode::Types,
        Mode::Full,
        Mode::Minimal,
    ] {
        group.bench_with_input(
            BenchmarkId::new("typescript", format!("{:?}", mode)),
            &mode,
            |b, &mode| {
                b.iter(|| transform(black_box(SMALL_TS), Language::TypeScript, mode).unwrap())
            },
        );
    }

    group.finish();
}

// ============================================================================
// Language Comparison Benchmarks
// ============================================================================

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

    let languages = [
        (Language::TypeScript, SMALL_TS),
        (Language::Python, SMALL_PY),
        (Language::Rust, SMALL_RS),
        (Language::Go, SMALL_GO),
        (Language::Java, SMALL_JAVA),
        (Language::C, SMALL_C),
        (Language::Cpp, SMALL_CPP),
        (Language::Toml, SMALL_TOML),
        (Language::CSharp, SMALL_CS),
        (Language::Ruby, SMALL_RB),
        (Language::Sql, SMALL_SQL),
        (Language::Kotlin, SMALL_KT),
        (Language::Swift, SMALL_SWIFT),
    ];

    for (lang, source) in languages {
        group.bench_with_input(
            BenchmarkId::from_parameter(format!("{:?}", lang)),
            &source,
            |b, &input| b.iter(|| transform(black_box(input), lang, Mode::Structure).unwrap()),
        );
    }

    group.finish();
}

// ============================================================================
// Token Budget Truncation Benchmarks
// ============================================================================

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

    let word_count = |s: &str| -> usize { s.split_whitespace().count() };

    for num_lines in [100, 500, 1000, 5000] {
        // ~4 lines per function
        let text = generate_large_typescript(num_lines / 4);
        let total = word_count(&text);
        // Budget = ~50% of total tokens to force binary search
        let budget = total / 2;

        group.bench_with_input(
            BenchmarkId::new("lines", num_lines),
            &(text.clone(), budget, total),
            |b, (input, budget, _total)| {
                b.iter(|| {
                    truncate_to_token_budget(
                        black_box(input),
                        Language::TypeScript,
                        *budget,
                        word_count,
                        None,
                    )
                    .unwrap()
                })
            },
        );

        // Variant with known token count — exercises the fast-path skip
        group.bench_with_input(
            BenchmarkId::new("lines_known", num_lines),
            &(text, budget, total),
            |b, (input, budget, total)| {
                b.iter(|| {
                    truncate_to_token_budget(
                        black_box(input),
                        Language::TypeScript,
                        *budget,
                        word_count,
                        Some(*total),
                    )
                    .unwrap()
                })
            },
        );
    }

    group.finish();
}

criterion_group!(
    benches,
    bench_structure_mode,
    bench_signatures_mode,
    bench_types_mode,
    bench_scaling,
    bench_mode_comparison,
    bench_language_comparison,
    bench_token_budget_truncation
);
criterion_main!(benches);
