// Package ui provides the unified interactive session for keld's TUI.
//
// The session runs a single [tea.Program] that coordinates navigation
// between screens, manages the visual chrome (breadcrumb, title, help
// bar), and handles back navigation and cancellation.
package ui

import (
	"charm.land/bubbles/v2/key"
	tea "charm.land/bubbletea/v2"
)

// Screen is the interface that every step in an interactive flow must
// satisfy. The session delegates input handling and rendering to the
// active screen without knowing its internals.
//
// Screens are constructed before use and may be re-activated when the
// user navigates back. Implementations should preserve their state
// across deactivation/reactivation cycles so previous answers are
// visible when the user returns.
type Screen interface {
	// Init returns the command to run when this screen becomes active.
	// Called both on first activation and when the user navigates back
	// to this screen.
	Init() tea.Cmd

	// Update handles a message and returns the updated screen plus any
	// command. The session forwards all messages to the active screen,
	// including Esc key presses.
	//
	// Screens that use Esc internally (e.g. closing a filter, navigating
	// to a parent directory) should handle it and return normally.
	// Screens that do not need Esc should return a [BackCmd] to signal
	// that the session should navigate back.
	Update(msg tea.Msg) (Screen, tea.Cmd)

	// View renders the screen's content. The session wraps this with
	// chrome (breadcrumb, title, help bar), so the screen should not
	// render those elements itself.
	View() string

	// Title returns the screen's display title, shown below the
	// breadcrumb.
	Title() string

	// KeyBindings returns the key bindings to display in the help bar
	// for this screen. The session adds the global bindings (Esc, Ctrl+C)
	// automatically.
	//
	// The returned slice must not be modified by the caller.
	KeyBindings() []key.Binding

	// Selection returns a short string representing the user's choice
	// on this screen, for display in the breadcrumb. Returns "" if the
	// screen has not been completed yet.
	Selection() string
}

// BackMsg signals that the active screen wants the session to navigate
// back to the previous screen. Screens return this via [BackCmd] when
// they receive an Esc press they do not handle internally.
type BackMsg struct{}

// BackCmd is a [tea.Cmd] that produces a [BackMsg]. Screens should
// return this from their Update method when they receive an Esc press
// and have no internal use for it.
func BackCmd() tea.Msg {
	return BackMsg{}
}

// DoneMsg signals that the active screen has been completed and the
// session should advance to the next screen. Screens return this via
// [DoneCmd] when the user confirms their selection.
type DoneMsg struct{}

// DoneCmd is a [tea.Cmd] that produces a [DoneMsg]. Screens should
// return this from their Update method when the user makes or confirms
// a selection.
func DoneCmd() tea.Msg {
	return DoneMsg{}
}

// ExtendMsg asks the session to append screens after the current
// cursor position, replacing any screens that were already queued
// beyond it. This allows a screen (or external code via [tea.Cmd])
// to build the next part of the flow dynamically — for example,
// after resolving a config to determine which command-specific
// screens are needed.
//
// If Screens is empty, the message is a no-op.
type ExtendMsg struct {
	Screens []Screen
}
