// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of K9s

package config

import (
	"fmt"
	"os"

	"github.com/derailed/k9s/internal/config/data"
	"github.com/derailed/k9s/internal/config/json"
	"github.com/derailed/tcell/v2"
	"github.com/derailed/tview"
	"gopkg.in/yaml.v3"
)

// StyleListener represents a skin's listener.
type StyleListener interface {
	// StylesChanged notifies listener the skin changed.
	StylesChanged(*Styles)
}

// TextStyle tracks text styles.
type TextStyle string

const (
	// TextStyleNormal is the default text style.
	TextStyleNormal TextStyle = "normal"

	// TextStyleBold is the bold text style.
	TextStyleBold TextStyle = "bold"

	// TextStyleDim is the dim text style.
	TextStyleDim TextStyle = "dim"
)

// ToShortString returns a short string representation of the text style.
func (ts TextStyle) ToShortString() string {
	switch ts {
	case TextStyleNormal:
		return "-"
	case TextStyleBold:
		return "b"
	case TextStyleDim:
		return "d"
	default:
		return "d"
	}
}

type (
	// Styles tracks K9s styling options.
	Styles struct {
		K9s       Style `json:"k9s" yaml:"k9s"`
		listeners []StyleListener
	}

	// Style tracks K9s styles.
	Style struct {
		Body   Body   `json:"body" yaml:"body"`
		Prompt Prompt `json:"prompt" yaml:"prompt"`
		Help   Help   `json:"help" yaml:"help"`
		Frame  Frame  `json:"frame" yaml:"frame"`
		Info   Info   `json:"info" yaml:"info"`
		Views  Views  `json:"views" yaml:"views"`
		Dialog Dialog `json:"dialog" yaml:"dialog"`
	}

	// Prompt tracks command styles
	Prompt struct {
		FgColor      Color        `json:"fgColor" yaml:"fgColor"`
		BgColor      Color        `json:"bgColor" yaml:"bgColor"`
		SuggestColor Color        `json:"" yaml:"suggestColor"`
		Border       PromptBorder `json:"" yaml:"border"`
	}

	// PromptBorder tracks the color of the prompt depending on its kind (e.g., command or filter)
	PromptBorder struct {
		CommandColor Color `json:"command" yaml:"command"`
		DefaultColor Color `json:"default" yaml:"default"`
	}

	// Help tracks help styles.
	Help struct {
		FgColor      Color `json:"fgColor" yaml:"fgColor"`
		BgColor      Color `json:"bgColor" yaml:"bgColor"`
		SectionColor Color `json:"sectionColor" yaml:"sectionColor"`
		KeyColor     Color `json:"keyColor" yaml:"keyColor"`
		NumKeyColor  Color `json:"numKeyColor" yaml:"numKeyColor"`
	}

	// Body tracks body styles.
	Body struct {
		FgColor        Color `json:"fgColor" yaml:"fgColor"`
		BgColor        Color `json:"bgColor" yaml:"bgColor"`
		LogoColor      Color `json:"logoColor" yaml:"logoColor"`
		LogoColorMsg   Color `json:"logoColorMsg" yaml:"logoColorMsg"`
		LogoColorInfo  Color `json:"logoColorInfo" yaml:"logoColorInfo"`
		LogoColorWarn  Color `json:"logoColorWarn" yaml:"logoColorWarn"`
		LogoColorError Color `json:"logoColorError" yaml:"logoColorError"`
	}

	// Dialog tracks dialog styles.
	Dialog struct {
		FgColor            Color `json:"fgColor" yaml:"fgColor"`
		BgColor            Color `json:"bgColor" yaml:"bgColor"`
		ButtonFgColor      Color `json:"buttonFgColor" yaml:"buttonFgColor"`
		ButtonBgColor      Color `json:"buttonBgColor" yaml:"buttonBgColor"`
		ButtonFocusFgColor Color `json:"buttonFocusFgColor" yaml:"buttonFocusFgColor"`
		ButtonFocusBgColor Color `json:"buttonFocusBgColor" yaml:"buttonFocusBgColor"`
		LabelFgColor       Color `json:"labelFgColor" yaml:"labelFgColor"`
		FieldFgColor       Color `json:"fieldFgColor" yaml:"fieldFgColor"`
	}

	// Frame tracks frame styles.
	Frame struct {
		Title  Title  `json:"title" yaml:"title"`
		Border Border `json:"border" yaml:"border"`
		Menu   Menu   `json:"menu" yaml:"menu"`
		Crumb  Crumb  `json:"crumbs" yaml:"crumbs"`
		Status Status `json:"status" yaml:"status"`
	}

	// Views tracks individual view styles.
	Views struct {
		Table  Table  `json:"table" yaml:"table"`
		Xray   Xray   `json:"xray" yaml:"xray"`
		Charts Charts `json:"charts" yaml:"charts"`
		Yaml   Yaml   `json:"yaml" yaml:"yaml"`
		Picker Picker `json:"picker" yaml:"picker"`
		Log    Log    `json:"logs" yaml:"logs"`
	}

	// Status tracks resource status styles.
	Status struct {
		NewColor       Color `json:"newColor" yaml:"newColor"`
		ModifyColor    Color `json:"modifyColor" yaml:"modifyColor"`
		AddColor       Color `json:"addColor" yaml:"addColor"`
		PendingColor   Color `json:"pendingColor" yaml:"pendingColor"`
		ErrorColor     Color `json:"errorColor" yaml:"errorColor"`
		HighlightColor Color `json:"highlightColor" yaml:"highlightColor"`
		KillColor      Color `json:"killColor" yaml:"killColor"`
		CompletedColor Color `json:"completedColor" yaml:"completedColor"`
	}

	// Log tracks Log styles.
	Log struct {
		FgColor   Color        `json:"fgColor" yaml:"fgColor"`
		BgColor   Color        `json:"bgColor" yaml:"bgColor"`
		Indicator LogIndicator `json:"indicator" yaml:"indicator"`
	}

	// Picker tracks color when selecting containers
	Picker struct {
		MainColor     Color `json:"mainColor" yaml:"mainColor"`
		FocusColor    Color `json:"focusColor" yaml:"focusColor"`
		ShortcutColor Color `json:"shortcutColor" yaml:"shortcutColor"`
	}

	// LogIndicator tracks log view indicator.
	LogIndicator struct {
		FgColor        Color `json:"fgColor" yaml:"fgColor"`
		BgColor        Color `json:"bgColor" yaml:"bgColor"`
		ToggleOnColor  Color `json:"toggleOnColor" yaml:"toggleOnColor"`
		ToggleOffColor Color `json:"toggleOffColor" yaml:"toggleOffColor"`
	}

	// Yaml tracks yaml styles.
	Yaml struct {
		KeyColor   Color `json:"keyColor" yaml:"keyColor"`
		ValueColor Color `json:"valueColor" yaml:"valueColor"`
		ColonColor Color `json:"colonColor" yaml:"colonColor"`
	}

	// Title tracks title styles.
	Title struct {
		FgColor        Color `json:"fgColor" yaml:"fgColor"`
		BgColor        Color `json:"bgColor" yaml:"bgColor"`
		HighlightColor Color `json:"highlightColor" yaml:"highlightColor"`
		CounterColor   Color `json:"counterColor" yaml:"counterColor"`
		FilterColor    Color `json:"filterColor" yaml:"filterColor"`
	}

	// Info tracks info styles.
	Info struct {
		SectionColor Color `json:"sectionColor" yaml:"sectionColor"`
		FgColor      Color `json:"fgColor" yaml:"fgColor"`
		CPUColor     Color `json:"cpuColor" yaml:"cpuColor"`
		MEMColor     Color `json:"memColor" yaml:"memColor"`
		K9sRevColor  Color `json:"k9sRevColor" yaml:"k9sRevColor"`
	}

	// Border tracks border styles.
	Border struct {
		FgColor    Color `json:"fgColor" yaml:"fgColor"`
		FocusColor Color `json:"focusColor" yaml:"focusColor"`
	}

	// Crumb tracks crumbs styles.
	Crumb struct {
		FgColor     Color `json:"fgColor" yaml:"fgColor"`
		BgColor     Color `json:"bgColor" yaml:"bgColor"`
		ActiveColor Color `json:"activeColor" yaml:"activeColor"`
	}

	// Table tracks table styles.
	Table struct {
		FgColor       Color       `json:"fgColor" yaml:"fgColor"`
		BgColor       Color       `json:"bgColor" yaml:"bgColor"`
		CursorFgColor Color       `json:"cursorFgColor" yaml:"cursorFgColor"`
		CursorBgColor Color       `json:"cursorBgColor" yaml:"cursorBgColor"`
		MarkColor     Color       `json:"markColor" yaml:"markColor"`
		Header        TableHeader `json:"header" yaml:"header"`
	}

	// TableHeader tracks table header styles.
	TableHeader struct {
		FgColor                 Color `json:"fgColor" yaml:"fgColor"`
		BgColor                 Color `json:"bgColor" yaml:"bgColor"`
		SorterColor             Color `json:"sorterColor" yaml:"sorterColor"`
		SelectedSortColumnColor Color `json:"selectedSortColumnColor" yaml:"selectedSortColumnColor"`
	}

	// Xray tracks xray styles.
	Xray struct {
		FgColor         Color `json:"fgColor" yaml:"fgColor"`
		BgColor         Color `json:"bgColor" yaml:"bgColor"`
		CursorColor     Color `json:"cursorColor" yaml:"cursorColor"`
		CursorTextColor Color `json:"cursorTextColor" yaml:"cursorTextColor"`
		GraphicColor    Color `json:"graphicColor" yaml:"graphicColor"`
	}

	// Menu tracks menu styles.
	Menu struct {
		FgColor     Color     `json:"fgColor" yaml:"fgColor"`
		FgStyle     TextStyle `json:"fgStyle" yaml:"fgStyle"`
		KeyColor    Color     `json:"keyColor" yaml:"keyColor"`
		NumKeyColor Color     `json:"numKeyColor" yaml:"numKeyColor"`
	}

	// Charts tracks charts styles.
	Charts struct {
		BgColor            Color             `json:"bgColor" yaml:"bgColor"`
		DialBgColor        Color             `json:"dialBgColor" yaml:"dialBgColor"`
		ChartBgColor       Color             `json:"chartBgColor" yaml:"chartBgColor"`
		DefaultDialColors  Colors            `json:"defaultDialColors" yaml:"defaultDialColors"`
		DefaultChartColors Colors            `json:"defaultChartColors" yaml:"defaultChartColors"`
		ResourceColors     map[string]Colors `json:"resourceColors" yaml:"resourceColors"`
		FocusFgColor       Color             `yaml:"focusFgColor"`
		FocusBgColor       Color             `yaml:"focusBgColor"`
	}
)

