package utils

import (
	
	
	
	
	
	
	
	
	
	
	

	
	

	ss 
	am 
	ssnode 
	ssrpc 
)

const EnvAmTestRunner = "AM_TEST_RUNNER"

var (
	ports    []int
	ConnInit sync.Mutex
)

func (,  int) string {

	 := rand.Intn(-+1) + 
	for slices.Contains(ports, ) {
		 = rand.Intn(-+1) + 
	}
	// remember used ports, but dont reuse them
	ports = append(ports, )

	return strconv.Itoa()
}

// RandListener creates a new listener on an open port between 40000 and 50000.
// It allows avoiding conflicts with other tests, using predefined addresses,
// unlike using port 0.
func ( string) net.Listener {

	ConnInit.Lock()
	defer ConnInit.Unlock()

	// var (
	// 	err error
	// 	l   net.Listener
	// )
	//
	// // try 10 times
	// for i := 0; i < 10; i++ {

	// addr := host + ":" + RandPort(40000, 50000)
	,  := net.Listen("tcp4", +":0")
	if  == nil {
		return 
	}
	// }

	panic("could not create listener on " + )
}

// NewRels creates a new machine with basic relations between ABCD states.
func ( *testing.T,  am.S) *am.Machine {
	// machine init
	 := am.New(context.Background(), ss.States, &am.Opts{
		Id: "t-" + .Name()})
	 := .VerifyStates(ss.Names)
	if  != nil {
		.Fatal()
	}

	.SemLogger().SetLevel(am.EnvLogLevel(os.Getenv(am.EnvAmLog)))
	if os.Getenv(am.EnvAmDebug) != "" && os.Getenv(EnvAmTestRunner) == "" {
		.HandlerTimeout = 2 * time.Minute
	}
	if  != nil {
		.Set(, nil)
	}
	.SemLogger().SetArgsMapper(am.NewArgsMapper(am.LogArgs, 50))

	return 
}

// NewRelsRpcWorker creates a new RPC worker machine with basic relations
// between ABCD states.
func ( *testing.T,  am.S) *am.Machine {

	// inherit from RPC worker

	// TODO define these in /states using v2 as RelWorkerStruct and
	//  RelWorkerStates, inheriting frm RelStructDef etc
	 := am.SchemaMerge(ssrpc.WorkerSchema, ss.States)
	 := am.SAdd(ss.Names, ssrpc.WorkerStates.Names())

	// machine init
	 := am.New(context.Background(), , &am.Opts{
		Id: "t-" + .Name()})
	 := .VerifyStates()
	if  != nil {
		.Fatal()
	}

	.SemLogger().SetLevel(am.EnvLogLevel(os.Getenv(am.EnvAmLog)))
	if os.Getenv(am.EnvAmDebug) != "" && os.Getenv(EnvAmTestRunner) == "" {
		.HandlerTimeout = 2 * time.Minute
	}
	if  != nil {
		.Set(, nil)
	}

	return 
}

// inherit from RPC worker

var (
	RelsNodeWorkerSchema = am.SchemaMerge(ssnode.WorkerSchema, ss.States)
	RelsNodeWorkerStates = am.SAdd(ss.Names, ssnode.WorkerStates.Names())
)

// NewRelsNodeWorker creates a new Node worker machine with basic relations
// between ABCD states.
func ( *testing.T,  am.S) *am.Machine {

	// machine init
	 := am.New(context.Background(), RelsNodeWorkerSchema, &am.Opts{
		Id: "t-" + .Name()})
	 := .VerifyStates(RelsNodeWorkerStates)
	if  != nil {
		.Fatal()
	}

	.SemLogger().SetLevel(am.EnvLogLevel(os.Getenv(am.EnvAmLog)))
	if os.Getenv(am.EnvAmDebug) != "" && os.Getenv(EnvAmTestRunner) == "" {
		.HandlerTimeout = 2 * time.Minute
	}
	if  != nil {
		.Set(, nil)
	}
	.SemLogger().SetArgsMapper(am.NewArgsMapper(am.LogArgs, 50))

	return 
}

// NewNoRels creates a new machine without relations between states.
func ( *testing.T,  am.S) *am.Machine {
	// machine init
	 := am.New(context.Background(), am.Schema{
		ss.A: {},
		ss.B: {},
		ss.C: {},
		ss.D: {},
	}, &am.Opts{Id: "t-" + .Name()})
	 := .VerifyStates(ss.Names)
	if  != nil {
		.Fatal()
	}

	.SemLogger().SetLevel(am.EnvLogLevel(os.Getenv(am.EnvAmLog)))
	if os.Getenv(am.EnvAmDebug) != "" && os.Getenv(EnvAmTestRunner) == "" {
		.HandlerTimeout = 2 * time.Minute
	}
	if  != nil {
		.Set(, nil)
	}
	.SemLogger().SetArgsMapper(am.NewArgsMapper(am.LogArgs, 50))

	return 
}

