package ui

import (
	"image/color"

	"opslag.de/schobers/geom"
)

type Button struct {
	ControlBase

	HoverColor color.Color
	Icon       string
	Text       string
	Type       ButtonType

	clicked ControlClickedEvents
}

type ButtonType int

const (
	ButtonTypeContained ButtonType = iota
	ButtonTypeIcon
	ButtonTypeOutlined
	ButtonTypeText
)

func BuildButton(text string, fn func(b *Button)) *Button { return BuildIconButton("", text, fn) }

func BuildIconButton(icon, text string, fn func(b *Button)) *Button {
	var b = &Button{Text: text, Icon: icon}
	if fn != nil {
		fn(b)
	}
	return b
}

func (b *Button) desiredSize(ctx Context) geom.PointF32 {
	var pad = ctx.Style().Dimensions.TextPadding
	var font = ctx.Fonts().Font(b.FontName(ctx))
	var w, h float32 = 0, font.Height()
	if len(b.Text) != 0 {
		w += pad + font.WidthOf(b.Text)
	}
	icon := b.icon(ctx)
	if icon != nil && icon.Height() > 0 {
		iconW := icon.Width() * h / icon.Height()
		w += pad + iconW
	}
	if w == 0 {
		return geom.ZeroPtF32
	}
	return geom.PtF32(w+pad, pad+h+pad)
}

func (b *Button) icon(ctx Context) Texture {
	if b.Icon == "" {
		return nil
	}
	return ctx.Textures().Texture(b.Icon)
}

func (b *Button) ButtonClicked() ControlClickedEventHandler { return &b.clicked }

func (b *Button) DesiredSize(ctx Context, _ geom.PointF32) geom.PointF32 {
	return b.desiredSize(ctx)
}

func (b *Button) Handle(ctx Context, e Event) bool {
	result := b.ControlBase.HandleNotify(ctx, e, b)
	if b.over {
		if b.Disabled {
			ctx.Renderer().SetMouseCursor(MouseCursorNotAllowed)
			return true
		}
		ctx.Renderer().SetMouseCursor(MouseCursorPointer)
	}
	return result
}

func (b *Button) Notify(ctx Context, state interface{}) bool {
	switch state.(type) {
	case ControlClickedArgs:
		if !b.Disabled {
			if b.clicked.Notify(ctx, state) {
				return true
			}
		}
	}
	return b.ControlBase.Notify(ctx, state)
}

func (b *Button) fillColor(p *Palette) color.Color {
	if b.Disabled {
		if b.Background != nil {
			return p.Disabled
		}
		switch b.Type {
		case ButtonTypeContained:
			return p.Disabled
		default:
			return nil
		}
	}
	if b.Background != nil {
		if b.over && b.HoverColor != nil {
			return b.HoverColor
		}
		return b.Background
	}
	if b.over {
		if b.HoverColor != nil {
			return b.HoverColor
		}
		switch b.Type {
		case ButtonTypeContained:
			return p.PrimaryLight
		case ButtonTypeIcon:
		default:
			return p.PrimaryHighlight
		}
	}
	switch b.Type {
	case ButtonTypeContained:
		return p.Primary
	case ButtonTypeIcon:
	default:
	}
	return nil
}

func (b *Button) textColor(p *Palette) color.Color {
	if b.Disabled {
		if b.Background != nil {
			return p.TextOnDisabled
		}
		switch b.Type {
		case ButtonTypeContained:
			return p.TextOnDisabled
		}
		return p.Disabled
	}
	if b.Font.Color != nil {
		return b.Font.Color
	}
	switch b.Type {
	case ButtonTypeContained:
		return p.TextOnPrimary
	case ButtonTypeIcon:
		if b.over {
			return p.Primary
		}
		return p.Text
	default:
		return p.Primary
	}
}

func (b *Button) Render(ctx Context) {
	var style = ctx.Style()
	var palette = style.Palette
	textColor := b.textColor(palette)
	fillColor := b.fillColor(palette)
	if fillColor != nil {
		ctx.Renderer().FillRectangle(b.bounds, fillColor)
	}
	size := b.desiredSize(ctx)
	bounds := b.bounds
	deltaX, deltaY := bounds.Dx()-size.X, bounds.Dy()-size.Y
	bounds.Min.X += .5 * deltaX
	bounds.Min.Y += .5 * deltaY

	var pad = style.Dimensions.TextPadding
	bounds = bounds.Inset(pad)
	boundsH := bounds.Dy()
	pos := bounds.Min
	icon := b.icon(ctx)
	if icon != nil && icon.Height() > 0 {
		scaled, _ := ctx.Textures().ScaledHeight(icon, boundsH) // try to pre-scale scaled
		if scaled == nil {                                      // let the renderer scale
			scaled = icon
		}
		scale, iconWidth := ScaleToHeight(SizeOfTexture(scaled), boundsH)
		ctx.Renderer().DrawTextureOptions(scaled, geom.PtF32(pos.X, pos.Y), DrawOptions{Tint: textColor, Scale: scale})
		pos.X += iconWidth + pad
	}
	if len(b.Text) != 0 {
		fontName := b.FontName(ctx)
		font := ctx.Fonts().Font(fontName)
		ctx.Renderer().Text(font, geom.PtF32(pos.X, pos.Y+.5*(boundsH-font.Height())), textColor, b.Text)
	}

	if b.Type == ButtonTypeOutlined {
		b.RenderOutlineDefault(ctx, textColor)
	}
}