use std::path::Path;
use std::time::Instant;

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 3 {
        eprintln!("Usage: bench_diff <left> <right>");
        std::process::exit(1);
    }

    let left = Path::new(&args[1]);
    let right = Path::new(&args[2]);

    // Step 1: Read files
    let t = Instant::now();
    let left_content = std::fs::read_to_string(left).unwrap();
    let right_content = std::fs::read_to_string(right).unwrap();
    println!(
        "Read files: {:?} ({} + {} lines)",
        t.elapsed(),
        left_content.lines().count(),
        right_content.lines().count()
    );

    // Step 2: Intern
    let t = Instant::now();
    let input = imara_diff::InternedInput::new(left_content.as_str(), right_content.as_str());
    println!("Intern: {:?}", t.elapsed());

    // Step 3: Diff compute
    let t = Instant::now();
    let mut diff = imara_diff::Diff::compute(imara_diff::Algorithm::Histogram, &input);
    println!("Diff::compute: {:?}", t.elapsed());

    // Step 4: Postprocess
    let t = Instant::now();
    diff.postprocess_lines(&input);
    println!("postprocess_lines: {:?}", t.elapsed());

    // Step 5: Build chunks
    let t = Instant::now();
    let result = spekter_core::diff::diff_files(left, right).unwrap();
    println!("diff_files (total): {:?}", t.elapsed());

    let replace_chunks: Vec<_> = result
        .chunks
        .iter()
        .filter(|c| matches!(c, spekter_core::types::DiffChunk::Replace { .. }))
        .collect();
    let replace_line_pairs: usize = replace_chunks
        .iter()
        .map(|c| match c {
            spekter_core::types::DiffChunk::Replace {
                left_lines,
                right_lines,
                ..
            } => left_lines.len().min(right_lines.len()),
            _ => 0,
        })
        .sum();
    println!(
        "Replace chunks: {}, line pairs needing inline diff: {}",
        replace_chunks.len(),
        replace_line_pairs
    );

    // Step 6: Simulate inline highlights
    let t = Instant::now();
    let mut total_highlights = 0usize;
    for chunk in &result.chunks {
        if let spekter_core::types::DiffChunk::Replace {
            left_lines,
            right_lines,
            ..
        } = chunk
        {
            let max_len = left_lines.len().max(right_lines.len());
            for i in 0..max_len {
                if i < left_lines.len() && i < right_lines.len() {
                    // Simulate compute_inline_highlights
                    let left_trimmed = left_lines[i].strip_suffix('\n').unwrap_or(&left_lines[i]);
                    let right_trimmed =
                        right_lines[i].strip_suffix('\n').unwrap_or(&right_lines[i]);

                    struct CharSource<'a>(&'a str);
                    impl<'a> imara_diff::TokenSource for CharSource<'a> {
                        type Token = char;
                        type Tokenizer = std::str::Chars<'a>;
                        fn tokenize(&self) -> Self::Tokenizer {
                            self.0.chars()
                        }
                        fn estimate_tokens(&self) -> u32 {
                            self.0.len() as u32
                        }
                    }

                    let input = imara_diff::InternedInput::new(
                        CharSource(left_trimmed),
                        CharSource(right_trimmed),
                    );
                    let mut char_diff =
                        imara_diff::Diff::compute(imara_diff::Algorithm::Myers, &input);
                    char_diff.postprocess_no_heuristic(&input);
                    total_highlights += char_diff.hunks().count();
                }
            }
        }
    }
    println!(
        "Inline highlights: {:?} ({} highlights)",
        t.elapsed(),
        total_highlights
    );
}
