package ui

import (
	"gioui.org/layout"
	"gioui.org/unit"
	"gioui.org/widget/material"
)

// Region defines a screen area in device-independent pixels (Dp).
// All element positions and sizes use Dp for device independence.
type Region struct {
	X, Y Dp
	W, H Dp
}

// Element is the base interface for all UI elements.
// Elements know how to draw themselves when given a Renderer.
type Element interface {
	Region() Region
	Visible() bool
	Draw(gtx layout.Context, r *Renderer)
}

// Container holds child elements and draws them within its bounds.
// Children's regions are screen-space; clipping handles containment.
type Container struct {
	id         string
	region     Region
	visible    bool
	background Color
	children   []Element
}

func (c Container) Region() Region     { return c.region }
func (c Container) Visible() bool      { return c.visible }
func (c Container) Draw(gtx layout.Context, r *Renderer) {
	// Draw background
	if c.background != (Color{}) {
		r.drawBg(gtx, c.region, c.background)
	}
	// Draw children
	for _, child := range c.children {
		child.Draw(gtx, r)
	}
}

// NewContainer creates a Container with the given region, background, and children.
func NewContainer(region Region, bg Color, children []Element) Container {
	return Container{
		region:     region,
		visible:    true,
		background: bg,
		children:   children,
	}
}

// --- Leaf element types (each implements Element and knows how to Draw itself) ---

// Label displays static text.
type Label struct {
	id       string
	region   Region
	visible  bool
	Text     string
	Align    TextAlign
	FontSize unit.Sp // 0 = theme default
	Color    Color   // 0 = theme default
	Bold     bool
}

func (l Label) Region() Region     { return l.region }
func (l Label) Visible() bool      { return l.visible }
func (l Label) Draw(gtx layout.Context, r *Renderer) {
	r.drawText(gtx, l.Text, l.FontSize, l.region, l.Color)
}
func (l Label) ID() string          { return l.id }

// NewLabel creates a visible Label element.
func NewLabel(text string, fontSize unit.Sp, region Region) Label {
	return Label{
		region:   region,
		visible:  true,
		Text:     text,
		FontSize: fontSize,
	}
}

// Icon displays a named icon image.
type Icon struct {
	id       string
	region   Region
	visible  bool
	Name     string // icon name, e.g. "cut"
	Size     Dp     // 0 = default icon size
}

func (i Icon) Region() Region     { return i.region }
func (i Icon) Visible() bool      { return i.visible }
func (i Icon) Draw(gtx layout.Context, r *Renderer) {
	img := r.icon(i.Name)
	if img == nil {
		return
	}
	size := i.Size
	if size == 0 {
		size = Dp(16)
	}
	r.drawPng(gtx, img, i.region, size, i.Size)
}
func (i Icon) ID() string          { return i.id }

// NewIcon creates a visible Icon element.
func NewIcon(name string, region Region, size Dp) Icon {
	return Icon{
		region:  region,
		visible: true,
		Name:    name,
		Size:    size,
	}
}

// TextField accepts text input or displays multiline text.
type TextField struct {
	id           string
	region       Region
	visible      bool
	Value        string
	Placeholder  string
	Focused      bool
	Multiline    bool
	ScrollOffset Dp
	VisibleLines []Line
	WordWrap     bool
	WrapWidth    Dp
}

func (tf TextField) Region() Region { return tf.region }
func (tf TextField) Visible() bool  { return tf.visible }
func (tf TextField) ID() string     { return tf.id }

// Line represents a single line of text in a multiline TextField.
type Line struct {
	Text       string
	LineNumber int // 1-indexed, for display
}

// ListView displays a scrollable list of items.
type ListView struct {
	id           string
	region       Region
	visible      bool
	Items        []ListItem
	ScrollOffset int
	Selected     int
}

func (lv ListView) Region() Region { return lv.region }
func (lv ListView) Visible() bool  { return lv.visible }
func (lv ListView) ID() string     { return lv.id }

// ListItem is a single entry in a ListView.
type ListItem struct {
	Text     string
	Subtext  string
	Selected bool
}

// AlphaIndex displays an alphabetical index for quick navigation.
type AlphaIndex struct {
	id           string
	region       Region
	visible      bool
	Letters      []string
	ActiveLetter string
}

func (ai AlphaIndex) Region() Region { return ai.region }
func (ai AlphaIndex) Visible() bool  { return ai.visible }
func (ai AlphaIndex) ID() string     { return ai.id }

// NewAlphaIndex creates a visible AlphaIndex element.
func NewAlphaIndex(region Region, letters []string) AlphaIndex {
	return AlphaIndex{
		region:  region,
		visible: true,
		Letters: letters,
	}
}

