package ui

import (
	"image/color"

	"charm.land/lipgloss/v2"
)

// Styles contains all styles used in the UI. They are resolved from light and
// dark color variants according to the terminal's background color, which
// Bubble Tea reports via tea.BackgroundColorMsg. Until then, we default to
// a dark background.
type Styles struct {
	lightDark lipgloss.LightDarkFunc

	fuchsia color.Color

	dimNormalFg      func(...string) string
	brightGrayFg     func(...string) string
	dimBrightGrayFg  func(...string) string
	grayFg           func(...string) string
	midGrayFg        func(...string) string
	darkGrayFg       lipgloss.Style
	greenFg          func(...string) string
	semiDimGreenFg   func(...string) string
	dimGreenFg       func(...string) string
	fuchsiaFg        func(...string) string
	dimFuchsiaFg     func(...string) string
	dullFuchsiaFg    func(...string) string
	dimDullFuchsiaFg func(...string) string
	redFg            func(...string) string

	tabStyle         lipgloss.Style
	selectedTabStyle lipgloss.Style
	errorTitleStyle  lipgloss.Style
	subtleStyle      lipgloss.Style
	paginationStyle  lipgloss.Style

	statusBarScrollPosStyle        func(...string) string
	statusBarNoteStyle             func(...string) string
	statusBarHelpStyle             func(...string) string
	statusBarMessageStyle          func(...string) string
	statusBarMessageScrollPosStyle func(...string) string
	statusBarMessageHelpStyle      func(...string) string
	helpViewStyle                  func(...string) string
	lineNumberStyle                func(...string) string

	dividerDot            lipgloss.Style
	dividerBar            lipgloss.Style
	logoStyle             lipgloss.Style
	stashSpinnerStyle     lipgloss.Style
	stashInputPromptStyle lipgloss.Style
}

// newStyles builds all styles for the given terminal background.
func newStyles(isDark bool) Styles {
	s := Styles{lightDark: lipgloss.LightDark(isDark)}

	// Colors
	normalDim := s.adaptive("#A49FA5", "#777777")
	gray := s.adaptive("#909090", "#626262")
	midGray := s.adaptive("#B2B2B2", "#4A4A4A")
	darkGray := s.adaptive("#DDDADA", "#3C3C3C")
	brightGray := s.adaptive("#847A85", "#979797")
	dimBrightGray := s.adaptive("#C2B8C2", "#4D4D4D")
	cream := s.adaptive("#FFFDF5", "#FFFDF5")
	yellowGreen := s.adaptive("#04B575", "#ECFD65")
	s.fuchsia = s.adaptive("#EE6FF8", "#EE6FF8")
	dimFuchsia := s.adaptive("#F1A8FF", "#99519E")
	dullFuchsia := s.adaptive("#F793FF", "#AD58B4")
	dimDullFuchsia := s.adaptive("#F6C9FF", "#7B4380")
	green := lipgloss.Color("#04B575")
	red := s.adaptive("#FF4672", "#ED567A")
	semiDimGreen := s.adaptive("#35D79C", "#036B46")
	dimGreen := s.adaptive("#72D2B0", "#0B5137")

	// Pager colors
	mintGreen := s.adaptive("#89F0CB", "#89F0CB")
	darkGreen := s.adaptive("#1C8760", "#1C8760")
	lineNumberFg := s.adaptive("#656565", "#7D7D7D")
	statusBarNoteFg := s.adaptive("#656565", "#7D7D7D")
	statusBarBg := s.adaptive("#E6E6E6", "#242424")

	// Render-func styles
	s.dimNormalFg = lipgloss.NewStyle().Foreground(normalDim).Render
	s.brightGrayFg = lipgloss.NewStyle().Foreground(brightGray).Render
	s.dimBrightGrayFg = lipgloss.NewStyle().Foreground(dimBrightGray).Render
	s.grayFg = lipgloss.NewStyle().Foreground(gray).Render
	s.midGrayFg = lipgloss.NewStyle().Foreground(midGray).Render
	s.darkGrayFg = lipgloss.NewStyle().Foreground(darkGray)
	s.greenFg = lipgloss.NewStyle().Foreground(green).Render
	s.semiDimGreenFg = lipgloss.NewStyle().Foreground(semiDimGreen).Render
	s.dimGreenFg = lipgloss.NewStyle().Foreground(dimGreen).Render
	s.fuchsiaFg = lipgloss.NewStyle().Foreground(s.fuchsia).Render
	s.dimFuchsiaFg = lipgloss.NewStyle().Foreground(dimFuchsia).Render
	s.dullFuchsiaFg = lipgloss.NewStyle().Foreground(dullFuchsia).Render
	s.dimDullFuchsiaFg = lipgloss.NewStyle().Foreground(dimDullFuchsia).Render
	s.redFg = lipgloss.NewStyle().Foreground(red).Render

	// Named styles
	s.tabStyle = lipgloss.NewStyle().Foreground(s.adaptive("#909090", "#626262"))
	s.selectedTabStyle = lipgloss.NewStyle().Foreground(s.adaptive("#333333", "#979797"))
	s.errorTitleStyle = lipgloss.NewStyle().Foreground(cream).Background(red).Padding(0, 1)
	s.subtleStyle = lipgloss.NewStyle().Foreground(s.adaptive("#9B9B9B", "#5C5C5C"))
	s.paginationStyle = s.subtleStyle

	// Pager styles
	s.statusBarScrollPosStyle = lipgloss.NewStyle().
		Foreground(s.adaptive("#949494", "#5A5A5A")).
		Background(statusBarBg).
		Render

	s.statusBarNoteStyle = lipgloss.NewStyle().
		Foreground(statusBarNoteFg).
		Background(statusBarBg).
		Render

	s.statusBarHelpStyle = lipgloss.NewStyle().
		Foreground(statusBarNoteFg).
		Background(s.adaptive("#DCDCDC", "#323232")).
		Render

	s.statusBarMessageStyle = lipgloss.NewStyle().
		Foreground(mintGreen).
		Background(darkGreen).
		Render

	s.statusBarMessageScrollPosStyle = lipgloss.NewStyle().
		Foreground(mintGreen).
		Background(darkGreen).
		Render

	s.statusBarMessageHelpStyle = lipgloss.NewStyle().
		Foreground(lipgloss.Color("#B6FFE4")).
		Background(green).
		Render

	s.helpViewStyle = lipgloss.NewStyle().
		Foreground(statusBarNoteFg).
		Background(s.adaptive("#f2f2f2", "#1B1B1B")).
		Render

	s.lineNumberStyle = lipgloss.NewStyle().
		Foreground(lineNumberFg).
		Render

	// Stash styles
	s.dividerDot = s.darkGrayFg.SetString(" • ")
	s.dividerBar = s.darkGrayFg.SetString(" │ ")

	s.logoStyle = lipgloss.NewStyle().
		Foreground(lipgloss.Color("#ECFD65")).
		Background(s.fuchsia).
		Bold(true)

	s.stashSpinnerStyle = lipgloss.NewStyle().
		Foreground(gray)
	s.stashInputPromptStyle = lipgloss.NewStyle().
		Foreground(yellowGreen).
		MarginRight(1)

	return s
}

// adaptive returns a color appropriate for the current terminal background.
func (s Styles) adaptive(light, dark string) color.Color {
	return s.lightDark(lipgloss.Color(light), lipgloss.Color(dark))
}
