package ui

import (
	"git.sr.ht/~rockorager/vaxis"
)

func StyledString(s string) *vaxis.StyledString {
	if state.vx == nil {
		return nil
	}
	return state.vx.NewStyledString(s, vaxis.Style{})
}

// Applies a style to a string. Any currently applied styles will not be overwritten
func ApplyStyle(style vaxis.Style, str string) string {
	ss := StyledString(str)
	if ss == nil {
		return str
	}
	d := vaxis.Style{}
	for i, sr := range ss.Cells {
		if sr.Style == d {
			sr.Style = style
			ss.Cells[i] = sr
		}
	}
	return ss.Encode()
}

// PadLeft inserts blank spaces at the beginning of the StyledString to produce
// a string of the provided width
func PadLeft(ss *vaxis.StyledString, width int) {
	w := ss.Len()
	if w >= width {
		return
	}
	cell := vaxis.Cell{
		Character: vaxis.Character{
			Grapheme: " ",
			Width:    1,
		},
	}
	w = width - w
	cells := make([]vaxis.Cell, 0, len(ss.Cells)+w)
	for w > 0 {
		cells = append(cells, cell)
		w -= 1
	}
	cells = append(cells, ss.Cells...)
	ss.Cells = cells
}

// PadLeft inserts blank spaces at the end of the StyledString to produce
// a string of the provided width
func PadRight(ss *vaxis.StyledString, width int) {
	w := ss.Len()
	if w >= width {
		return
	}
	cell := vaxis.Cell{
		Character: vaxis.Character{
			Grapheme: " ",
			Width:    1,
		},
	}
	w = width - w
	for w > 0 {
		w -= 1
		ss.Cells = append(ss.Cells, cell)
	}
}

// ApplyAttrs applies the style, and if another style is present ORs the
// attributes
func ApplyAttrs(ss *vaxis.StyledString, style vaxis.Style) {
	for i, cell := range ss.Cells {
		if style.Foreground != 0 {
			cell.Style.Foreground = style.Foreground
		}
		if style.Background != 0 {
			cell.Style.Background = style.Background
		}
		cell.Style.Attribute |= style.Attribute
		if style.UnderlineColor != 0 {
			cell.Style.UnderlineColor = style.UnderlineColor
		}
		if style.UnderlineStyle != vaxis.UnderlineOff {
			cell.Style.UnderlineStyle = style.UnderlineStyle
		}
		ss.Cells[i] = cell
	}
}

// Truncates the styled string on the right and inserts a '…' as the last
// character
func Truncate(ss *vaxis.StyledString, width int) {
	if ss.Len() <= width {
		return
	}
	cells := make([]vaxis.Cell, 0, len(ss.Cells))
	total := 0
	for _, cell := range ss.Cells {
		if total+cell.Width >= width {
			// we can't fit this cell so put in our truncator
			cells = append(cells, vaxis.Cell{
				Character: vaxis.Character{
					Grapheme: "…",
					Width:    1,
				},
				Style: cell.Style,
			})
			break
		}
		total += cell.Width
		cells = append(cells, cell)
	}
	ss.Cells = cells
}

// TruncateHead truncates the left side of the string and inserts '…' as the
// first character
func TruncateHead(ss *vaxis.StyledString, width int) {
	l := ss.Len()
	if l <= width {
		return
	}
	offset := l - width
	cells := make([]vaxis.Cell, 0, len(ss.Cells))
	cells = append(cells, vaxis.Cell{
		Character: vaxis.Character{
			Grapheme: "…",
			Width:    1,
		},
	})
	total := 0
	for _, cell := range ss.Cells {
		total += cell.Width
		if total < offset {
			// we always have at least one for our truncator. We
			// copy this cells style to it so that it retains the
			// style information from the first printed cell
			cells[0].Style = cell.Style
			continue
		}
		cells = append(cells, cell)
	}
	ss.Cells = cells
}
