package machine

import (
	
	
	
	
)

// Mutation represents an atomic change (or an attempt) of machine's active
// states. Mutation causes a Transition.
type Mutation struct {
	// add, set, remove
	Type MutationType
	// States explicitly passed to the mutation method, as their indexes. Use
	// Transition.CalledStates or IndexToStates to get the actual state names.
	Called []int
	// argument map passed to the mutation method (if any).
	Args A
	// this mutation has been triggered by an auto state
	// TODO rename to IsAuto
	IsAuto bool
	// Source is the source event for this mutation.
	Source *MutSource
	// IsCheck indicates that this mutation is a check, see [Machine.CanAdd].
	IsCheck bool

	// optional queue info

	// QueueTickNow is the queue tick during which this mutation was scheduled.
	QueueTickNow uint64
	// QueueLen is the length of the queue at the time when the mutation was
	// queued.
	QueueLen int32
	// QueueTokensLen is the amount of unexecuted queue tokens (priority queue).
	// TODO impl
	QueueTokensLen int32
	// QueueTick is the assigned queue tick at the time when the mutation was
	// queued. 0 for prepended mutations.
	QueueTick uint64
	// QueueToken is a unique ID, which is given to prepended mutations.
	// Tokens are assigned in a series but executed in random order.
	QueueToken uint64

	// internals

	// specific context for this mutation (optional)
	ctx context.Context
	// optional eval func, only for mutationEval
	eval        func()
	evalSource  string
	cacheCalled atomic.Pointer[S]
}

func ( *Mutation) () string {
	return fmt.Sprintf("[%s] %v", .Type, .Called)
}

func ( *Mutation) ( int) bool {
	return slices.Contains(.Called, )
}

func ( *Mutation) ( S) *TimeIndex {
	return NewTimeIndex(, .Called)
}

func ( *Mutation) ( S) string {
	 := NewTimeIndex(, .Called)
	return "[" + .Type.String() + "] " + j(.ActiveStates(nil))
}

// MapArgs returns arguments of this Mutation which match the passed [mapper].
// The returned map is never nil.
func ( *Mutation) ( LogArgsMapperFn) map[string]string {
	if  == nil {
		return map[string]string{}
	}

	if  := (.Args);  == nil {
		return map[string]string{}
	} else {
		return 
	}
}

// LogArgs returns a text snippet with arguments which should be logged for this
// Mutation.
func ( *Mutation) ( LogArgsMapperFn) string {
	return MutationFormatArgs(.MapArgs())
}

// StepType enum
type StepType int8

const (
	StepRelation StepType = 1 << iota
	StepHandler
	// TODO rename to StepActivate
	StepSet
	// StepRemove indicates a step where a state goes active->inactive
	// TODO rename to StepDeactivate
	StepRemove
	// StepRemoveNotActive indicates a step where a state goes inactive->inactive
	// TODO rename to StepDeactivatePassive
	StepRemoveNotActive
	StepRequested
	StepCancel
)

func ( StepType) () string {
	switch  {
	case StepRelation:
		return "rel"
	case StepHandler:
		return "handler"
	case StepSet:
		return "activate"
	case StepRemove:
		return "deactivate"
	case StepRemoveNotActive:
		return "deactivate-passive"
	case StepRequested:
		return "requested"
	case StepCancel:
		return "cancel"
	}
	return ""
}

// Step struct represents a single step within a Transition, either a relation
// resolving step or a handler call.
type Step struct {
	Type StepType
	// Only for Type == StepRelation.
	RelType Relation
	// marks a final handler (FooState, FooEnd)
	IsFinal bool
	// marks a self handler (FooFoo)
	IsSelf bool
	// marks an enter handler (FooState, but not FooEnd). Requires IsFinal.
	IsEnter bool
	// Deprecated, use GetFromState(). TODO remove
	FromState string
	// TODO implement
	FromStateIdx int
	// Deprecated, use GetToState(). TODO remove
	ToState string
	// TODO implement
	ToStateIdx int
	// Deprecated, use RelType. TODO remove
	Data any
	// TODO emitter name and num
}

// GetFromState returns the source state of a step. Optional, unless no
// GetToState().
func ( *Step) ( S) string {
	// TODO rename to FromState
	if .FromState != "" {
		return .FromState
	}
	if .FromStateIdx == -1 {
		return ""
	}
	if .FromStateIdx < len() {
		return [.FromStateIdx]
	}

	return ""
}

// GetToState returns the target state of a step. Optional, unless no
// GetFromState().
func ( *Step) ( S) string {
	// TODO rename to ToState
	if .ToState != "" {
		return .ToState
	}
	if .ToStateIdx == -1 {
		return ""
	}
	if .ToStateIdx < len() {
		return [.ToStateIdx]
	}

	return ""
}

func ( *Step) ( S) string {
	var  string

	// collect
	 := .GetFromState()
	 := .GetToState()
	if  == "" &&  == "" {
		 = StateAny
	}

	// format TODO markdown?
	if  != "" {
		 = "**" +  + "**"
	}
	if  != "" {
		 = "**" +  + "**"
	}

	// output
	if  != "" &&  != "" {
		 +=  + " " + .RelType.String() + " " + 
	} else {
		 = 
	}
	if  == "" {
		 = 
	}

	if .Type == StepRelation {
		return 
	}

	 := ""
	if .Type == StepHandler {
		if .IsSelf {
			 = 
		} else if .IsFinal && .IsEnter {
			 = SuffixState
		} else if .IsFinal && !.IsEnter {
			 = SuffixEnd
		} else if !.IsFinal && .IsEnter {
			 = SuffixEnter
		} else if !.IsFinal && !.IsEnter {
			 = SuffixExit
		}
	}

	// infer the name
	return .Type.String() + " " +  + 
}

func newStep( string,  string,  StepType,
	 Relation,
) *Step {
	 := &Step{
		// TODO refac with the new dbg protocol, use indexes only
		FromState: ,
		ToState:   ,
		Type:      ,
		RelType:   ,
	}
	// default values TODO use real values
	if  == "" {
		.FromStateIdx = -1
	}
	if  == "" {
		.ToStateIdx = -1
	}

	return 
}

func newSteps( string,  S,  StepType,
	 Relation,
) []*Step {
	// TODO optimize, only use during debug
	var  []*Step
	for ,  := range  {
		 = append(, newStep(, , , ))
	}

	return 
}