//! Performance benchmarks for ggen critical paths
//!
//! Run with: cargo bench --bench performance_benchmark

use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use ggen_core::{
    generator::{GenContext, Generator},
    graph::Graph,
    lockfile::LockfileManager,
    pipeline::Pipeline,
    template::Template,
    template_cache::TemplateCache,
};
use std::collections::BTreeMap;
use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;

// Helper to create test template
fn create_test_template(content: &str) -> (TempDir, PathBuf) {
    let temp_dir = TempDir::new().expect("Failed to create temp dir");
    let template_path = temp_dir.path().join("test.tmpl");
    fs::write(&template_path, content).expect("Failed to write test template");
    (temp_dir, template_path)
}

// Benchmark 1: Template Parsing
fn bench_template_parsing(c: &mut Criterion) {
    let mut group = c.benchmark_group("template_parsing");

    let simple_template = r#"---
to: "output/{{ name }}.rs"
---
// Simple template
pub fn {{ name }}() {
    println!("Hello, {{ name }}!");
}
"#;

    let complex_template = r#"---
to: "output/{{ module }}/{{ name | lower }}.rs"
graph:
  data: |
    @prefix ex: <http://example.org/> .
    ex:{{ name }} a ex:Module ;
                  ex:version "{{ version }}" ;
                  ex:dependencies (ex:dep1 ex:dep2 ex:dep3) .
query: |
  SELECT ?dep WHERE {
    ex:{{ name }} ex:dependencies/rdf:rest*/rdf:first ?dep .
  }
---
// Complex template with RDF
{% for dep in query_results %}
use {{ dep }};
{% endfor %}

pub mod {{ module }} {
    pub fn {{ name | lower }}() -> &'static str {
        "{{ version }}"
    }
}
"#;

    group.bench_function("simple_template", |b| {
        b.iter(|| {
            let result = Template::parse(black_box(simple_template));
            assert!(result.is_ok());
        })
    });

    group.bench_function("complex_template", |b| {
        b.iter(|| {
            let result = Template::parse(black_box(complex_template));
            assert!(result.is_ok());
        })
    });

    group.finish();
}

// Benchmark 2: Template Caching
fn bench_template_caching(c: &mut Criterion) {
    let mut group = c.benchmark_group("template_caching");

    let (_temp_dir, template_path) = create_test_template(
        r#"---
to: "output.rs"
---
fn main() {}"#,
    );

    group.bench_function("cache_hit", |b| {
        let cache = TemplateCache::new(100);
        // Pre-warm cache
        let _ = cache.get_or_parse(&template_path);

        b.iter(|| {
            let result = cache.get_or_parse(black_box(&template_path));
            assert!(result.is_ok());
        })
    });

    group.bench_function("cache_miss", |b| {
        b.iter(|| {
            let cache = TemplateCache::new(100);
            let result = cache.get_or_parse(black_box(&template_path));
            assert!(result.is_ok());
        })
    });

    group.finish();
}

// Benchmark 3: Code Generation Pipeline
fn bench_code_generation(c: &mut Criterion) {
    let mut group = c.benchmark_group("code_generation");

    let (_temp_dir, template_path) = create_test_template(
        r#"---
to: "output/{{ name | lower }}.rs"
---
// Generated by ggen
pub struct {{ name }} {
    version: &'static str,
}

impl {{ name }} {
    pub fn new() -> Self {
        Self { version: "{{ version }}" }
    }
}
"#,
    );

    group.bench_function("generate_simple_file", |b| {
        let output_dir = TempDir::new().unwrap();

        b.iter(|| {
            let pipeline = Pipeline::new().unwrap();
            let mut vars = BTreeMap::new();
            vars.insert("name".to_string(), "TestModule".to_string());
            vars.insert("version".to_string(), "1.0.0".to_string());

            let ctx = GenContext::new(template_path.clone(), output_dir.path().to_path_buf())
                .with_vars(vars);

            let mut generator = Generator::new(pipeline, ctx);
            let result = generator.generate();
            assert!(result.is_ok());
        });
    });

    group.finish();
}