func newStyle() Style {
	return Style{
		Body:   newBody(),
		Prompt: newPrompt(),
		Help:   newHelp(),
		Frame:  newFrame(),
		Info:   newInfo(),
		Views:  newViews(),
		Dialog: newDialog(),
	}
}

func newDialog() Dialog {
	return Dialog{
		FgColor:            "cadetblue",
		BgColor:            "black",
		ButtonBgColor:      "darkslateblue",
		ButtonFgColor:      "black",
		ButtonFocusBgColor: "dodgerblue",
		ButtonFocusFgColor: "black",
		LabelFgColor:       "white",
		FieldFgColor:       "white",
	}
}

func newPrompt() Prompt {
	return Prompt{
		FgColor:      "cadetblue",
		BgColor:      "black",
		SuggestColor: "dodgerblue",
		Border: PromptBorder{
			DefaultColor: "seagreen",
			CommandColor: "aqua",
		},
	}
}

func newCharts() Charts {
	return Charts{
		BgColor:            "black",
		DialBgColor:        "black",
		ChartBgColor:       "black",
		DefaultDialColors:  Colors{Color("palegreen"), Color("orangered")},
		DefaultChartColors: Colors{Color("palegreen"), Color("orangered")},
		ResourceColors: map[string]Colors{
			CPU: {Color("dodgerblue"), Color("darkslateblue")},
			MEM: {Color("yellow"), Color("goldenrod")},
		},
		FocusFgColor: "white",
		FocusBgColor: "orange",
	}
}

