package ui

import (
	"opslag.de/schobers/geom"
)

type SelectedChangedFn func(ctx Context, c Control, selected bool)

type Checkbox struct {
	ControlBase

	onSelectedChanged SelectedChangedFn

	Selected bool
	Text     string
}

func BuildCheckbox(text string, fn func(c *Checkbox)) *Checkbox {
	var c = &Checkbox{Text: text}
	if fn != nil {
		fn(c)
	}
	return c
}

func (c *Checkbox) desiredSize(ctx Context) geom.PointF32 {
	var pad = ctx.Style().Dimensions.TextPadding
	var font = ctx.Renderer().Font(c.FontName(ctx))
	var w, h float32 = 0, font.Height()
	if len(c.Text) != 0 {
		w += pad + font.WidthOf(c.Text)
	}
	icon, _ := ctx.Images().ScaledHeight(c.getOrCreateNormalIcon(ctx), h)
	w += pad + icon.Width()
	return geom.PtF32(w+pad, pad+h+pad)
}

func (c *Checkbox) icon(ctx Context) Image {
	if c.Selected {
		return GetOrCreateIcon(ctx, "ui-default-checkbox-selected", c.selectedIcon)
	} else if c.over {
		return GetOrCreateIcon(ctx, "ui-default-checkbox-hover", c.hoverIcon)
	}
	return c.getOrCreateNormalIcon(ctx)
}

func (c *Checkbox) getOrCreateNormalIcon(ctx Context) Image {
	return GetOrCreateIcon(ctx, "ui-default-checkbox", c.normalIcon)
}

func (c *Checkbox) iconBorder() geom.PolygonF32 {
	return geom.PolF32(
		geom.PtF32(48, 80),
		geom.PtF32(400, 80),
		geom.PtF32(400, 432),
		geom.PtF32(48, 432),
	)
}

func (c *Checkbox) checkMark() geom.PointsF32 {
	return geom.PointsF32{
		geom.PtF32(96, 256),
		geom.PtF32(180, 340),
		geom.PtF32(340, 150),
	}
}

func (c *Checkbox) hoverIcon() IconPixelTestFn {
	border := c.iconBorder()
	check := c.checkMark()
	return func(pt geom.PointF32) bool {
		return (pt.DistanceToPolygon(border) < 48 && !pt.InPolygon(border)) || pt.DistanceToLines(check) < 24
	}
}

func (c *Checkbox) normalIcon() IconPixelTestFn {
	border := c.iconBorder()
	return func(pt geom.PointF32) bool {
		return pt.DistanceToPolygon(border) < 48 && !pt.InPolygon(border)
	}
}

func (c *Checkbox) selectedIcon() IconPixelTestFn {
	border := c.iconBorder()
	check := c.checkMark()
	return func(pt geom.PointF32) bool {
		if pt.DistanceToPolygon(border) < 48 || pt.InPolygon(border) {
			return pt.DistanceToLines(check) > 24
		}
		return false
	}
}

func (c *Checkbox) DesiredSize(ctx Context) geom.PointF32 { return c.desiredSize(ctx) }

func (c *Checkbox) Handle(ctx Context, e Event) {
	switch e := e.(type) {
	case *MouseButtonDownEvent:
		if e.Button == MouseButtonLeft && c.over {
			c.Selected = !c.Selected
			onSelectedChanged := c.onSelectedChanged
			if onSelectedChanged != nil {
				onSelectedChanged(ctx, c, c.Selected)
			}
		}
	}
	c.ControlBase.Handle(ctx, e)
	if c.over {
		ctx.Renderer().SetMouseCursor(MouseCursorPointer)
	}
}

func (c *Checkbox) OnSelectedChanged(fn SelectedChangedFn) {
	c.onSelectedChanged = fn
}

func (c *Checkbox) Render(ctx Context) {
	c.RenderBackground(ctx)

	var style = ctx.Style()
	var palette = style.Palette
	fore := c.FontColor(ctx)
	bounds := c.bounds

	var pad = style.Dimensions.TextPadding
	bounds = bounds.Inset(pad)
	pos := bounds.Min
	icon, _ := ctx.Images().ScaledHeight(c.icon(ctx), bounds.Dy())
	if icon != nil {
		iconColor := fore
		if c.Selected && c.Font.Color == nil {
			iconColor = palette.Primary
		}
		ctx.Renderer().DrawImageOptions(icon, geom.PtF32(pos.X, pos.Y+.5*(bounds.Dy()-icon.Height())), DrawOptions{Tint: iconColor})
		pos.X += icon.Width() + pad
	}
	if len(c.Text) != 0 {
		var fontName = c.FontName(ctx)
		var font = ctx.Renderer().Font(fontName)
		ctx.Renderer().Text(geom.PtF32(pos.X, pos.Y+.5*(bounds.Dy()-font.Height())), fontName, fore, c.Text)
	}
}