// Benchmark 4: RDF Graph Operations
fn bench_rdf_operations(c: &mut Criterion) {
    let mut group = c.benchmark_group("rdf_operations");

    let small_graph_data = r#"
@prefix ex: <http://example.org/> .
ex:alice a ex:Person ;
         ex:name "Alice" ;
         ex:age 30 .
"#;

    let large_graph_data = r#"
@prefix ex: <http://example.org/> .
ex:alice a ex:Person ; ex:name "Alice" ; ex:age 30 .
ex:bob a ex:Person ; ex:name "Bob" ; ex:age 25 .
ex:charlie a ex:Person ; ex:name "Charlie" ; ex:age 35 .
ex:diana a ex:Person ; ex:name "Diana" ; ex:age 28 .
ex:eve a ex:Person ; ex:name "Eve" ; ex:age 32 .
"#;

    group.bench_function("insert_small_turtle", |b| {
        b.iter(|| {
            let graph = Graph::new().unwrap();
            let result = graph.insert_turtle(black_box(small_graph_data));
            assert!(result.is_ok());
        })
    });

    group.bench_function("insert_large_turtle", |b| {
        b.iter(|| {
            let graph = Graph::new().unwrap();
            let result = graph.insert_turtle(black_box(large_graph_data));
            assert!(result.is_ok());
        })
    });

    group.bench_function("query_simple", |b| {
        let graph = Graph::new().unwrap();
        graph.insert_turtle(small_graph_data).unwrap();

        b.iter(|| {
            let result = graph.query(black_box(
                "SELECT ?name WHERE { ?s <http://example.org/name> ?name }",
            ));
            assert!(result.is_ok());
        })
    });

    group.bench_function("query_with_cache_hit", |b| {
        let graph = Graph::new().unwrap();
        graph.insert_turtle(small_graph_data).unwrap();

        // Pre-warm cache
        let _ = graph.query("SELECT ?name WHERE { ?s <http://example.org/name> ?name }");

        b.iter(|| {
            let result = graph.query(black_box(
                "SELECT ?name WHERE { ?s <http://example.org/name> ?name }",
            ));
            assert!(result.is_ok());
        })
    });

    group.finish();
}

// Benchmark 5: Lockfile Operations
fn bench_lockfile_operations(c: &mut Criterion) {
    let mut group = c.benchmark_group("lockfile_operations");

    group.throughput(Throughput::Elements(1));

    group.bench_function("lockfile_create_and_save", |b| {
        let temp_dir = TempDir::new().unwrap();

        b.iter(|| {
            let manager = LockfileManager::new(temp_dir.path());
            let lockfile = manager.create().unwrap();
            manager.save(&lockfile).unwrap();
        })
    });

    group.bench_function("lockfile_load", |b| {
        let temp_dir = TempDir::new().unwrap();
        let manager = LockfileManager::new(temp_dir.path());

        // Create initial lockfile
        manager
            .upsert("io.ggen.test", "1.0.0", "abc123", "https://example.com")
            .unwrap();

        b.iter(|| {
            let result = manager.load();
            assert!(result.is_ok());
        })
    });

    group.bench_function("lockfile_upsert", |b| {
        let temp_dir = TempDir::new().unwrap();
        let manager = LockfileManager::new(temp_dir.path());

        b.iter(|| {
            manager
                .upsert(
                    black_box("io.ggen.test"),
                    black_box("1.0.0"),
                    black_box("abc123"),
                    black_box("https://example.com"),
                )
                .unwrap();
        })
    });

    // Benchmark with multiple entries
    group.throughput(Throughput::Elements(10));
    group.bench_function("lockfile_load_10_entries", |b| {
        let temp_dir = TempDir::new().unwrap();
        let manager = LockfileManager::new(temp_dir.path());

        // Create lockfile with 10 entries
        for i in 0..10 {
            manager
                .upsert(
                    &format!("io.ggen.pack{}", i),
                    "1.0.0",
                    "abc123",
                    "https://example.com",
                )
                .unwrap();
        }

        b.iter(|| {
            let result = manager.load();
            assert!(result.is_ok());
        })
    });

    // Benchmark with 100 entries
    group.throughput(Throughput::Elements(100));
    group.bench_function("lockfile_load_100_entries", |b| {
        let temp_dir = TempDir::new().unwrap();
        let manager = LockfileManager::new(temp_dir.path());

        // Create lockfile with 100 entries
        for i in 0..100 {
            manager
                .upsert(
                    &format!("io.ggen.pack{}", i),
                    "1.0.0",
                    "abc123",
                    "https://example.com",
                )
                .unwrap();
        }

        b.iter(|| {
            let result = manager.load();
            assert!(result.is_ok());
        })
    });

    group.finish();
}

// Benchmark 6: Pipeline Creation
fn bench_pipeline_creation(c: &mut Criterion) {
    c.bench_function("pipeline_new", |b| {
        b.iter(|| {
            let result = Pipeline::new();
            assert!(result.is_ok());
        })
    });
}

criterion_group!(
    benches,
    bench_template_parsing,
    bench_template_caching,
    bench_code_generation,
    bench_rdf_operations,
    bench_lockfile_operations,
    bench_pipeline_creation,
);
criterion_main!(benches);