func newViews() Views {
	return Views{
		Table:  newTable(),
		Xray:   newXray(),
		Charts: newCharts(),
		Yaml:   newYaml(),
		Picker: newPicker(),
		Log:    newLog(),
	}
}

func newFrame() Frame {
	return Frame{
		Title:  newTitle(),
		Border: newBorder(),
		Menu:   newMenu(),
		Crumb:  newCrumb(),
		Status: newStatus(),
	}
}

func newHelp() Help {
	return Help{
		FgColor:      "cadetblue",
		BgColor:      "black",
		SectionColor: "green",
		KeyColor:     "dodgerblue",
		NumKeyColor:  "fuchsia",
	}
}

func newBody() Body {
	return Body{
		FgColor:        "cadetblue",
		BgColor:        "black",
		LogoColor:      "orange",
		LogoColorMsg:   "white",
		LogoColorInfo:  "green",
		LogoColorWarn:  "mediumvioletred",
		LogoColorError: "red",
	}
}

func newStatus() Status {
	return Status{
		NewColor:       "lightskyblue",
		ModifyColor:    "greenyellow",
		AddColor:       "dodgerblue",
		PendingColor:   "darkorange",
		ErrorColor:     "orangered",
		HighlightColor: "aqua",
		KillColor:      "mediumpurple",
		CompletedColor: "lightslategray",
	}
}

