package packs

import (
	"go/ast"
	"go/parser"
	"go/token"
	"path/filepath"
	"runtime"
	"testing"
)

func TestManagedLifecycleCoordinatorsShareOneAttemptEngine(t *testing.T) {
	_, currentFile, _, ok := runtime.Caller(0)
	if !ok {
		t.Fatal("resolve managed lifecycle structure test path")
	}
	directory := filepath.Dir(currentFile)
	files := []string{
		"managed_lifecycle_attempt.go",
		"managed_lifecycle_ambient_stage.go",
		"managed_lifecycle_host.go",
	}
	calls := make(map[string]map[string]int, len(files))
	for _, name := range files {
		parsed, err := parser.ParseFile(token.NewFileSet(), filepath.Join(directory, name), nil, 0)
		if err != nil {
			t.Fatalf("parse %s: %v", name, err)
		}
		calls[name] = make(map[string]int)
		ast.Inspect(parsed, func(node ast.Node) bool {
			call, ok := node.(*ast.CallExpr)
			if !ok {
				return true
			}
			switch function := call.Fun.(type) {
			case *ast.Ident:
				calls[name][function.Name]++
			case *ast.SelectorExpr:
				calls[name][function.Sel.Name]++
			}
			return true
		})
	}
	for _, coordinator := range []string{"managed_lifecycle_host.go", "managed_lifecycle_ambient_stage.go"} {
		if calls[coordinator]["runManagedLifecycleAttempt"] != 1 {
			t.Fatalf("%s attempt-engine calls = %d, want 1", coordinator, calls[coordinator]["runManagedLifecycleAttempt"])
		}
	}
	for _, operation := range []string{
		"newManagedLifecycleMutationStore",
		"validateManagedLifecycleStagedMutation",
		"applyEffects",
		"insertManagedLifecycleEvidence",
	} {
		if calls["managed_lifecycle_attempt.go"][operation] != 1 {
			t.Fatalf("attempt engine %s calls = %d, want 1", operation, calls["managed_lifecycle_attempt.go"][operation])
		}
		for _, coordinator := range []string{"managed_lifecycle_host.go", "managed_lifecycle_ambient_stage.go"} {
			if calls[coordinator][operation] != 0 {
				t.Fatalf("%s must not call %s outside the shared attempt engine", coordinator, operation)
			}
		}
	}
}
