/// Step 3: Annotate datatypes on literal values.
///
/// Loads `data/graph-02.ttl`, applies all SPARQL UPDATE queries from the
/// `updates_step03/` directory (sorted alphabetically), and writes the
/// result to `data/graph-03.ttl`.
///
/// Usage: Run from the mapping project directory:
///   cargo run --release --bin step-03

use std::fs;

use oxigraph::io::{RdfFormat, RdfParser};
use oxigraph::model::GraphNameRef;
use oxigraph::store::Store;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input_path = "data/graph-02.ttl";
    let output_path = "data/graph-03.ttl";
    let updates_dir = "updates_step03";

    // Create in-memory store and load input graph
    let store = Store::new()?;

    eprintln!("Loading graph from {}...", input_path);
    let input = fs::File::open(input_path)?;
    let reader = std::io::BufReader::new(input);
    let parser = RdfParser::from_format(RdfFormat::Turtle)
        .without_named_graphs()
        .with_default_graph(GraphNameRef::DefaultGraph);
    store.load_from_reader(parser, reader)?;

    let initial_count = count_triples(&store);
    eprintln!("Loaded {} triples.", initial_count);

    // Read and sort SPARQL UPDATE files
    let mut update_files: Vec<_> = fs::read_dir(updates_dir)?
        .filter_map(|e| e.ok())
        .map(|e| e.path())
        .filter(|p| {
            p.extension()
                .and_then(|e| e.to_str())
                .map_or(false, |e| e == "rq")
        })
        .collect();
    update_files.sort();

    // Apply each SPARQL UPDATE query
    for query_file in &update_files {
        let query = fs::read_to_string(query_file)?;
        let name = query_file
            .file_name()
            .and_then(|n| n.to_str())
            .unwrap_or("unknown");

        let before = count_triples(&store);
        store.update(&query)?;
        let after = count_triples(&store);

        let diff = after as i64 - before as i64;
        let sign = if diff >= 0 { "+" } else { "" };
        eprintln!(
            "Applied {}: {} -> {} triples ({}{})",
            name, before, after, sign, diff
        );
    }

    let final_count = count_triples(&store);
    eprintln!("Writing {} triples to {}...", final_count, output_path);

    // Dump store to Turtle
    fs::create_dir_all("data")?;
    let output = fs::File::create(output_path)?;
    let writer = std::io::BufWriter::new(output);
    store.dump_graph_to_writer(GraphNameRef::DefaultGraph, RdfFormat::Turtle, writer)?;

    eprintln!("Done.");
    Ok(())
}

fn count_triples(store: &Store) -> usize {
    store
        .quads_for_pattern(None, None, None, None)
        .count()
}
