/// Step 6: Map to Theatre Migrants ontology (tm: namespace).
///
/// Loads `data/graph-05.ttl`, runs all SPARQL CONSTRUCT queries from
/// `constructs_step06/` (sorted alphabetically), collects the resulting
/// triples into a new graph, and writes it to `data/graph-06.ttl`.
///
/// Usage: Run from the mapping project directory:
///   cargo run --release --bin step-06

use std::fs;

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

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input_path = "data/graph-05.ttl";
    let output_path = "data/graph-06.ttl";
    let constructs_dir = "constructs_step06";

    // Create in-memory store and load input graph
    let source = 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);
    source.load_from_reader(parser, reader)?;

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

    // Output store collects all CONSTRUCT results
    let output = Store::new()?;

    // Read and sort SPARQL CONSTRUCT files
    let mut query_files: Vec<_> = fs::read_dir(constructs_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();
    query_files.sort();

    // Run each CONSTRUCT query and collect results
    for query_file in &query_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(&output);

        match source.query(&query)? {
            QueryResults::Graph(triples) => {
                for triple in triples {
                    let triple = triple?;
                    output.insert(QuadRef::new(
                        triple.subject.as_ref(),
                        triple.predicate.as_ref(),
                        triple.object.as_ref(),
                        GraphNameRef::DefaultGraph,
                    ))?;
                }
            }
            _ => {
                eprintln!("Warning: {} did not return a graph", name);
            }
        }

        let after = count_triples(&output);
        let diff = after as i64 - before as i64;
        eprintln!("  {}: +{} triples (total: {})", name, diff, after);
    }

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

    // Dump output store to Turtle
    fs::create_dir_all("data")?;
    let out_file = fs::File::create(output_path)?;
    let writer = std::io::BufWriter::new(out_file);
    output.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()
}
