package readline

import (
	"fmt"
	"strconv"
)

// initMap - Map display details. Called each time we want to be sure to have
// a working completion group either immediately, or later on. Generally defered.
func (g *CompletionGroup) initMap(rl *Instance) {

	// We make the map anyway, especially if we need to use it later
	if g.Descriptions == nil {
		g.Descriptions = make(map[string]string)
	}

	// Compute size of each completion item box. Group independent
	g.tcMaxLength = 1
	for i := range g.Suggestions {
		if len(g.Descriptions[g.Suggestions[i]]) > g.tcMaxLength {
			g.tcMaxLength = len(g.Descriptions[g.Suggestions[i]])
		}
	}

	g.tcPosX = 0
	g.tcPosY = 0
	g.tcOffset = 0

	// Number of lines allowed to be printed for group
	if len(g.Suggestions) > g.MaxLength {
		g.tcMaxY = g.MaxLength
	} else {
		g.tcMaxY = len(g.Suggestions)
	}
}

// moveTabMapHighlight - Moves the highlighting for currently selected completion item (map display)
func (g *CompletionGroup) moveTabMapHighlight(rl *Instance, x, y int) (done bool, next bool) {

	g.tcPosY += x
	g.tcPosY += y

	// Lines
	if g.tcPosY < 1 {
		if rl.tabCompletionReverse {
			if g.tcOffset > 0 {
				g.tcPosY = 1
				g.tcOffset--
			} else {
				return true, false
			}
		}
	}
	if g.tcPosY > g.tcMaxY {
		g.tcPosY--
		g.tcOffset++
	}

	if g.tcOffset+g.tcPosY < 1 && len(g.Suggestions) > 0 {
		g.tcPosY = g.tcMaxY
		g.tcOffset = len(g.Suggestions) - g.tcMaxY
	}
	if g.tcOffset < 0 {
		g.tcOffset = 0
	}

	if g.tcOffset+g.tcPosY > len(g.Suggestions) {
		g.tcOffset--
		return true, true
	}
	return false, false
}

// writeMap - A map or list completion string
func (g *CompletionGroup) writeMap(rl *Instance) (comp string) {

	if g.Name != "" {
		// Print group title (changes with line returns depending on type)
		comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, fmtEscape(g.Name), RESET)
		rl.tcUsedY++
	}

	termWidth := GetTermWidth()
	if termWidth < 20 {
		// terminal too small. Probably better we do nothing instead of crash
		// We are more conservative than lmorg, and push it to 20 instead of 10
		return
	}

	// Set all necessary dimensions
	maxLength := g.tcMaxLength
	if maxLength > termWidth-9 {
		maxLength = termWidth - 9
	}
	maxDescWidth := termWidth - maxLength - 4

	cellWidth := strconv.Itoa(maxLength)
	itemWidth := strconv.Itoa(maxDescWidth)
	y := 0

	// Highlighting function
	highlight := func(y int) string {
		if y == g.tcPosY && g.isCurrent {
			return seqInvert
		}
		return ""
	}

	// String formating
	var item, description string
	for i := g.tcOffset; i < len(g.Suggestions); i++ {
		y++ // Consider new item
		if y > g.tcMaxY {
			break
		}

		item = g.Suggestions[i]

		if len(item) > maxDescWidth {
			item = item[:maxDescWidth-3] + "..."
		}

		description = g.Descriptions[g.Suggestions[i]]
		if len(description) > maxLength {
			description = description[:maxLength-3] + "..."
		}

		comp += fmt.Sprintf("\r%-"+cellWidth+"s %s %-"+itemWidth+"s %s\n",
			description, highlight(y), fmtEscape(item), seqReset)
	}

	// Add the equivalent of this group's size to final screen clearing
	if len(g.Suggestions) > g.MaxLength {
		rl.tcUsedY += g.MaxLength
	} else {
		rl.tcUsedY += len(g.Suggestions)
	}

	return
}