// Acceptance for P3.2 — the v0 publish manifest model + parse + validate.
//
// 1. Parses `examples/dist.json` into a typed `Manifest` and asserts the
//    fields (app/version/channel, the artifact count, and each artifact's
//    platform + path).
// 2. Asserts each failure class surfaces a DISTINCT machine-readable error
//    (never a silent default):
//      - a missing required field (a manifest lacking `version`)  -> MissingField
//      - an unknown platform ("psvita")                           -> UnknownPlatform
//      - a non-existent artifact path                             -> MissingArtifact
//
// Prints a PASS/FAIL line per case and exits non-zero if any case behaves
// unexpectedly, so the test runner counts it as a failure.
#import "modules/std.sx";
#import "../src/domain/platform.sx";
#import "../src/manifest/manifest.sx";

// ── happy path: examples/dist.json -> typed Manifest ────────────────────
check_parse_valid :: (alloc: Allocator) -> bool {
    m, e := load_manifest("examples/dist.json", alloc);
    if e { return false; }
    if m.app != "acme-app" { return false; }
    if m.version != "1.2.3" { return false; }
    if m.channel != "stable" { return false; }
    if m.artifacts.len != 2 { return false; }

    a0 := m.artifacts.items[0];
    if a0.platform != .android_apk { return false; }
    if a0.path != "fixtures/acme-1.2.3-android.apk" { return false; }
    if a0.filename != "acme.apk" { return false; }
    if a0.content_type != "application/vnd.android.package-archive" { return false; }

    a1 := m.artifacts.items[1];
    if a1.platform != .ios { return false; }
    if a1.path != "fixtures/acme-1.2.3-ios.ipa" { return false; }
    if a1.filename != "" { return false; }          // optional override, absent -> ""
    return true;
}

// ── failure: a required field (version) is absent -> MissingField ───────
check_missing_version :: (alloc: Allocator) -> bool {
    src := "{\"app\":\"acme-app\",\"channel\":\"stable\",\"artifacts\":[{\"platform\":\"ios\",\"path\":\"fixtures/acme-1.2.3-ios.ipa\"}]}";
    _, e := parse_manifest(src, alloc);
    return e == error.MissingField;
}

// ── failure: an artifact platform id is unknown -> UnknownPlatform ──────
check_unknown_platform :: (alloc: Allocator) -> bool {
    src := "{\"app\":\"acme-app\",\"version\":\"1.2.3\",\"channel\":\"stable\",\"artifacts\":[{\"platform\":\"psvita\",\"path\":\"fixtures/acme-1.2.3-ios.ipa\"}]}";
    _, e := parse_manifest(src, alloc);
    return e == error.UnknownPlatform;
}

// ── failure: an artifact path does not exist on disk -> MissingArtifact ─
// Parse SUCCEEDS (parse is filesystem-free); the missing file surfaces only
// at validate time, against the manifest's base directory.
check_missing_artifact_path :: (alloc: Allocator) -> bool {
    src := "{\"app\":\"acme-app\",\"version\":\"1.2.3\",\"channel\":\"stable\",\"artifacts\":[{\"platform\":\"ios\",\"path\":\"fixtures/does-not-exist.ipa\"}]}";
    m, pe := parse_manifest(src, alloc);
    if pe { return false; }                          // parse must not fail here
    raised := false;
    matched := false;
    validate_manifest(m, "examples") catch (err) { raised = true; matched = (err == error.MissingArtifact); };
    return raised and matched;
}

run_case :: (label: string, ok: bool) -> i32 {
    if ok { print("  PASS  {}\n", label); return 0; }
    print("  FAIL  {}\n", label);
    return 1;
}

main :: () -> i32 {
    gpa := GPA.init();
    arena := Arena.init(xx gpa, 65536);
    defer arena.deinit();

    failures : i32 = 0;
    failures += run_case("parse valid dist.json -> fields",            check_parse_valid(xx arena));
    failures += run_case("missing version -> MissingField",            check_missing_version(xx arena));
    failures += run_case("unknown platform 'psvita' -> UnknownPlatform", check_unknown_platform(xx arena));
    failures += run_case("nonexistent path -> MissingArtifact",        check_missing_artifact_path(xx arena));

    print("------------------------------------------------\n");
    if failures == 0 {
        print("manifest_parse: ALL CASES PASS\n");
        return 0;
    }
    print("manifest_parse: {} CASE(S) FAILED\n", failures);
    return 1;
}