func newPicker() Picker {
	return Picker{
		MainColor:     "white",
		FocusColor:    "aqua",
		ShortcutColor: "aqua",
	}
}

func newLog() Log {
	return Log{
		FgColor:   "lightskyblue",
		BgColor:   "black",
		Indicator: newLogIndicator(),
	}
}

func newLogIndicator() LogIndicator {
	return LogIndicator{
		FgColor:        "dodgerblue",
		BgColor:        "black",
		ToggleOnColor:  "limegreen",
		ToggleOffColor: "gray",
	}
}

func newYaml() Yaml {
	return Yaml{
		KeyColor:   "steelblue",
		ColonColor: "white",
		ValueColor: "papayawhip",
	}
}

func newTitle() Title {
	return Title{
		FgColor:        "aqua",
		BgColor:        "black",
		HighlightColor: "fuchsia",
		CounterColor:   "papayawhip",
		FilterColor:    "seagreen",
	}
}

func newInfo() Info {
	return Info{
		SectionColor: "white",
		FgColor:      "orange",
		CPUColor:     "lawngreen",
		MEMColor:     "darkturquoise",
		K9sRevColor:  "aqua",
	}
}

func newXray() Xray {
	return Xray{
		FgColor:         "aqua",
		BgColor:         "black",
		CursorColor:     "dodgerblue",
		CursorTextColor: "black",
		GraphicColor:    "cadetblue",
	}
}

func newTable() Table {
	return Table{
		FgColor:       "aqua",
		BgColor:       "black",
		CursorFgColor: "black",
		CursorBgColor: "aqua",
		MarkColor:     "palegreen",
		Header:        newTableHeader(),
	}
}

func newTableHeader() TableHeader {
	return TableHeader{
		FgColor:                 "white",
		BgColor:                 "black",
		SorterColor:             "aqua",
		SelectedSortColumnColor: "lightskyblue",
	}
}

func newCrumb() Crumb {
	return Crumb{
		FgColor:     "black",
		BgColor:     "aqua",
		ActiveColor: "orange",
	}
}

func newBorder() Border {
	return Border{
		FgColor:    "dodgerblue",
		FocusColor: "lightskyblue",
	}
}