// Button is an interactive button element.
type Button struct {
	id        string
	region    Region
	visible   bool
	Text      string
	Enabled   bool
	Primary   bool
}

func (b Button) Region() Region     { return b.region }
func (b Button) Visible() bool      { return b.visible }
func (b Button) Draw(gtx layout.Context, r *Renderer) {
	th := material.NewTheme()
	th.Shaper = r.shp
	gtx.Constraints.Min.X = int(r.toPx(b.region.X))
	gtx.Constraints.Min.Y = int(r.toPx(b.region.Y))
	material.Label(th, r.theme.FontSize, b.Text).Layout(gtx)
}
func (b Button) ID() string          { return b.id }

// NewButton creates a visible Button element.
func NewButton(text string, enabled bool, primary bool, region Region) Button {
	return Button{
		region:  region,
		visible: true,
		Text:    text,
		Enabled: enabled,
		Primary: primary,
	}
}

// SearchBar displays an in-editor search interface.
type SearchBar struct {
	id      string
	region  Region
	visible bool
	Query   string
	Match   int
	Total   int
	Forward bool
}

func (sb SearchBar) Region() Region { return sb.region }
func (sb SearchBar) Visible() bool  { return sb.visible }
func (sb SearchBar) ID() string     { return sb.id }

// NewSearchBar creates a visible SearchBar element.
func NewSearchBar(region Region, query string, match, total int, forward bool) SearchBar {
	return SearchBar{
		region:  region,
		visible: true,
		Query:   query,
		Match:   match,
		Total:   total,
		Forward: forward,
	}
}

// Cursor displays the text cursor and optional selection highlight.
type Cursor struct {
	id        string
	region    Region
	visible   bool
	Line      int
	Column    int
	Blinking  bool
	Selection *Selection
}

func (c Cursor) Region() Region { return c.region }
func (c Cursor) Visible() bool  { return c.visible }
func (c Cursor) ID() string     { return c.id }

// Selection represents a text selection range.
type Selection struct {
	StartLine, StartCol int
	EndLine, EndCol     int
}

// MergeHunk displays a conflict resolution hunk.
type MergeHunk struct {
	id           string
	region       Region
	visible      bool
	HunkNumber   int
	TotalHunks   int
	LineRange    string
	ContextLines []string
	OurLines     []string
	TheirLines   []string
	Resolution   HunkResolution
}

func (mh MergeHunk) Region() Region { return mh.region }
func (mh MergeHunk) Visible() bool  { return mh.visible }
func (mh MergeHunk) ID() string     { return mh.id }

// HunkResolution represents the resolution state of a merge hunk.
type HunkResolution int

const (
	Unresolved HunkResolution = iota
	KeepOurs
	KeepTheirs
	MergeBoth
)

// Toast displays a temporary notification.
type Toast struct {
	id      string
	region  Region
	visible bool
	Text    string
	Timeout int // milliseconds
}

func (t Toast) Region() Region { return t.region }
func (t Toast) Visible() bool  { return t.visible }
func (t Toast) ID() string     { return t.id }

// NewToast creates a visible Toast element.
func NewToast(region Region, text string, timeout int) Toast {
	return Toast{
		region:  region,
		visible: true,
		Text:    text,
		Timeout: timeout,
	}
}

// Spacer adds vertical or horizontal space.
type Spacer struct {
	id      string
	region  Region
	visible bool
}

func (s Spacer) Region() Region { return s.region }
func (s Spacer) Visible() bool  { return s.visible }
func (s Spacer) ID() string     { return s.id }

// NewSpacer creates a visible Spacer element.
func NewSpacer(height Dp) Spacer {
	return Spacer{
		region:  Region{H: height},
		visible: true,
	}
}

// --- Utility types ---

// Color is an RGBA color.
type Color struct {
	R, G, B, A uint8
}

// Theme holds styling defaults for the UI.
type Theme struct {
	FontSize unit.Sp // Gio's shaper requires unit.Sp for font sizes
}

// TextAlign specifies horizontal text alignment.
type TextAlign int

const (
	AlignStart TextAlign = iota
	AlignCenter
	AlignEnd
)

// InputType specifies the type of user input event.
type InputType int

const (
	Tap InputType = iota
	DoubleTap
	LongPress
	Scroll
	KeyDown
	KeyUp
)

// InputEvent represents a user input event routed to an element.
type InputEvent struct {
	ElementID string
	Type      InputType
	Data      any
}

// ConfigEvent represents a window configuration change (resize, orientation).
// Width and Height are in device-independent pixels (Dp).
type ConfigEvent struct {
	Width  Dp
	Height Dp
}
