//! Demonstrates manual pipeline construction with non-default components.
//!
//! Instead of using a convenience constructor like `AspicPipeline::classical()`,
//! this example assembles the pipeline piece by piece, choosing specific
//! implementations for each stage.
//!
//! Run with: `cargo run --example custom_pipeline`

use pickaxe_rs::prelude::*;

fn main() {
    // ── 1. Build a small system ─────────────────────────────────────────

    let (system, _) = AspicSystemBuilder::new()
        .ordinary_premise(formula!(a))
        .ordinary_premise(formula!(b))
        .defeasible_rule("d1", vec![formula!(a)], formula!(c))
        .defeasible_rule("d2", vec![formula!(b)], formula!(!c))
        .with_classical_negation()
        .build();

    // ── 2. Configure a weakest-link ordering ────────────────────────────

    let ordering: Box<dyn ArgumentOrdering> = Box::new(WeakestLinkOrdering {
        rule_ordering: Box::new(TieredOrdering::new(vec![
            vec![RuleId("d1".into())],
            vec![RuleId("d2".into())],
        ])),
        premise_ordering: Box::new(NoPreference),
        lifting: LiftingStrategy::Democratic,
    });

    // ── 3. Assemble the pipeline manually ───────────────────────────────

    let pipeline = AspicPipeline {
        system,
        grounder: Box::new(NaiveGrounder),
        arg_constructor: Box::new(ForwardChainingConstructor),
        attack_computer: Box::new(PairwiseAttackComputer),
        evaluator: Box::new(ClassicalEvaluator {
            semantics_solver: Box::new(NaiveEnumerationSolver),
        }),
        preference: PreferenceConfig::ArgumentOrdering(ordering),
    };

    // ── 4. Evaluate multiple semantics ──────────────────────────────────

    for sem in [Semantics::Grounded, Semantics::Preferred, Semantics::Stable] {
        let result = pipeline.evaluate(sem).expect("evaluation failed");
        println!(
            "{sem:?}: {} extension(s), {} argument(s) total",
            result.extensions.len(),
            result.store.len(),
        );
        for (i, ext) in result.extensions.iter().enumerate() {
            let conclusions: Vec<String> = ext
                .iter()
                .filter_map(|&id| result.store.get(id))
                .map(|arg| format!("{}", arg.conclusion()))
                .collect();
            println!("  ext {i}: {conclusions:?}");
        }
    }
}
