package tui

import (
	"charm.land/bubbles/v2/help"
	"charm.land/bubbles/v2/key"
	"charm.land/bubbles/v2/list"
	"charm.land/bubbles/v2/viewport"
)

// NewListKeyMap returns a set of keybindings for the list view.
func NewListKeyMap() list.KeyMap {
	return list.KeyMap{
		// Browsing.
		CursorUp: key.NewBinding(
			key.WithKeys("k", "up", "ctrl+p"),
			key.WithHelp("k/↑", "move up"),
		),
		CursorDown: key.NewBinding(
			key.WithKeys("j", "down", "ctrl+n"),
			key.WithHelp("j/↓", "move down"),
		),
		PrevPage: key.NewBinding(
			key.WithKeys("h", "left", "pgup", "alt+v"),
			key.WithHelp("h/←", "prev page"),
		),
		NextPage: key.NewBinding(
			key.WithKeys("l", "right", "pgdown", "ctrl+v"),
			key.WithHelp("l/→", "next page"),
		),
		GoToStart: key.NewBinding(
			key.WithKeys("home", "ctrl+a"),
			key.WithHelp("home", "go to start"),
		),
		GoToEnd: key.NewBinding(
			key.WithKeys("end", "ctrl+e"),
			key.WithHelp("end", "go to end"),
		),
		Filter: key.NewBinding(
			key.WithKeys("/"),
			key.WithHelp("/", "search"),
		),
		ClearFilter: key.NewBinding(
			key.WithKeys("esc"),
			key.WithHelp("esc", "clear filter"),
		),

		// Filtering.
		CancelWhileFiltering: key.NewBinding(
			key.WithKeys("esc"),
			key.WithHelp("esc", "cancel"),
		),
		AcceptWhileFiltering: key.NewBinding(
			key.WithKeys("enter", "tab", "shift+tab", "ctrl+k", "up", "down"),
			key.WithHelp("enter", "apply filter"),
		),

		// Toggle help.
		ShowFullHelp: key.NewBinding(
			key.WithKeys("?"),
			key.WithHelp("?", "more"),
		),
		CloseFullHelp: key.NewBinding(
			key.WithKeys("?"),
			key.WithHelp("?", "close help"),
		),

		// Quitting.
		Quit: key.NewBinding(
			key.WithKeys("q", "esc"),
			key.WithHelp("q", "quit"),
		),
		ForceQuit: key.NewBinding(key.WithKeys("ctrl+c")),
	}
}

// DelegateKeyMap defines the list-row keybindings. `s` opens the
// interactive scaffold form; the placeholder-only flow is reachable from
// inside that form via ctrl+d when required values are still unfilled,
// or directly from the pager via ctrl+d.
type DelegateKeyMap struct {
	Choose              key.Binding
	ScaffoldInteractive key.Binding
}

// ShortHelp returns additional short help entries. This satisfies the help.KeyMap interface and
// is entirely optional.
func (d DelegateKeyMap) ShortHelp() []key.Binding {
	return []key.Binding{
		d.Choose,
		d.ScaffoldInteractive,
	}
}

// FullHelp returns additional full help entries. This satisfies the help.KeyMap interface and
// is entirely optional.
func (d DelegateKeyMap) FullHelp() [][]key.Binding {
	return [][]key.Binding{
		{
			d.Choose,
			d.ScaffoldInteractive,
		},
	}
}

// NewDelegateKeyMap returns a set of keybindings.
func NewDelegateKeyMap() *DelegateKeyMap {
	return &DelegateKeyMap{
		Choose: key.NewBinding(
			key.WithKeys("enter"),
			key.WithHelp("enter", "choose"),
		),
		ScaffoldInteractive: key.NewBinding(
			key.WithKeys("s"),
			key.WithHelp("s", "scaffold"),
		),
	}
}

