package ui

import (
	"context"

	"github.com/derailed/k9s/internal/model"
	"github.com/derailed/tview"
	"github.com/gdamore/tcell"
)

// KeyListenerFunc listens to key presses.
type KeyListenerFunc func()

// Tree represents a tree view.
type Tree struct {
	*tview.TreeView

	actions      KeyActions
	selectedItem string
	cmdBuff      *model.CmdBuff
	expandNodes  bool
	Count        int
	keyListener  KeyListenerFunc
}

// NewTree returns a new view.
func NewTree() *Tree {
	return &Tree{
		TreeView:    tview.NewTreeView(),
		expandNodes: true,
		actions:     make(KeyActions),
		cmdBuff:     model.NewCmdBuff('/', model.Filter),
	}
}

// Init initializes the view
func (t *Tree) Init(ctx context.Context) error {
	t.BindKeys()
	t.SetBorder(true)
	t.SetBorderAttributes(tcell.AttrBold)
	t.SetBorderPadding(0, 0, 1, 1)
	t.SetGraphics(true)
	t.SetGraphicsColor(tcell.ColorFloralWhite)
	t.SetInputCapture(t.keyboard)

	return nil
}

// SetSelectedItem sets the currently selected node.
func (t *Tree) SetSelectedItem(s string) {
	t.selectedItem = s
}

// GetSelectedItem returns the currently selected item or blank if none.
func (t *Tree) GetSelectedItem() string {
	return t.selectedItem
}

// ExpandNodes returns true if nodes are expanded or false otherwise.
func (t *Tree) ExpandNodes() bool {
	return t.expandNodes
}

// CmdBuff returns the filter command.
func (t *Tree) CmdBuff() *model.CmdBuff {
	return t.cmdBuff
}

// SetKeyListenerFn sets a key entered listener.
func (t *Tree) SetKeyListenerFn(f KeyListenerFunc) {
	t.keyListener = f
}

// Actions returns active menu bindings.
func (t *Tree) Actions() KeyActions {
	return t.actions
}

// Hints returns the view hints.
func (t *Tree) Hints() model.MenuHints {
	return t.actions.Hints()
}

// ExtraHints returns additional hints.
func (t *Tree) ExtraHints() map[string]string {
	return nil
}

// BindKeys binds default mnemonics.
func (t *Tree) BindKeys() {
	t.Actions().Add(KeyActions{
		KeySpace: NewKeyAction("Expand/Collapse", t.noopCmd, true),
		KeyX:     NewKeyAction("Expand/Collapse All", t.toggleCollapseCmd, true),
	})
}

func (t *Tree) keyboard(evt *tcell.EventKey) *tcell.EventKey {
	key := evt.Key()
	if key == tcell.KeyRune {
		if t.cmdBuff.IsActive() {
			t.cmdBuff.Add(evt.Rune())
			t.ClearSelection()
			if t.keyListener != nil {
				t.keyListener()
			}
			return nil
		}
		key = mapKey(evt)
	}

	if a, ok := t.actions[key]; ok {
		return a.Action(evt)
	}

	return evt
}

func (t *Tree) noopCmd(evt *tcell.EventKey) *tcell.EventKey {
	return evt
}

func (t *Tree) toggleCollapseCmd(evt *tcell.EventKey) *tcell.EventKey {
	t.expandNodes = !t.expandNodes
	t.GetRoot().Walk(func(node, parent *tview.TreeNode) bool {
		if parent != nil {
			node.SetExpanded(t.expandNodes)
		}
		return true
	})
	return nil
}

// ClearSelection clears the currently selected node.
func (t *Tree) ClearSelection() {
	t.selectedItem = ""
	t.SetCurrentNode(nil)
}

// ----------------------------------------------------------------------------
// Helpers...

func mapKey(evt *tcell.EventKey) tcell.Key {
	key := tcell.Key(evt.Rune())
	if evt.Modifiers() == tcell.ModAlt {
		key = tcell.Key(int16(evt.Rune()) * int16(evt.Modifiers()))
	}
	return key
}
