package gui

import (
	"fmt"
	"image"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/inpututil"
)

type Point struct {
	X, Y int
}

func P(x, y int) Point {
	return Point{x, y}
}

func (p Point) Add(o Point) Point {
	return Point{p.X + o.X, p.Y + o.Y}
}

func (p Point) Sub(o Point) Point {
	return Point{p.X - o.X, p.Y - o.Y}
}

func (p Point) Mul(o Point) Point {
	return Point{p.X * o.X, p.Y * o.Y}
}

func (p Point) Div(o Point) Point {
	return Point{p.X / o.X, p.Y / o.Y}
}

func (p Point) Pt() image.Point {
	return image.Pt(p.X, p.Y)
}

func Pf(x, y float64) Point {
	return Point{int(x), int(y)}
}

func (p Point) In(d Dimension) bool {
	return p.X >= d.X && p.X < d.X+d.Width && p.Y >= d.Y && p.Y < d.Y+d.Height
}

func (p Point) String() string {
	return fmt.Sprintf("P(%d, %d)", p.X, p.Y)
}

type Size struct {
	Width, Height int
}

func S(w, h int) Size {
	return Size{w, h}
}

func (s Size) Pt() image.Point {
	return image.Pt(s.Width, s.Height)
}

func (s Size) String() string {
	return fmt.Sprintf("S(%d, %d)", s.Width, s.Height)
}

type Dimension struct {
	Point
	Size
}

func D(x, y, w, h int) Dimension {
	return Dimension{P(x, y), S(w, h)}
}

func (d Dimension) Rect() image.Rectangle {
	return image.Rectangle{Min: d.Point.Pt(), Max: d.Point.Pt().Add(d.Size.Pt())}
}

func (d Dimension) String() string {
	return fmt.Sprintf("D(%d, %d, %d, %d)", d.X, d.Y, d.Width, d.Height)
}

type Orientation uint8

const (
	Horizontal Orientation = iota
	Vertical
)

type Side uint8

const (
	SideTop Side = iota
	SideBottom
	SideLeft
	SideRight
)

// Horizontal returns true if s is either SideLeft or SideRight
func (s Side) Horizontal() bool {
	return s == SideLeft || s == SideRight
}

// Vertical returns true if s is either SideTop or SideBottom
func (s Side) Vertical() bool {
	return s == SideTop || s == SideBottom
}

type Anchor uint8

const (
	AnchorTopLeft Anchor = iota
	AnchorTop
	AnchorTopRight
	AnchorLeft
	AnchorCenter
	AnchorRight
	AnchorBottomLeft
	AnchorBottom
	AnchorBottomRight
)

type MouseButton uint8

const (
	MouseButtonLeft   = MouseButton(ebiten.MouseButtonLeft)
	MouseButtonRight  = MouseButton(ebiten.MouseButtonRight)
	MouseButtonMiddle = MouseButton(ebiten.MouseButtonMiddle)
)

type ButtonMask uint16

func Buttons() ButtonMask {
	var mask ButtonMask

	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
		mask |= 1 << MouseButtonLeft
	}

	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonRight) {
		mask |= 1 << MouseButtonRight
	}

	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonMiddle) {
		mask |= 1 << MouseButtonMiddle
	}

	if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
		mask |= 1 << (MouseButtonLeft + 3)
	}

	if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonRight) {
		mask |= 1 << (MouseButtonRight + 3)
	}

	if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonMiddle) {
		mask |= 1 << (MouseButtonMiddle + 3)
	}

	if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft) {
		mask |= 1 << (MouseButtonLeft + 6)
	}

	if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonRight) {
		mask |= 1 << (MouseButtonRight + 6)
	}

	if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonMiddle) {
		mask |= 1 << (MouseButtonMiddle + 6)
	}

	return mask
}

func (m ButtonMask) Pressed(button MouseButton) bool {
	return m&(1<<button) > 0
}

func (m ButtonMask) JustPressed(button MouseButton) bool {
	return m&(1<<button+3) > 0
}

func (m ButtonMask) Clicked(button MouseButton) bool {
	return m&(1<<button+6) > 0
}

func (m ButtonMask) anyPressed() bool {
	return m.Pressed(MouseButtonLeft) || m.Pressed(MouseButtonMiddle) || m.Pressed(MouseButtonRight)
}

func (m ButtonMask) anyClicked() bool {
	return m.Clicked(MouseButtonLeft) || m.Clicked(MouseButtonMiddle) || m.Clicked(MouseButtonRight)
}
