package app

import (
	
	
)

// Action represents a custom event that can be propagated across the app. It
// can carry a payload and be enriched with additional contextual tags.
type Action struct {
	// Name uniquely identifies the action.
	Name string

	// Value is the data associated with the action and can be nil.
	Value any

	// Tags provide additional context or metadata for the action.
	Tags Tags
}

// ActionHandler defines a callback executed when an action is triggered
// via Context.NewAction().
type ActionHandler func(Context, Action)

// Handle registers the provided handler for a specific action name. When that
// action is triggered, the handler executes in a separate goroutine.
func ( string,  ActionHandler) {
	actionHandlers[] = 
}

var actionHandlers = make(map[string]ActionHandler)

type actionHandler struct {
	Source   UI
	Function ActionHandler
	Async    bool
}

// actionManager manages the registration and execution of action handlers. It
// ensures that only actions related to mounted sources are processed.
type actionManager struct {
	mutex    sync.Mutex
	handlers map[string]map[string]actionHandler
}

// Handle registers an ActionHandler for the given action and source.
func ( *actionManager) ( string,  UI,  bool,  ActionHandler) {
	.mutex.Lock()
	defer .mutex.Unlock()

	if .handlers == nil {
		.handlers = make(map[string]map[string]actionHandler)
	}

	,  := .handlers[]
	if ! {
		 = make(map[string]actionHandler)
		.handlers[] = 
	}

	 := actionHandlerKey(, )
	[] = actionHandler{
		Source:   ,
		Function: ,
		Async:    ,
	}
}

// Post processes the provided action by executing its associated handlers.
func ( *actionManager) ( Context,  Action) {
	.mutex.Lock()
	defer .mutex.Unlock()

	for ,  := range .handlers[.Name] {
		 := .Source
		if !.Mounted() {
			delete(.handlers[.Name], )
			continue
		}
		.sourceElement = 

		 := .Function
		if .Async {
			.Async(func() {
				(, )
			})
			continue
		}

		.Dispatch(func( Context) {
			(, )
		})
	}
}

// Cleanup removes handlers corresponding to unmounted sources.
func ( *actionManager) () {
	.mutex.Lock()
	defer .mutex.Unlock()

	for ,  := range .handlers {
		for ,  := range  {
			if !.Source.Mounted() {
				delete(, )
			}
		}

		if len() == 0 {
			delete(.handlers, )
		}
	}
}

func actionHandlerKey( UI,  ActionHandler) string {
	return fmt.Sprintf("/%T/%p/%p", , , )
}