func newMenu() Menu {
	return Menu{
		FgColor:     "white",
		KeyColor:    "dodgerblue",
		NumKeyColor: "fuchsia",
	}
}

// NewStyles creates a new default config.
func NewStyles() *Styles {
	var s Styles
	if err := yaml.Unmarshal(stockSkinTpl, &s); err == nil {
		return &s
	}

	return &Styles{
		K9s: newStyle(),
	}
}

// Reset resets styles.
func (s *Styles) Reset(invert bool) {
	if err := yaml.Unmarshal(stockSkinTpl, s); err != nil {
		s.K9s = newStyle()
	}
	if invert {
		s.K9s.Invert()
	}
}

// FgColor returns the foreground color.
func (s *Styles) FgColor() tcell.Color {
	return s.Body().FgColor.Color()
}

// BgColor returns the background color.
func (s *Styles) BgColor() tcell.Color {
	return s.Body().BgColor.Color()
}

// AddListener registers a new listener.
func (s *Styles) AddListener(l StyleListener) {
	s.listeners = append(s.listeners, l)
}

// RemoveListener removes a listener.
func (s *Styles) RemoveListener(l StyleListener) {
	victim := -1
	for i, lis := range s.listeners {
		if lis == l {
			victim = i
			break
		}
	}
	if victim == -1 {
		return
	}
	s.listeners = append(s.listeners[:victim], s.listeners[victim+1:]...)
}

func (s *Styles) fireStylesChanged() {
	for _, list := range s.listeners {
		list.StylesChanged(s)
	}
}

// Body returns body styles.
func (s *Styles) Body() Body {
	return s.K9s.Body
}

// Prompt returns prompt styles.
func (s *Styles) Prompt() Prompt {
	return s.K9s.Prompt
}

// Frame returns frame styles.
func (s *Styles) Frame() Frame {
	return s.K9s.Frame
}

// Crumb returns crumb styles.
func (s *Styles) Crumb() Crumb {
	return s.Frame().Crumb
}

// Title returns title styles.
func (s *Styles) Title() Title {
	return s.Frame().Title
}

// Charts returns charts styles.
func (s *Styles) Charts() Charts {
	return s.K9s.Views.Charts
}

// Dialog returns dialog styles.
func (s *Styles) Dialog() Dialog {
	return s.K9s.Dialog
}

// Table returns table styles.
func (s *Styles) Table() Table {
	return s.K9s.Views.Table
}

// Xray returns xray styles.
func (s *Styles) Xray() Xray {
	return s.K9s.Views.Xray
}

// Views returns views styles.
func (s *Styles) Views() Views {
	return s.K9s.Views
}

// Invert inverts all colors in the Style.
func (s *Style) Invert() {
	s.Body.Invert()
	s.Prompt.Invert()
	s.Help.Invert()
	s.Frame.Invert()
	s.Info.Invert()
	s.Views.Invert()
	s.Dialog.Invert()
}

// Invert inverts all colors in Body.
func (b *Body) Invert() {
	b.FgColor = b.FgColor.InvertColor()
	b.BgColor = b.BgColor.InvertColor()
	b.LogoColor = b.LogoColor.InvertColor()
	b.LogoColorMsg = b.LogoColorMsg.InvertColor()
	b.LogoColorInfo = b.LogoColorInfo.InvertColor()
	b.LogoColorWarn = b.LogoColorWarn.InvertColor()
	b.LogoColorError = b.LogoColorError.InvertColor()
}

// Invert inverts all colors in Prompt.
func (p *Prompt) Invert() {
	p.FgColor = p.FgColor.InvertColor()
	p.BgColor = p.BgColor.InvertColor()
	p.SuggestColor = p.SuggestColor.InvertColor()
	p.Border.Invert()
}

// Invert inverts all colors in PromptBorder.
func (p *PromptBorder) Invert() {
	p.CommandColor = p.CommandColor.InvertColor()
	p.DefaultColor = p.DefaultColor.InvertColor()
}

