package ui

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

type Scrollbar struct {
	ControlBase

	Orientation Orientation

	Content float32
	Offset  float32

	handle          ScrollbarHandle
	startDragOffset float32
}

func BuildScrollbar(o Orientation, fn func(s *Scrollbar)) *Scrollbar {
	var s = &Scrollbar{Orientation: o, Content: 0, Offset: 0}
	s.handle.OnDragStart(func(_ Context, _ Control, _ geom.PointF32) {
		s.startDragOffset = s.Offset
	})
	s.handle.OnDragMove(func(_ Context, _ Control, start, move geom.PointF32) {
		var length = s.Orientation.SizeParallel(s.bounds)
		var handleMaxOffset = length - s.Orientation.SizeParallel(s.handle.bounds)
		var hidden = s.Content - length
		var offset = (s.Orientation.LengthParallel(move) - s.Orientation.LengthParallel(start)) / handleMaxOffset
		s.Offset = geom.Max32(0, geom.Min32(s.startDragOffset+offset*hidden, hidden))
	})
	fn(s)
	return s
}

func (s *Scrollbar) Arrange(ctx Context, bounds geom.RectangleF32, offset geom.PointF32) {
	s.ControlBase.Arrange(ctx, bounds, offset)
	s.updateBar(ctx)
}

func (s *Scrollbar) DesiredSize(ctx Context) geom.PointF32 {
	return s.Orientation.Pt(geom.NaN32(), ctx.Style().Dimensions.ScrollbarWidth)
}

func (s *Scrollbar) Handle(ctx Context, e Event) {
	s.handle.Handle(ctx, e)
	switch e := e.(type) {
	case *MouseMoveEvent:
		if e.MouseWheel != 0 && e.Pos().Sub(s.offset).In(s.bounds) {
			s.Offset = geom.Max32(0, geom.Min32(s.Content-s.Orientation.SizeParallel(s.bounds), s.Offset-36*e.MouseWheel))
		}
	}
	s.ControlBase.Handle(ctx, e)
}

func (s *Scrollbar) Render(ctx Context) {
	s.handle.Render(ctx)
}

func (s *Scrollbar) updateBar(ctx Context) {
	var length = s.Orientation.SizeParallel(s.bounds)
	var width = ctx.Style().Dimensions.ScrollbarWidth
	var handleLength = length
	var handleOffset = s.Orientation.LengthParallel(s.bounds.Min)
	if s.Content > length {
		handleLength = geom.Max32(2*width, length*length/s.Content)
		var hidden = s.Content - length
		if s.Offset > hidden {
			s.Offset = hidden
		}
		var offset = geom.Min32(1, s.Offset/hidden)
		handleOffset = handleOffset + offset*(length-handleLength)
	}
	var min = s.Orientation.Pt(handleOffset, s.Orientation.LengthPerpendicular(s.bounds.Max)-width)
	s.handle.Arrange(ctx, s.Orientation.Rect(min, handleLength, width), s.offset)
}

type ScrollbarHandle struct {
	ControlBase
}

func (h *ScrollbarHandle) Render(ctx Context) {
	h.RenderBackground(ctx)
	p := ctx.Style().Palette
	fill := p.Primary
	if h.over {
		fill = p.PrimaryHighlight
	}
	ctx.Renderer().FillRectangle(h.bounds.Inset(1), fill)
}