package testbed

import (
	"embed"
	"log"
	"path"

	ui "github.com/codingpoeta/termui"
	"github.com/codingpoeta/termui/widgets"
	tb "github.com/nsf/termbox-go"
)

//go:embed templates
var local embed.FS

type TestbedUi struct {
	P0 *widgets.Paragraph
	P1 *widgets.Paragraph
	T  *widgets.Tree
}
type nodeValue string

func (nv nodeValue) String() string {
	return string(nv)
}

func (t *TestbedUi) resize() {
	x, y := ui.TerminalDimensions()
	var lx int
	if x/4 > 20 {
		lx = x / 4
	} else {
		lx = 20
	}
	t.T.SetRect(0, 0, lx, y-4)
	t.P0.SetRect(-1, y-5, lx+1, y+1)
	t.P1.SetRect(lx, 0, x, y)
}

func (t *TestbedUi) render() {
	ui.Render(t.P0, t.T, t.P1)
}

func (t *TestbedUi) getPath() string {
	nodes := t.T.SelectedNodeWithIndex()
	path := "templates"
	for {
		path = path + "/" + nodes.Value.String()
		if nodes.Nodes != nil {
			nodes = nodes.Nodes[0]
		} else {
			break
		}
	}
	return path
}

func isDir(path string) bool {
	b, err := local.Open(path)
	info, _ := b.Stat()
	if err != nil {
		return false
	}
	return info.IsDir()
}

func (t *TestbedUi) parseDir(nodes *[]*widgets.TreeNode, path0 string) {
	if !isDir(path0) {
		return
	}
	fis, _ := local.ReadDir(path0)
	for _, fi := range fis {
		thisnode := widgets.TreeNode{Value: nodeValue(path.Base(fi.Name()))}
		*nodes = append(*nodes, &thisnode)
		t.parseDir(&thisnode.Nodes, path0+"/"+path.Base(fi.Name()))
	}
}

func NewTestbedUi() (t *TestbedUi) {
	if err := ui.Init(); err != nil {
		log.Fatalf("failed to initialize termui: %v", err)
	}
	nodes := []*widgets.TreeNode{}
	t = &TestbedUi{}
	t.parseDir(&nodes, "templates")

	t.T = widgets.NewTree()
	t.T.TextStyle = ui.NewStyle(ui.ColorYellow)
	t.T.WrapText = false
	t.T.SetNodes(nodes)

	t.P0 = widgets.NewParagraph()
	t.P0.Text = "▲▼ to scroll up/down\n'S' to submit template\n'E' to edit template\n<PgUp> to scroll up text"
	t.P0.Border = false

	t.P1 = widgets.NewParagraph()
	t.P1.Title = "Help"
	t.P1.Text = "[//To do: ](fg:blue,mod:bold)fill the [help](fg:red) [here](bg:blue)"
	t.P1.BorderStyle.Fg = ui.ColorBlue

	t.resize()
	t.render()
	return
}

func (t *TestbedUi) Run() (rawYAML []byte) {
	defer ui.Close()

	previousKey := ""
	uiEvents := ui.PollEvents()
	for {
		e := <-uiEvents
		switch e.ID {
		case "q", "<C-c>":
			return
		case "j", "<Down>":
			t.T.ScrollDown()
		case "k", "<Up>":
			t.T.ScrollUp()
		case "<C-d>":
			t.T.ScrollHalfPageDown()
		case "<C-u>":
			t.T.ScrollHalfPageUp()
		case "<C-f>":
			t.T.ScrollPageDown()
		case "<C-b>":
			t.T.ScrollPageUp()
		case "<PageUp>":
			t.P1.ScrollHalfPageUp()
		case "<PageDown>":
			t.P1.ScrollHalfPageDown()
		case "g":
			if previousKey == "g" {
				t.T.ScrollTop()
			}
		case "<Home>":
			t.T.ScrollTop()
		case "<Enter>":
			if len(t.T.SelectedNode().Nodes) == 0 {
				tmp, _ := local.ReadFile(t.getPath())
				t.P1.Title = t.getPath()
				t.P1.Text = string(tmp)
			} else {
				t.T.ToggleExpand()
			}
		case "G", "<End>":
			t.T.ScrollBottom()
		case "C":
			t.T.ExpandAll()
		case "c":
			t.T.CollapseAll()
		case "e", "E":
			rawYAML = []byte(t.P1.Edit())
			tb.Close()
			tb.Init()
			return
		case "s", "S":
			rawYAML = []byte(t.P1.Get())
			return
		case "<Resize>":
			t.resize()
		}

		if previousKey == "g" {
			previousKey = ""
		} else {
			previousKey = e.ID
		}

		t.render()
	}
	return
}