// PagerKeyMap returns a set of keybindings for the pager. It satisfies to the
// help.KeyMap interface, which is used to render the menu.
type PagerKeyMap struct {
	viewport.KeyMap

	HelpModel help.Model

	// Button navigation (tab forward, shift+tab back). The buttonbar
	// consumes the keypresses; this binding exists for the help line.
	Navigation key.Binding

	// Select button
	Choose key.Binding

	// Run the interactive scaffold flow (s).
	ScaffoldInteractive key.Binding

	// Scaffold immediately with placeholder values, skipping the form (ctrl+d).
	ScaffoldImmediate key.Binding

	// Toggle soft-wrapping of long README lines (w).
	ToggleWrap key.Binding

	// Help toggle keybindings.
	Help key.Binding

	// The quit keybinding. This won't be caught when filtering.
	Quit key.Binding

	// The quit-no-matter-what keybinding. This will be caught when filtering.
	ForceQuit key.Binding
}

// ShortHelp returns keybindings to be shown in the mini help view. It's part
// of the key.Map interface. Paging and wrap keys are omitted so the line
// fits a 120-column terminal; they stay discoverable via `?`.
func (keys PagerKeyMap) ShortHelp() []key.Binding {
	return []key.Binding{
		keys.Up,
		keys.Down,
		keys.Navigation,
		keys.Choose,
		keys.ScaffoldInteractive,
		keys.ScaffoldImmediate,
		keys.Help,
		keys.Quit,
	}
}

// FullHelp returns keybindings for the expanded help view. It's part of the
// key.Map interface.
func (keys PagerKeyMap) FullHelp() [][]key.Binding {
	return [][]key.Binding{
		{keys.Up, keys.Down, keys.PageDown, keys.PageUp},                                 // first column
		{keys.Navigation, keys.Choose, keys.ScaffoldInteractive, keys.ScaffoldImmediate}, // second column
		{keys.ToggleWrap, keys.Help, keys.Quit, keys.ForceQuit},                          // third column
	}
}

// NewPagerKeyMap returns a set of keybindings for the pager view.
func NewPagerKeyMap() PagerKeyMap {
	return PagerKeyMap{
		KeyMap: viewport.KeyMap{
			HalfPageUp: key.NewBinding(
				key.WithDisabled(),
			),
			HalfPageDown: key.NewBinding(
				key.WithDisabled(),
			),
			Up: key.NewBinding(
				key.WithKeys("k", "up", "ctrl+p"),
				key.WithHelp("k/↑", "move up"),
			),
			Down: key.NewBinding(
				key.WithKeys("j", "down", "ctrl+n"),
				key.WithHelp("j/↓", "move down"),
			),
			PageDown: key.NewBinding(
				key.WithKeys("l", "right", "pgdown", "ctrl+v"),
				key.WithHelp("l/→", "page down"),
			),
			PageUp: key.NewBinding(
				key.WithKeys("h", "left", "pgup", "alt+v"),
				key.WithHelp("h/←", "page up"),
			),
		},
		HelpModel: help.New(),
		Navigation: key.NewBinding(
			key.WithKeys("tab", "shift+tab"),
			key.WithHelp("tab/shift+tab", "nav"),
		),
		Choose: key.NewBinding(
			key.WithKeys("enter"),
			key.WithHelp("enter", "choose"),
		),
		ScaffoldInteractive: key.NewBinding(
			key.WithKeys("s"),
			key.WithHelp("s", "scaffold"),
		),
		ScaffoldImmediate: key.NewBinding(
			key.WithKeys("ctrl+d"),
			key.WithHelp("ctrl+d", "scaffold now"),
		),
		ToggleWrap: key.NewBinding(
			key.WithKeys("w"),
			key.WithHelp("w", "wrap"),
		),
		Help: key.NewBinding(
			key.WithKeys("?"),
			key.WithHelp("?", "help"),
		),
		Quit: key.NewBinding(
			key.WithKeys("q", "esc"),
			key.WithHelp("q", "back"),
		),
		ForceQuit: key.NewBinding(key.WithKeys("ctrl+c")),
	}
}
