package runtimeworker

import (
	"reflect"
	"testing"
)

func TestWorkerPermissionStateProcessInputsCombineCapabilitiesAndReadiness(t *testing.T) {
	ownershipReady := true
	gate := &workerPermissionStateGateStub{
		capabilities: []string{
			"permission_state.v1",
			"permission_state.role=reader-writer",
		},
		ready: true,
	}
	capabilities, ready, err := workerPermissionStateProcessInputs(
		"runtime.record-event-dispatch.v1",
		gate,
		func() bool { return ownershipReady },
	)
	if err != nil {
		t.Fatal(err)
	}
	if want := []string{
		"runtime.record-event-dispatch.v1",
		"permission_state.v1",
		"permission_state.role=reader-writer",
	}; !reflect.DeepEqual(capabilities, want) {
		t.Fatalf("capabilities = %v, want %v", capabilities, want)
	}
	if !ready() {
		t.Fatal("combined readiness rejected two ready owners")
	}
	ownershipReady = false
	if ready() {
		t.Fatal("combined readiness ignored ownership loss")
	}
	ownershipReady = true
	gate.ready = false
	if ready() {
		t.Fatal("combined readiness ignored Permission State loss")
	}
}

func TestWorkerPermissionStateProcessInputsRejectIncompleteComposition(t *testing.T) {
	for _, test := range []struct {
		name       string
		workFamily string
		gate       workerPermissionStateGate
		ready      func() bool
	}{
		{name: "missing family", gate: &workerPermissionStateGateStub{}, ready: func() bool { return true }},
		{name: "missing gate", workFamily: "runtime.test.v1", ready: func() bool { return true }},
		{name: "missing ownership readiness", workFamily: "runtime.test.v1", gate: &workerPermissionStateGateStub{}},
	} {
		t.Run(test.name, func(t *testing.T) {
			if _, _, err := workerPermissionStateProcessInputs(
				test.workFamily,
				test.gate,
				test.ready,
			); err == nil {
				t.Fatal("incomplete worker Permission State composition was accepted")
			}
		})
	}
}

func TestObservedPermissionStateGateRecordsChecksWithoutChangingResult(t *testing.T) {
	stub := &workerPermissionStateGateStub{ready: true}
	gate := &observedWorkerPermissionStateGate{gate: stub}
	if !gate.Ready() {
		t.Fatal("observed gate changed successful readiness")
	}
	stub.ready = false
	if gate.Ready() {
		t.Fatal("observed gate changed failed readiness")
	}
	snapshot := gate.snapshot()
	if snapshot.Checks != 2 || snapshot.Failures != 1 {
		t.Fatalf("snapshot = %+v, want two checks and one failure", snapshot)
	}
	if snapshot.LastSuccess.IsZero() {
		t.Fatal("successful Permission State check timestamp was not retained")
	}
}

type workerPermissionStateGateStub struct {
	capabilities []string
	ready        bool
}

func (gate *workerPermissionStateGateStub) Capabilities() []string {
	return append([]string(nil), gate.capabilities...)
}

func (gate *workerPermissionStateGateStub) Ready() bool {
	return gate != nil && gate.ready
}