// NewNoRelsRpcWorker creates a new RPC worker without relations between states.
func ( *testing.T,  am.S) *am.Machine {

	// inherit from RPC worker
	 := am.SchemaMerge(ssrpc.WorkerSchema, am.Schema{
		ss.A: {},
		ss.B: {},
		ss.C: {},
		ss.D: {},
	})
	 := am.SAdd(ss.Names, ssrpc.WorkerStates.Names())

	// machine init
	 := am.New(context.Background(), , &am.Opts{Id: "t-" + .Name()})
	 := .VerifyStates()
	if  != nil {
		.Fatal()
	}

	.SemLogger().SetLevel(am.EnvLogLevel(os.Getenv(am.EnvAmLog)))
	if os.Getenv(am.EnvAmDebug) != "" && os.Getenv(EnvAmTestRunner) == "" {
		.HandlerTimeout = 2 * time.Minute
	}
	if  != nil {
		.Set(, nil)
	}
	.SemLogger().SetArgsMapper(am.NewArgsMapper(am.LogArgs, 50))

	return 
}

// NewNoRelsRpcWorkerSchema creates a new RPC worker without relations between
// states and applies a schema overlay.
func (
	 *testing.T,  am.S,  am.Schema) *am.Machine {

	// inherit from RPC worker
	 := am.SchemaMerge(ssrpc.WorkerSchema, am.SchemaMerge(am.Schema{
		ss.A: {},
		ss.B: {},
		ss.C: {},
		ss.D: {},
	}, ))
	 := am.SAdd(ss.Names, ssrpc.WorkerStates.Names())

	// machine init
	 := am.New(context.Background(), , &am.Opts{Id: "t-" + .Name()})
	 := .VerifyStates()
	if  != nil {
		.Fatal()
	}

	.SemLogger().SetLevel(am.EnvLogLevel(os.Getenv(am.EnvAmLog)))
	if os.Getenv(am.EnvAmDebug) != "" && os.Getenv(EnvAmTestRunner) == "" {
		.HandlerTimeout = 2 * time.Minute
	}
	if  != nil {
		.Set(, nil)
	}
	.SemLogger().SetArgsMapper(am.NewArgsMapper(am.LogArgs, 50))

	return 
}

// NewCustom creates a new machine with custom states.
func ( *testing.T,  am.Schema) *am.Machine {
	 := am.New(context.Background(), , &am.Opts{
		Id: "t-" + .Name()})
	 := .VerifyStates(append(maps.Keys(), am.StateException))
	if  != nil {
		.Fatal()
	}

	.SemLogger().SetLevel(am.EnvLogLevel(os.Getenv(am.EnvAmLog)))
	if os.Getenv(am.EnvAmDebug) != "" && os.Getenv(EnvAmTestRunner) == "" {
		.HandlerTimeout = 2 * time.Minute
	}
	.SemLogger().SetArgsMapper(am.NewArgsMapper(am.LogArgs, 50))

	return 
}

// NewCustomRpcWorker creates a new worker with custom states.
func ( *testing.T,  am.Schema) *am.Machine {

	// inherit from RPC worker

	 := am.SchemaMerge(ssrpc.WorkerSchema, )
	 := am.SAdd(maps.Keys(), ssrpc.WorkerStates.Names())

	 := am.New(context.Background(), , &am.Opts{
		Id: "t-" + .Name()})
	 := .VerifyStates()
	if  != nil {
		.Fatal()
	}

	.SemLogger().SetLevel(am.EnvLogLevel(os.Getenv(am.EnvAmLog)))
	if os.Getenv(am.EnvAmDebug) != "" && os.Getenv(EnvAmTestRunner) == "" {
		.HandlerTimeout = 2 * time.Minute
	}
	.SemLogger().SetArgsMapper(am.NewArgsMapper(am.LogArgs, 50))

	return 
}

// KillProcessesByName finds and attempts to terminate all processes with the
// given name. It returns a slice of PIDs that were successfully terminated and
// a slice of errors for any processes that could not be terminated.
func (
	 string) ( []int32,  []error) {

	,  := process.Processes()
	if  != nil {
		 := fmt.Errorf("failed to get process list: %w", )
		return nil, []error{}
	}

	for ,  := range  {
		,  := .Name()
		if  != nil {
			// Skip processes whose names cannot be retrieved (e.g., transient or
			// permission issues)
			continue
		}

		// Use strings.EqualFold for case-insensitive comparison, or `==` for
		// case-sensitive
		if strings.EqualFold(, ) { // Use `name == processName` for
			// exact case match
			 := .Pid

			// Try graceful termination first (SIGTERM)
			if  := .Terminate();  != nil {
				// If graceful termination fails, try forceful kill (SIGKILL)
				if os.IsPermission() {
					 := fmt.Errorf("permission denied for PID %d (%s): %w",
						, , )
					 = append(, )
					continue // Cannot kill this one, move to next
				}

				if  := .Kill();  != nil {
					 := fmt.Errorf("failed to force kill PID %d (%s): %w",
						, , )
					 = append(, )
					continue // Failed to kill, move to next
				}
			}

			// Give the process a very brief moment to react to the signal
			time.Sleep(50 * time.Millisecond)

			// Verify if the process is no longer running
			,  := .IsRunning()
			if  == nil && ! {
				 = append(, )
			} else if  != nil {
				 = append(, fmt.Errorf(
					"could not verify status of PID %d (%s): %w", , , ))
			} else { // stillRunning is true
				 = append(, fmt.Errorf(
					"PID %d (%s) is still running after termination attempts",
					, ))
			}
		}
	}

	return , 
}