// Package theme provides a single source of truth for keld's TUI styling.
//
// It uses bubbletint's Rosé Pine palettes (Moon for dark terminals, Dawn
// for light) and exposes semantic colour helpers plus pre-built themes
// for huh forms, the bubbles help bar, and the vendored file picker.
//
// Call [New] once at startup after detecting the terminal background.
// The returned [Styles] struct is then passed to all UI components.
package theme

import (
	"image/color"

	"charm.land/bubbles/v2/help"
	"charm.land/lipgloss/v2"

	"charm.land/huh/v2"

	tint "github.com/lrstanley/bubbletint/v2"

	"git.secluded.site/keld/internal/picker"
)

// Cursor is the string used to indicate the highlighted item in any
// list. Every selectable-list screen should use this.
const Cursor = "▸ "

var (
	paletteDark  = tint.TintRosePineMoon
	paletteLight = tint.TintRosePineDawn
)

// Styles holds all pre-computed styles for keld's TUI. Create one
// with [New] after detecting the terminal background and pass it to
// every UI component. Do not create styles elsewhere.
type Styles struct {
	// Dark reports whether the dark palette is active.
	Dark bool

	// Semantic colours derived from the active Rosé Pine palette.
	// Use these when building ad-hoc styled strings; prefer the
	// pre-built style fields below when possible.
	Accent    color.Color // iris (purple) — cursor, focused borders, titles
	Secondary color.Color // foam (teal) — directory names, filter prompts
	Warning   color.Color // love (red) — error indicators, validation
	Confirm   color.Color // foam (teal) — confirmation, success

	// Chrome styles for the session frame.
	Breadcrumb lipgloss.Style
	Title      lipgloss.Style

	// Pre-built component themes, computed once.
	Help   help.Styles
	Huh    huh.Theme
	Picker picker.Styles
}

// New creates a [Styles] from the given dark/light setting. Call once
// after receiving [tea.BackgroundColorMsg] and thread the result
// through to all UI components.
func New(isDark bool) Styles {
	p := paletteLight
	if isDark {
		p = paletteDark
	}

	accent := p.Purple
	secondary := p.Green
	warn := p.Red
	confirm := p.Green

	// Buttons invert the normal text/background relationship. On
	// dark terminals the palette foreground is light; on light
	// terminals the palette background is light. Both contrast
	// well against the purple accent.
	//
	// TODO: evaluate contrast of Moon Fg (#e0def3) on Moon iris
	// (#c3a7e7). It's the brightest colour the palette offers,
	// but the pairing may still be too low-contrast for some
	// displays. Revisit once the session shell is wired up and
	// we can eyeball it in a real terminal.
	buttonFg := color.Color(p.Fg)
	if !isDark {
		buttonFg = p.Bg
	}

	return Styles{
		Dark:      isDark,
		Accent:    accent,
		Secondary: secondary,
		Warning:   warn,
		Confirm:   confirm,

		Breadcrumb: lipgloss.NewStyle().Foreground(accent),
		Title:      lipgloss.NewStyle().Bold(true),

		Help:   buildHelpStyles(accent),
		Huh:    buildHuhTheme(isDark, accent, secondary, warn, confirm, buttonFg),
		Picker: buildPickerStyles(accent, secondary),
	}
}

// ── Help bar ─────────────────────────────────────────────────

// buildHelpStyles creates [help.Styles] for the bubbles help bar.
// Keys are bold; descriptions and separators use readable colours
// with no muted or dim text.
func buildHelpStyles(accent color.Color) help.Styles {
	sep := lipgloss.NewStyle().Foreground(accent)

	return help.Styles{
		Ellipsis:       lipgloss.NewStyle(),
		ShortKey:       lipgloss.NewStyle().Bold(true),
		ShortDesc:      lipgloss.NewStyle(),
		ShortSeparator: sep,
		FullKey:        lipgloss.NewStyle().Bold(true),
		FullDesc:       lipgloss.NewStyle(),
		FullSeparator:  sep,
	}
}

// ── huh form theme ───────────────────────────────────────────

