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

mod support;

const MSRV: &str = "1.87";
const VERSION: &str = "0.2.3";
const FEATURES: &[&str] = &[
    "default",
    "core",
    "rest",
    "rpc",
    "resil",
    "cache",
    "cache-redis",
    "discovery",
    "discovery-etcd",
    "discovery-kube",
    "observability",
    "observability-prometheus-client",
    "otlp",
    "profiling",
    "db",
    "db-sqlite",
    "db-mysql",
    "db-postgres",
];

#[test]
fn workspace_manifest_declares_version_msrv_and_feature_boundaries() {
    let manifest = read("Cargo.toml");
    support::assert_contains_all(
        &manifest,
        &[
            &format!("version = \"{VERSION}\""),
            "edition = \"2024\"",
            &format!("rust-version = \"{MSRV}\""),
            "rust-version.workspace = true",
            "default = [\"core\", \"rest\", \"rpc\", \"resil\", \"cache\", \"discovery\", \"observability\", \"db-sqlite\"]",
            "cache-redis = [\"cache\", \"resil\", \"dep:redis\", \"dep:sha1_smol\", \"dep:uuid\"]",
            "discovery-etcd = [\"discovery\", \"dep:etcd-client\"]",
            "discovery-kube = [\"discovery\", \"dep:kube\", \"dep:k8s-openapi\", \"dep:tokio-stream\", \"k8s-openapi/v1_30\"]",
            "observability-prometheus-client = [\"observability\", \"dep:prometheus-client\"]",
            "otlp = [\"observability\"",
            "profiling = [\"core\", \"dep:pyroscope\"]",
            "db-mysql = [\"db\", \"sqlx/mysql\"]",
            "db-postgres = [\"db\", \"sqlx/postgres\"]",
        ],
    );

    for manifest_path in [
        "crates/rs-zero-cli/Cargo.toml",
        "examples/rest-hello/Cargo.toml",
        "examples/rpc-hello/Cargo.toml",
    ] {
        let content = read(manifest_path);
        assert!(
            content.contains("rust-version.workspace = true"),
            "{manifest_path} must inherit workspace rust-version"
        );
    }
}

#[test]
fn stability_docs_link_policy_feature_matrix_and_migrations() {
    let readme = read("README.md");
    support::assert_contains_all(
        &readme,
        &[
            "API 稳定性",
            "docs/api-stability.md",
            "docs/feature-matrix.md",
            "docs/migrations/README.md",
            &format!("Rust `{MSRV}`"),
        ],
    );

    let docs_index = read("docs/README.md");
    support::assert_contains_all(
        &docs_index,
        &[
            "API 稳定性",
            "api-stability.md",
            "feature-matrix.md",
            "migrations/README.md",
        ],
    );

    let stability = read("docs/api-stability.md");
    support::assert_contains_all(
        &stability,
        &[
            "不承诺 `1.0` 稳定性",
            &format!("当前 MSRV 是 Rust `{MSRV}`"),
            "feature matrix",
            "migrations/README.md",
            "稳定面",
            "非承诺项",
            "cargo +1.87 check",
        ],
    );
}

#[test]
fn feature_matrix_covers_manifest_features_and_validation_commands() {
    let matrix = read("docs/feature-matrix.md");
    for feature in FEATURES {
        assert!(
            matrix.contains(&format!("`{feature}`")),
            "feature matrix must document `{feature}`"
        );
    }

    support::assert_contains_all(
        &matrix,
        &[
            "cargo check -p rs-zero --no-default-features",
            "cargo check -p rs-zero --no-default-features --features rest,rpc",
            "cargo check -p rs-zero --no-default-features --features db-mysql,db-postgres,cache-redis,discovery-etcd,discovery-kube,otlp",
            "cargo test -p rs-zero --test service_group",
            "cargo package -p rs-zero --allow-dirty",
            "cargo package -p rs-zero-cli --allow-dirty",
            "scripts/external-integration.sh all",
        ],
    );
}

#[test]
fn migration_docs_define_current_baseline_and_entry_template() {
    let index_path = Path::new("docs/migrations/README.md");
    let baseline_path = Path::new("docs/migrations/0.1.md");
    assert!(index_path.exists(), "migration index must exist");
    assert!(baseline_path.exists(), "0.1 migration baseline must exist");

    let index = read(index_path);
    support::assert_contains_all(
        &index,
        &["0.1.x", "条目模板", "影响范围", "迁移步骤", "MSRV"],
    );

    let baseline = read(baseline_path);
    support::assert_contains_all(
        &baseline,
        &[
            &format!("workspace 版本：`{VERSION}`"),
            &format!("MSRV：Rust `{MSRV}`"),
            "默认 runtime features",
            "外部 adapter features",
            "升级检查清单",
        ],
    );
}

#[test]
fn verify_yaml_runs_api_stability_guard() {
    let verify = read(".helloagents/verify.yaml");
    support::assert_contains_all(
        &verify,
        &[
            "cargo test --test api_stability",
            "cargo test -p rs-zero --test service_group",
            "cargo test -p rs-zero --test service_group_adapters",
        ],
    );
}

fn read(path: impl AsRef<Path>) -> String {
    fs::read_to_string(path.as_ref()).unwrap_or_else(|err| {
        panic!("read {}: {err}", path.as_ref().display());
    })
}
