//! Dialect versioning strategies — Caret vs Exact.
//!
//! Installs multiple versions of a "ui" dialect into an InMemoryRegistry
//! and shows how VersionStrategy::Caret picks the highest compatible version
//! while VersionStrategy::Exact requires a byte-for-byte version match.
//!
//! Run: `cargo run --example tier1_versioning`

// What this shows:
//   - InMemoryRegistry.resolve(name, version_req) applies each dialect's
//     VersionStrategy when deciding if it satisfies the request
//   - Caret (default): same major, installed >= requested → picks highest match
//   - Exact: must match exactly to the requested version string
//   - decode_t1_with_registry succeeds when a matching dialect exists, fails otherwise

use dms::tier1::{
    decode_t1_with_registry, DialectRegistry, DialectSpec, FamilySpec, InMemoryRegistry,
    ParamSignature, VersionStrategy,
};
use dms::Value;

fn ui_dialect(version: &str, strategy: VersionStrategy) -> DialectSpec {
    DialectSpec {
        name: "ui".into(),
        version: version.into(),
        version_strategy: strategy,
        families: vec![FamilySpec {
            name: "widget".into(),
            default_sigils: vec!["|".into()],
            empty_default: Value::Table(Default::default()),
            content_slot: None,
            params: ParamSignature::default(),
        }],
        structs: vec![],
    }
}

// A document that requests ui@1.0.0.
const DOC_V1: &str = "\
+++
_dms_tier: 1
_dms_imports:
  + dialect: \"ui\"
    version: \"1.0.0\"
    bind:
      \"|\": [\"widget\"]
+++
btn: |widget(label: \"OK\")
";

// A document that requests ui@2.0.0.
const DOC_V2: &str = "\
+++
_dms_tier: 1
_dms_imports:
  + dialect: \"ui\"
    version: \"2.0.0\"
    bind:
      \"|\": [\"widget\"]
+++
btn: |widget(label: \"OK\")
";

fn main() {
    // ── Part A: VersionStrategy::Caret ────────────────────────────────────────
    // Install v1.5.0 (Caret). It should satisfy requests for 1.0.0 (same major,
    // installed >= requested) but reject requests for 2.0.0 (different major).
    let caret_registry = InMemoryRegistry::new()
        .with(ui_dialect("1.5.0", VersionStrategy::Caret));

    println!("=== Caret strategy (installed: ui@1.5.0) ===");

    let r1 = decode_t1_with_registry(DOC_V1, &caret_registry);
    match r1 {
        Ok(_)  => println!("  request 1.0.0 -> OK  (1.5.0 satisfies ^1.0.0)"),
        Err(e) => println!("  request 1.0.0 -> ERR: {}", e.message),
    }

    // 2.0.0 has a different major; Caret rejects it.
    // Without a matching dialect the call still parses — resolution just leaves
    // call.family empty (no registry entry to match). So we probe the registry
    // directly to show the behaviour:
    let resolved = caret_registry.resolve("ui", "2.0.0");
    match resolved {
        Some(d) => println!("  request 2.0.0 -> resolved to v{}", d.version),
        None    => println!("  request 2.0.0 -> None  (1.5.0 does NOT satisfy ^2.0.0 — different major)"),
    }

    // ── Part B: VersionStrategy::Exact ────────────────────────────────────────
    // Install v1.0.0 (Exact). Only an exact 1.0.0 request matches.
    let exact_registry = InMemoryRegistry::new()
        .with(ui_dialect("1.0.0", VersionStrategy::Exact));

    println!("\n=== Exact strategy (installed: ui@1.0.0) ===");

    let r2 = decode_t1_with_registry(DOC_V1, &exact_registry);
    match r2 {
        Ok(_)  => println!("  request 1.0.0 -> OK  (exact match)"),
        Err(e) => println!("  request 1.0.0 -> ERR: {}", e.message),
    }

    // A 2.0.0 request won't match even though there's a 1.0.0 in the registry.
    let resolved2 = exact_registry.resolve("ui", "2.0.0");
    match resolved2 {
        Some(d) => println!("  request 2.0.0 -> resolved to v{}", d.version),
        None    => println!("  request 2.0.0 -> None  (1.0.0 does not exactly equal 2.0.0)"),
    }

    // ── Part C: multiple installed versions ───────────────────────────────────
    // Install 1.0.0 + 1.5.0 + 2.0.0 (all Caret). Request 1.0.0 picks the
    // highest compatible version in the 1.x range = 1.5.0.
    let multi_registry = InMemoryRegistry::new()
        .with(ui_dialect("1.0.0", VersionStrategy::Caret))
        .with(ui_dialect("1.5.0", VersionStrategy::Caret))
        .with(ui_dialect("2.0.0", VersionStrategy::Caret));

    println!("\n=== Multiple installed (1.0.0, 1.5.0, 2.0.0, all Caret) ===");

    let pick = multi_registry.resolve("ui", "1.0.0");
    match pick {
        Some(d) => println!("  request 1.0.0 -> picked v{}  (highest ^1.x match)", d.version),
        None    => println!("  request 1.0.0 -> None"),
    }

    let pick2 = multi_registry.resolve("ui", "2.0.0");
    match pick2 {
        Some(d) => println!("  request 2.0.0 -> picked v{}  (highest ^2.x match)", d.version),
        None    => println!("  request 2.0.0 -> None"),
    }

    // decode with the multi-registry for the v2 doc also succeeds.
    let r3 = decode_t1_with_registry(DOC_V2, &multi_registry);
    match r3 {
        Ok(doc) => println!(
            "  DOC_V2 decode -> OK  (resolved {} import(s))",
            doc.imports.imports.len()
        ),
        Err(e) => println!("  DOC_V2 decode -> ERR: {}", e.message),
    }
}
