package twin

import (
	"fmt"
	"unicode"

	"github.com/rivo/uniseg"
)

// StyledRune is a rune with a style to be written to a one or more cells on the
// screen. Note that a StyledRune may use more than one cell on the screen ('午'
// for example).
type StyledRune struct {
	Rune  rune
	Style Style
}

func NewStyledRune(char rune, style Style) StyledRune {
	return StyledRune{
		Rune:  char,
		Style: style,
	}
}

func (styledRune StyledRune) String() string {
	return fmt.Sprint("rune='", string(styledRune.Rune), "' ", styledRune.Style)
}

// How many screen cells will this rune cover? Most runes cover one, but some
// like '午' will cover two.
func (styledRune StyledRune) Width() int {
	return uniseg.StringWidth(string(styledRune.Rune))
}

func (styledRune StyledRune) Equal(other StyledRune) bool {
	return styledRune.Rune == other.Rune && styledRune.Style.Equal(other.Style)
}

// Returns a slice of cells with trailing whitespace cells removed
func TrimSpaceRight(runes []StyledRune) []StyledRune {
	for i := len(runes) - 1; i >= 0; i-- {
		cell := runes[i]
		if !unicode.IsSpace(cell.Rune) {
			return runes[0 : i+1]
		}

		// That was a space, keep looking
	}

	// All whitespace, return empty
	return []StyledRune{}
}

// Returns a slice of cells with leading whitespace cells removed
func TrimSpaceLeft(runes []StyledRune) []StyledRune {
	for i := range runes {
		cell := runes[i]
		if !unicode.IsSpace(cell.Rune) {
			return runes[i:]
		}

		// That was a space, keep looking
	}

	// All whitespace, return empty
	return []StyledRune{}
}

func Printable(char rune) bool {
	if unicode.IsPrint(char) {
		return true
	}

	if unicode.Is(unicode.Co, char) {
		// Co == "Private Use": https://www.compart.com/en/unicode/category
		//
		// This space is used by Font Awesome, for "fa-battery-empty" for
		// example: https://fontawesome.com/v4/icon/battery-empty
		//
		// So we want to print these and let the rendering engine deal with
		// outputting them in a way that's helpful to the user.
		return true
	}

	if char == 0xa0 {
		// 0xa0 is a non-breaking space, which is printable, despite what
		// unicode.IsPrint() says.
		return true
	}

	return false
}
