package app

import (
	
	
	
	
	

	
	
)

// Context represents a UI element-associated environment enabling interactions
// with the browser, page navigation, concurrency, and component communication.
type Context struct {
	context.Context

	page                  func() Page
	appUpdatable          bool
	resolveURL            func(string) string
	navigate              func(*url.URL, bool)
	localStorage          BrowserStorage
	sessionStorage        BrowserStorage
	dispatch              func(func())
	defere                func(func())
	async                 func(func())
	addComponentUpdate    func(Composer, int)
	removeComponentUpdate func(Composer)
	handleAction          func(string, UI, bool, ActionHandler)
	postAction            func(Context, Action)
	observeState          func(Context, string, any) Observer
	getState              func(Context, string, any)
	setState              func(Context, string, any) State
	delState              func(Context, string)

	sourceElement        UI
	notifyComponentEvent func(Context, UI, any)
}

// Src retrieves the linked UI element of the context.
func ( Context) () UI {
	return .sourceElement
}

// JSSrc fetches the JavaScript representation of the associated UI element.
func ( Context) () Value {
	return .sourceElement.JSValue()
}

// AppUpdateAvailable checks if there's a pending app update.
func ( Context) () bool {
	return .appUpdatable
}

// IsAppInstallable verifies if the app is eligible for installation.
func ( Context) () bool {
	if Window().Get("goappIsAppInstallable").Truthy() {
		return Window().Call("goappIsAppInstallable").Bool()
	}
	return false
}

// IsAppleBrowser reports whether the app is running on an Apple browser.
func ( Context) () bool {
	if Window().Get("goappIsAppleBrowser").Truthy() {
		return Window().Call("goappIsAppleBrowser").Bool()
	}
	return false
}

// ShowAppInstallPrompt initiates the app installation process.
func ( Context) () {
	if .IsAppInstallable() {
		Window().Call("goappShowInstallPrompt")
	}
}

// DeviceID fetches a distinct identifier for the app on the present device.
func ( Context) () string {
	var  string
	if  := .localStorage.Get("/go-app/deviceID", &);  != nil {
		panic(errors.New("retrieving device id failed").Wrap())
	}
	if  != "" {
		return 
	}

	 = uuid.NewString()
	if  := .localStorage.Set("/go-app/deviceID", );  != nil {
		panic(errors.New("creating device id failed").Wrap())
	}
	return 
}

// Page retrieves the current active page.
func ( Context) () Page {
	return .page()
}

// Reload refreshes the present page.
func ( Context) () {
	if IsServer {
		return
	}
	Window().Get("location").Call("reload")
}

// Navigate transitions to the given URL string.
func ( Context) ( string) {
	,  := url.Parse()
	if  != nil {
		Log(errors.New("navigating to URL failed").
			WithTag("url", ).
			Wrap())
		return
	}
	.NavigateTo()
}

// NavigateTo transitions to the provided URL.
func ( Context) ( *url.URL) {
	.navigate(, true)
}

// ResolveStaticResource adjusts a given path to point to the correct static
// resource location.
func ( Context) ( string) string {
	return .resolveURL()
}

// ScrollTo adjusts the scrollbar to target an HTML element by its ID.
func ( Context) ( string) {
	.Defer(func( Context) {
		Window().ScrollToID()
	})
}

// LocalStorage accesses the browser's local storage tied to the document
// origin.
func ( Context) () BrowserStorage {
	return .localStorage
}

// SessionStorage accesses the browser's session storage tied to the
// document origin.
func ( Context) () BrowserStorage {
	return .sessionStorage
}

// Encrypt enciphers a value using AES encryption.
func ( Context) ( any) ([]byte, error) {
	,  := json.Marshal()
	if  != nil {
		return nil, errors.New("encoding value failed").Wrap()
	}

	,  = encrypt(.cryptoKey(), )
	if  != nil {
		return nil, errors.New("encrypting value failed").Wrap()
	}
	return , nil
}

// Decrypt deciphers encrypted data into a given reference value.
func ( Context) ( []byte,  any) error {
	,  := decrypt(.cryptoKey(), )
	if  != nil {
		return errors.New("decrypting value failed").Wrap()
	}

	if  := json.Unmarshal(, );  != nil {
		return errors.New("decoding value failed").Wrap()
	}
	return nil
}

func ( Context) () string {
	return strings.ReplaceAll(.DeviceID(), "-", "")
}

// Notifications accesses the notifications service.
func ( Context) () NotificationService {
	return NotificationService{}
}

// Dispatch prompts the execution of a function on the UI goroutine,
// flagging the enclosing component for an update.
func ( Context) ( func(Context)) {
	.dispatch(func() {
		if !.sourceElement.Mounted() {
			return
		}

		for ,  := component(.sourceElement); ; ,  = component(.parent()) {
			.addComponentUpdate(, 1)
		}

		if  != nil {
			()
		}
	})
}

// Defer postpones the function execution on the UI goroutine until the
// current update cycle completes.
func ( Context) ( func(Context)) {
	.defere(func() {
		if !.sourceElement.Mounted() {
			return
		}

		if  != nil {
			()
		}
	})
}

// Async initiates a function asynchronously. It enables go-app to monitor
// goroutines, ensuring they conclude when rendering server-side.
func ( Context) ( func()) {
	.async()
}

// After pauses for a determined span, then triggers a specified function.
func ( Context) ( time.Duration,  func(Context)) {
	.async(func() {
		time.Sleep()
		.Dispatch()
	})
}

// PreventUpdate halts updates for the enclosing component.
func ( Context) () {
	for ,  := component(.sourceElement); ; ,  = component(.parent()) {
		.addComponentUpdate(, -1)
	}
}

// Update flags the enclosing component for an update.
func ( Context) () {
	.Dispatch(nil)
}

// Handle designates a handler for a particular action, set to run on the UI
// goroutine.
func ( Context) ( string,  ActionHandler) {
	.handleAction(, .sourceElement, false, )
}

// NewAction generates a new action for handling.
func ( Context) ( string,  ...Tagger) {
	.NewActionWithValue(, nil, ...)

}

// NewActionWithValue crafts an action with a given value for processing.
func ( Context) ( string,  any,  ...Tagger) {
	var  Tags
	for ,  := range  {
		if  == nil {
			 = make(Tags)
		}

		for ,  := range .Tags() {
			[] = 
		}
	}

	.postAction(, Action{
		Name:  ,
		Value: ,
		Tags:  ,
	})
}

// ObserveState establishes an observer for a state, tracking its changes.
func ( Context) ( string,  any) Observer {
	return .observeState(, , )
}

// GetState fetches the value of a particular state.
func ( Context) ( string,  any) {
	.getState(, , )
}

// SetState modifies a state with the provided value.
func ( Context) ( string,  any) State {
	return .setState(, , )
}

// DelState erases a state, halting all associated observations.
func ( Context) ( string) {
	.delState(, )
}

// ResizeContent notifies the children of the associated element that implement
// the Resizer interface about a resize event. It ensures that components can
// adjust their size and layout in response to changes. This method is typically
// used when the size of the container changes, requiring child components to
// update their dimensions accordingly.
func ( Context) () {
	.Defer(func( Context) {
		.Dispatch(func( Context) {
			.notifyComponentEvent(, .Src(), resize{})
		})
	})
}