package screens

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

	"charm.land/huh/v2"

	"git.secluded.site/keld/internal/theme"
	"git.secluded.site/keld/internal/ui"
)

// globalDefaultLabel is the breadcrumb display text when the user
// selects "(global defaults only)". This avoids the ambiguity of
// Selection() returning "" for both "not yet selected" and "selected
// global defaults".
const globalDefaultLabel = "(global defaults)"

// Preset is a Screen adapter that wraps a huh Select form for
// choosing a configuration preset. It intercepts Esc for back
// navigation when the filter is not active, and delegates all other
// input to the embedded form.
type Preset struct {
	presets   []string
	styles    *theme.Styles
	form      *huh.Form
	selectFld *huh.Select[string]
	selected  string
	selection string
}

// NewPreset creates a preset selector screen. The styles pointer
// should come from Session.Styles() so theme updates propagate
// automatically.
//
// The huh form is not built until Init is called, so the form
// picks up whatever theme the session has settled on by then
// (after background colour detection).
func NewPreset(presets []string, styles *theme.Styles) *Preset {
	return &Preset{
		presets: presets,
		styles:  styles,
	}
}

// buildForm constructs the huh form and select field. Called from
// the constructor and from Init when the form needs resetting
// (e.g. after back navigation).
func (p *Preset) buildForm() {
	opts := make([]huh.Option[string], 0, len(p.presets)+1)
	opts = append(opts, huh.NewOption("(global defaults only)", ""))
	for _, name := range p.presets {
		opts = append(opts, huh.NewOption(name, name))
	}

	// Preserve any previous selection so back-navigation shows
	// the user's earlier choice. Reset the breadcrumb label since
	// the screen is being re-activated (no longer "completed").
	p.selection = ""

	sel := huh.NewSelect[string]().
		Options(opts...).
		Value(&p.selected)

	p.selectFld = sel

	p.form = huh.NewForm(
		huh.NewGroup(sel),
	).WithTheme(p.styles.Huh).WithShowHelp(false)
}

// Init initialises the embedded form. On first call or after
// completion, the form is (re)built so it picks up the current
// theme and can accept input again.
func (p *Preset) Init() tea.Cmd {
	if p.form == nil || p.form.State != huh.StateNormal {
		p.buildForm()
	}
	return p.form.Init()
}

// Update handles messages. Esc is intercepted for back navigation
// when the select field is not in filter mode. All other messages
// are forwarded to the huh form.
func (p *Preset) Update(msg tea.Msg) (ui.Screen, tea.Cmd) {
	if p.form == nil {
		return p, nil
	}

	switch msg.(type) {
	case tea.BackgroundColorMsg:
		// The session has already updated *styles. Rebuild the
		// form so it picks up the new huh theme.
		p.buildForm()
		return p, p.form.Init()
	}

	// Intercept Esc for back navigation, but only when the select
	// field is not filtering. When filtering, Esc should close the
	// filter (handled by huh internally).
	if kp, ok := msg.(tea.KeyPressMsg); ok {
		if kp.Code == tea.KeyEscape && !p.selectFld.GetFiltering() {
			return p, ui.BackCmd
		}
	}

	// Forward to huh.
	model, cmd := p.form.Update(msg)
	if f, ok := model.(*huh.Form); ok {
		p.form = f
	}

	if p.form.State == huh.StateCompleted {
		if p.selected == "" {
			p.selection = globalDefaultLabel
		} else {
			p.selection = p.selected
		}
		return p, ui.DoneCmd
	}

	return p, cmd
}

// View renders the form.
func (p *Preset) View() string {
	if p.form == nil {
		return ""
	}
	return p.form.View()
}

// Title returns the screen's display title.
func (p *Preset) Title() string { return "Select a preset" }

// KeyBindings returns bindings for the help bar. The huh form
// handles its own key bindings internally; we expose the most
// relevant ones for display.
func (p *Preset) KeyBindings() []key.Binding {
	return []key.Binding{
		key.NewBinding(key.WithKeys("↑/↓"), key.WithHelp("↑/↓", "navigate")),
		key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "select")),
	}
}

// Selection returns the chosen preset name for breadcrumb display,
// or "" if nothing has been selected yet. For global defaults this
// returns a display label like "(global defaults)", not the empty
// string — use [Value] for the actual config preset name.
func (p *Preset) Selection() string { return p.selection }

// Value returns the resolved preset name for use in config resolution.
// Returns "" when the user selected global defaults.
func (p *Preset) Value() string { return p.selected }
