//! Integration tests for `cph-schema::validate`, driven by tiny fixtures under
//! `tests/fixtures/<case>/` and in-code `ElementDescriptor`s.

use std::path::{Path, PathBuf};

use cph_diag::DiagCode;
use cph_model::ElementDescriptor;
use cph_schema::validate;

/// Absolute path to a fixture directory.
fn fixture(case: &str) -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("fixtures")
        .join(case)
}

fn desc(kind: &str, dir: PathBuf, scalars: toml::Table) -> ElementDescriptor {
    ElementDescriptor {
        kind: kind.to_string(),
        dir,
        scalars,
    }
}

#[test]
fn valid_example_no_diagnostics() {
    let mut scalars = toml::Table::new();
    scalars.insert("source".into(), toml::Value::String("Textbook §3".into()));
    let d = desc("example", fixture("example_valid"), scalars);
    let diags = validate(&d);
    assert!(diags.is_empty(), "expected no diagnostics, got {diags:?}");
}

#[test]
fn example_missing_solution_typ_is_missing_content_file() {
    let d = desc(
        "example",
        fixture("example_missing_solution"),
        toml::Table::new(),
    );
    let diags = validate(&d);
    assert_eq!(diags.len(), 1, "got {diags:?}");
    assert_eq!(diags[0].code, DiagCode::MissingContentFile);
    assert!(diags[0].message.contains("solution.typ"));
    assert!(diags[0].hint.is_some());
}

#[test]
fn lemma_without_proof_typ_is_ok() {
    // stmt.typ exists, proof.typ does not — proof is optional, so no diagnostic.
    let d = desc("lemma", fixture("lemma_no_proof"), toml::Table::new());
    let diags = validate(&d);
    assert!(diags.is_empty(), "expected no diagnostics, got {diags:?}");
}

#[test]
fn unknown_kind_is_reported() {
    let d = desc("frob", fixture("example_valid"), toml::Table::new());
    let diags = validate(&d);
    assert_eq!(diags.len(), 1, "got {diags:?}");
    assert_eq!(diags[0].code, DiagCode::UnknownKind);
    assert!(diags[0].message.contains("frob"));
}

#[test]
fn example_source_non_string_is_schema_violation() {
    let mut scalars = toml::Table::new();
    scalars.insert("source".into(), toml::Value::Integer(42));
    let d = desc("example", fixture("example_valid"), scalars);
    let diags = validate(&d);
    assert_eq!(diags.len(), 1, "got {diags:?}");
    assert_eq!(diags[0].code, DiagCode::SchemaViolation);
    assert!(diags[0].message.contains("source"));
    assert!(diags[0].message.contains("string"));
}
