package utils

import (
	
	
	
	
	
	
	
	
	

	
	am 
)

// EnvAmHostname will override the hostname in all machine names.
const EnvAmHostname = "AM_HOSTNAME"

// J joins state names into a single string
func ( []string) string {
	return strings.Join(, " ")
}

// Jw joins state names into a single string with a separator.
func ( []string,  string) string {
	return strings.Join(, )
}

func () string {
	,  := debug.ReadBuildInfo()
	if ! {
		return "(devel)"
	}

	 := .Main.Version
	if  == "" {
		return "(devel)"
	}

	return 
}

// TODO remove if that speeds things up
func [ any]( chan ) {
	select {
	case <-:
	default:
		close()
	}
}

func [ ~[],  comparable]( ,  )  {
	 := slices.Index(, )
	 := slices.Clone()
	if  == -1 {
		return 
	}
	return slices.Delete(, , +1)
}

// SlicesNone returns true if none of the elements of coll2 are in coll1.
func [ ~[],  ~[],  comparable]( ,  ) bool {
	for ,  := range  {
		if slices.Contains(, ) {
			return false
		}
	}
	return true
}

// SlicesEvery returns true if all elements of coll2 are in coll1.
func [ ~[],  ~[],  comparable]( ,  ) bool {
	for ,  := range  {
		if !slices.Contains(, ) {
			return false
		}
	}
	return true
}

func [ ~[],  comparable]( )  {
	var  
	for ,  := range  {
		if !slices.Contains(, ) {
			 = append(, )
		}
	}
	return 
}

// RandId generates a random ID of the given length (defaults to 8).
func ( int) string {
	if  == 0 {
		 = 16
	}
	++
	 =  / 2

	 := make([]byte, )
	,  := rand.Read()
	if  != nil {
		return "error"
	}

	return hex.EncodeToString()
}

func () string {
	if  := os.Getenv(EnvAmHostname);  != "" {
		return 
	}
	,  := os.Hostname()
	if  == "" {
		 = "localhost"
	}

	return 
}

func ( string,  ...any) string {
	return fmt.Sprintf(dedent.Dedent(strings.Trim(, "\n")), ...)
}

func ( string,  ...any) {
	fmt.Printf(dedent.Dedent(strings.Trim(, "\n")), ...)
}

// TruncateStr with shorten the string and leave a tripedot suffix.
func ( string,  int) string {
	if len() <=  {
		return 
	}
	if  < 5 {
		return [:]
	} else {
		return [:-3] + "..."
	}
}

func ( string,  int,  string) string {
	for {
		 += 
		if len() >  {
			return [0:]
		}
	}
}

func () string {
	 := make([]byte, 4024)
	 := runtime.Stack(, false)
	 := string([:])
	 := strings.Split(, "\n")
	 := strings.Contains(, "panic")
	slices.Reverse()

	 := []string{
		"AddErr", "AddErrState", "Remove", "Remove1", "Add", "Add1", "Set",
	}
	// TODO trim tails start at reflect.Value.Call({
	//  with asyncmachine 2 frames down

	// trim the head, remove junk
	 := false
	for ,  := range  {
		if  && strings.HasPrefix(, "panic(") {
			 = [:-1]
			break
		}

		for ,  := range  {
			if strings.Contains("machine.(*Machine)."++"(", ) {
				 = [:-1]
				 = true
				break
			}
		}
		if  {
			break
		}
	}
	slices.Reverse()
	 := strings.Join(, "\n")

	if  := os.Getenv(am.EnvAmTraceFilter);  != "" {
		 = strings.ReplaceAll(, , "")
	}

	return 
}

func ( interface{}) ([]string, error) {
	 := reflect.ValueOf()
	 := .Type()

	// validate
	if .Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected a struct, got %s", .Kind())
	}

	var  []string
	for  := 0;  < .NumField(); ++ {
		 := .Field()
		 := .Field() // Get the value of the fieldh

		// nested args
		if .Type.Kind() == reflect.Pointer {
			 := .Type.Elem()
			if .Kind() == reflect.Struct {
				if .IsNil() {
					// skip nil pointers
					continue
				}

				 := .Elem().Interface()
				,  := ()
				if  != nil {
					return nil, 
				}
				 = append(, ...)
			}
		} else {
			 = append(, .Name)
		}
	}

	return , nil
}