// Invert inverts all colors in Help.
func (h *Help) Invert() {
	h.FgColor = h.FgColor.InvertColor()
	h.BgColor = h.BgColor.InvertColor()
	h.SectionColor = h.SectionColor.InvertColor()
	h.KeyColor = h.KeyColor.InvertColor()
	h.NumKeyColor = h.NumKeyColor.InvertColor()
}

// Invert inverts all colors in Dialog.
func (d *Dialog) Invert() {
	d.FgColor = d.FgColor.InvertColor()
	d.BgColor = d.BgColor.InvertColor()
	d.ButtonFgColor = d.ButtonFgColor.InvertColor()
	d.ButtonBgColor = d.ButtonBgColor.InvertColor()
	d.ButtonFocusFgColor = d.ButtonFocusFgColor.InvertColor()
	d.ButtonFocusBgColor = d.ButtonFocusBgColor.InvertColor()
	d.LabelFgColor = d.LabelFgColor.InvertColor()
	d.FieldFgColor = d.FieldFgColor.InvertColor()
}

// Invert inverts all colors in Frame.
func (f *Frame) Invert() {
	f.Title.Invert()
	f.Border.Invert()
	f.Menu.Invert()
	f.Crumb.Invert()
	f.Status.Invert()
}

// Invert inverts all colors in Title.
func (t *Title) Invert() {
	t.FgColor = t.FgColor.InvertColor()
	t.BgColor = t.BgColor.InvertColor()
	t.HighlightColor = t.HighlightColor.InvertColor()
	t.CounterColor = t.CounterColor.InvertColor()
	t.FilterColor = t.FilterColor.InvertColor()
}

// Invert inverts all colors in Border.
func (b *Border) Invert() {
	b.FgColor = b.FgColor.InvertColor()
	b.FocusColor = b.FocusColor.InvertColor()
}

// Invert inverts all colors in Menu.
func (m *Menu) Invert() {
	m.FgColor = m.FgColor.InvertColor()
	m.KeyColor = m.KeyColor.InvertColor()
	m.NumKeyColor = m.NumKeyColor.InvertColor()
}

// Invert inverts all colors in Crumb.
func (c *Crumb) Invert() {
	c.FgColor = c.FgColor.InvertColor()
	c.BgColor = c.BgColor.InvertColor()
	c.ActiveColor = c.ActiveColor.InvertColor()
}

// Invert inverts all colors in Status.
func (s *Status) Invert() {
	s.NewColor = s.NewColor.InvertColor()
	s.ModifyColor = s.ModifyColor.InvertColor()
	s.AddColor = s.AddColor.InvertColor()
	s.PendingColor = s.PendingColor.InvertColor()
	s.ErrorColor = s.ErrorColor.InvertColor()
	s.HighlightColor = s.HighlightColor.InvertColor()
	s.KillColor = s.KillColor.InvertColor()
	s.CompletedColor = s.CompletedColor.InvertColor()
}

// Invert inverts all colors in Info.
func (i *Info) Invert() {
	i.SectionColor = i.SectionColor.InvertColor()
	i.FgColor = i.FgColor.InvertColor()
	i.CPUColor = i.CPUColor.InvertColor()
	i.MEMColor = i.MEMColor.InvertColor()
	i.K9sRevColor = i.K9sRevColor.InvertColor()
}

// Invert inverts all colors in Views.
func (v *Views) Invert() {
	v.Table.Invert()
	v.Xray.Invert()
	v.Charts.Invert()
	v.Yaml.Invert()
	v.Picker.Invert()
	v.Log.Invert()
}

// Invert inverts all colors in Table.
func (t *Table) Invert() {
	t.FgColor = t.FgColor.InvertColor()
	t.BgColor = t.BgColor.InvertColor()
	t.CursorFgColor = t.CursorFgColor.InvertColor()
	t.CursorBgColor = t.CursorBgColor.InvertColor()
	t.MarkColor = t.MarkColor.InvertColor()
	t.Header.Invert()
}

