package catalogpublication

import "testing"

func TestOutcomeDigestBindsTerminalResult(t *testing.T) {
	base := Outcome{
		OrgID:                      "org-1",
		CommandID:                  "018f0000-0000-7000-9000-000000000001",
		CandidatePublicationDigest: testDigest("1"),
		Result:                     ResultSelected,
		ObservedPrior:              Reference{},
		ResultingActive:            Reference{Present: true, Digest: testDigest("1")},
	}
	digest, err := canonicalOutcomeDigest(base)
	if err != nil || digest == "" {
		t.Fatalf("valid outcome digest = %q, %v", digest, err)
	}

	mutations := map[string]func(*Outcome){
		"org":     func(value *Outcome) { value.OrgID = "org-2" },
		"command": func(value *Outcome) { value.CommandID = "018f0000-0000-7000-9000-000000000002" },
		"candidate": func(value *Outcome) {
			value.CandidatePublicationDigest = testDigest("2")
			value.ResultingActive.Digest = testDigest("2")
		},
		"prior": func(value *Outcome) { value.ObservedPrior = Reference{Present: true, Digest: testDigest("9")} },
	}
	for name, mutate := range mutations {
		t.Run(name, func(t *testing.T) {
			changed := base
			mutate(&changed)
			changedDigest, err := canonicalOutcomeDigest(changed)
			if err != nil {
				t.Fatal(err)
			}
			if changedDigest == digest {
				t.Fatal("semantic change did not change outcome digest")
			}
		})
	}
}

func TestOutcomeValidationEnforcesResultSemantics(t *testing.T) {
	candidate := testDigest("1")
	prior := Reference{Present: true, Digest: candidate}
	tests := map[string]Outcome{
		"selected does not activate candidate": {
			Result: ResultSelected, ResultingActive: Reference{Present: true, Digest: testDigest("2")},
		},
		"unchanged without selected candidate": {
			Result: ResultUnchanged, ObservedPrior: Reference{}, ResultingActive: Reference{},
		},
		"mismatch changes active": {
			Result: ResultExpectedPriorMismatch, ObservedPrior: Reference{}, ResultingActive: prior,
		},
		"unknown result": {Result: Result("UNKNOWN")},
	}
	for name, outcome := range tests {
		t.Run(name, func(t *testing.T) {
			outcome.OrgID = "org-1"
			outcome.CommandID = "018f0000-0000-7000-9000-000000000001"
			outcome.CandidatePublicationDigest = candidate
			if _, err := canonicalOutcomeDigest(outcome); err == nil {
				t.Fatal("invalid outcome accepted")
			}
		})
	}
}