// buildHuhTheme creates an [huh.Theme] that applies the active
// palette to huh forms. It builds on huh's base theme and overrides
// colours to match keld's visual identity.
//
// The isDark parameter is captured at build time so the ThemeFunc
// callback always uses the same palette as the rest of the session,
// regardless of what huh passes in.
func buildHuhTheme(
	isDark bool,
	accent, secondary, warn, confirm, buttonFg color.Color,
) huh.Theme {
	// Build the huh styles once and close over the result. The
	// ThemeFunc callback may be invoked on every render tick, so
	// returning a pre-computed value avoids repeated allocation.
	t := huh.ThemeBase(isDark)

	// Focused field styles.
	t.Focused.Base = t.Focused.Base.BorderForeground(accent)
	t.Focused.Card = t.Focused.Base
	t.Focused.Title = t.Focused.Title.Foreground(accent).Bold(true)
	t.Focused.NoteTitle = t.Focused.NoteTitle.Foreground(accent).Bold(true).MarginBottom(1)
	t.Focused.Directory = t.Focused.Directory.Foreground(secondary)
	// Description left unstyled — terminal default foreground.
	t.Focused.Description = t.Focused.Description.UnsetForeground()
	t.Focused.ErrorIndicator = t.Focused.ErrorIndicator.Foreground(warn)
	t.Focused.ErrorMessage = t.Focused.ErrorMessage.Foreground(warn)
	t.Focused.SelectSelector = t.Focused.SelectSelector.Foreground(accent).SetString(Cursor)
	t.Focused.NextIndicator = t.Focused.NextIndicator.Foreground(accent)
	t.Focused.PrevIndicator = t.Focused.PrevIndicator.Foreground(accent)
	// Options left unstyled — terminal default foreground.
	t.Focused.Option = t.Focused.Option.UnsetForeground()
	t.Focused.MultiSelectSelector = t.Focused.MultiSelectSelector.Foreground(accent).SetString(Cursor)
	t.Focused.SelectedOption = t.Focused.SelectedOption.Foreground(confirm)
	t.Focused.SelectedPrefix = lipgloss.NewStyle().Foreground(confirm).SetString("✓ ")
	// Unselected items use terminal default — no dimming.
	t.Focused.UnselectedPrefix = lipgloss.NewStyle().SetString("• ")
	t.Focused.UnselectedOption = t.Focused.UnselectedOption.UnsetForeground()
	t.Focused.FocusedButton = t.Focused.FocusedButton.Foreground(buttonFg).Background(accent)
	t.Focused.Next = t.Focused.FocusedButton
	t.Focused.BlurredButton = t.Focused.BlurredButton.UnsetForeground().UnsetBackground()
	t.Focused.TextInput.Cursor = t.Focused.TextInput.Cursor.Foreground(accent)
	// Placeholder left at terminal default — no dimming.
	t.Focused.TextInput.Placeholder = t.Focused.TextInput.Placeholder.UnsetForeground()
	t.Focused.TextInput.Prompt = t.Focused.TextInput.Prompt.Foreground(accent)

	// Blurred styles: same as focused but with a hidden border so
	// alignment is preserved without the visual weight.
	t.Blurred = t.Focused
	t.Blurred.Base = t.Focused.Base.BorderStyle(lipgloss.HiddenBorder())
	t.Blurred.Card = t.Blurred.Base
	t.Blurred.NextIndicator = lipgloss.NewStyle()
	t.Blurred.PrevIndicator = lipgloss.NewStyle()

	t.Group.Title = t.Focused.Title
	t.Group.Description = t.Focused.Description

	// Help bar within huh forms — same style as the session help.
	t.Help = buildHelpStyles(accent)

	return huh.ThemeFunc(func(_ bool) *huh.Styles { return t })
}

// ── File picker styles ───────────────────────────────────────

// buildPickerStyles creates [picker.Styles] derived from the palette.
func buildPickerStyles(accent, secondary color.Color) picker.Styles {
	return picker.Styles{
		Cursor:    lipgloss.NewStyle().Foreground(accent),
		Directory: lipgloss.NewStyle().Foreground(secondary),
		File:      lipgloss.NewStyle(), // terminal default
		// Permissions and file sizes: unstyled, terminal default.
		// No muted text.
		Permission: lipgloss.NewStyle(),
		Selected:   lipgloss.NewStyle().Foreground(accent).Bold(true),
		FileSize:   lipgloss.NewStyle().Width(7).Align(lipgloss.Right),
		EmptyDirectory: lipgloss.NewStyle().
			PaddingLeft(2).
			SetString("No files in this directory."),
	}
}