// Invert inverts all colors in TableHeader.
func (t *TableHeader) Invert() {
	t.FgColor = t.FgColor.InvertColor()
	t.BgColor = t.BgColor.InvertColor()
	t.SorterColor = t.SorterColor.InvertColor()
	t.SelectedSortColumnColor = t.SelectedSortColumnColor.InvertColor()
}

// Invert inverts all colors in Xray.
func (x *Xray) Invert() {
	x.FgColor = x.FgColor.InvertColor()
	x.BgColor = x.BgColor.InvertColor()
	x.CursorColor = x.CursorColor.InvertColor()
	x.CursorTextColor = x.CursorTextColor.InvertColor()
	x.GraphicColor = x.GraphicColor.InvertColor()
}

// Invert inverts all colors in Charts.
func (c *Charts) Invert() {
	c.BgColor = c.BgColor.InvertColor()
	c.DialBgColor = c.DialBgColor.InvertColor()
	c.ChartBgColor = c.ChartBgColor.InvertColor()
	c.FocusFgColor = c.FocusFgColor.InvertColor()
	c.FocusBgColor = c.FocusBgColor.InvertColor()
	c.DefaultDialColors = c.DefaultDialColors.Invert()
	c.DefaultChartColors = c.DefaultChartColors.Invert()
	for k, v := range c.ResourceColors {
		c.ResourceColors[k] = v.Invert()
	}
}

// Invert inverts all colors in Yaml.
func (y *Yaml) Invert() {
	y.KeyColor = y.KeyColor.InvertColor()
	y.ValueColor = y.ValueColor.InvertColor()
	y.ColonColor = y.ColonColor.InvertColor()
}

// Invert inverts all colors in Picker.
func (p *Picker) Invert() {
	p.MainColor = p.MainColor.InvertColor()
	p.FocusColor = p.FocusColor.InvertColor()
	p.ShortcutColor = p.ShortcutColor.InvertColor()
}

// Invert inverts all colors in Log.
func (l *Log) Invert() {
	l.FgColor = l.FgColor.InvertColor()
	l.BgColor = l.BgColor.InvertColor()
	l.Indicator.Invert()
}

// Invert inverts all colors in LogIndicator.
func (l *LogIndicator) Invert() {
	l.FgColor = l.FgColor.InvertColor()
	l.BgColor = l.BgColor.InvertColor()
	l.ToggleOnColor = l.ToggleOnColor.InvertColor()
	l.ToggleOffColor = l.ToggleOffColor.InvertColor()
}

// Load K9s configuration from file.
func (s *Styles) Load(path string, invert bool) error {
	bb, err := os.ReadFile(path)
	if err != nil {
		return err
	}
	if err := data.JSONValidator.Validate(json.SkinSchema, bb); err != nil {
		return err
	}
	if err := yaml.Unmarshal(bb, s); err != nil {
		return err
	}

	if invert {
		s.K9s.Invert()
	}

	return nil
}

// Update apply terminal colors based on styles.
func (s *Styles) Update() {
	tview.Styles.PrimitiveBackgroundColor = s.BgColor()
	tview.Styles.ContrastBackgroundColor = s.BgColor()
	tview.Styles.MoreContrastBackgroundColor = s.BgColor()
	tview.Styles.PrimaryTextColor = s.FgColor()
	tview.Styles.BorderColor = s.K9s.Frame.Border.FgColor.Color()
	tview.Styles.FocusColor = s.K9s.Frame.Border.FocusColor.Color()
	tview.Styles.TitleColor = s.FgColor()
	tview.Styles.GraphicsColor = s.FgColor()
	tview.Styles.SecondaryTextColor = s.FgColor()
	tview.Styles.TertiaryTextColor = s.FgColor()
	tview.Styles.InverseTextColor = s.FgColor()
	tview.Styles.ContrastSecondaryTextColor = s.FgColor()

	s.fireStylesChanged()
}

// Dump for debug.
func (s *Styles) Dump() {
	bb, _ := yaml.Marshal(s)
	fmt.Println(string(bb))
}
