package components

import (
	"fmt"
	"image"
	. "openquell/config"
)

// physical location on screen
type Position struct {
	X        int
	Y        int
	Cellsize int
	Rect     *image.Rectangle
}

func (position *Position) Update(x, y int, size ...int) {
	if len(size) == 1 {
		position.Cellsize = size[0]
	}

	position.X = x
	position.Y = y

	rect := image.Rect(x, y, x+position.Cellsize, y+position.Cellsize)
	position.Rect = &rect
}

func NewPosition(point image.Point, cellsize int) *Position {
	position := &Position{}
	position.Update(point.X*cellsize, point.Y*cellsize, cellsize)
	return position
}

func (position *Position) GetMoved(velosity *Velocity) *Position {
	pos := &Position{}
	pos.Update(position.X+(velosity.Data.X*velosity.Speed),
		position.Y+(velosity.Data.Y*velosity.Speed), position.Cellsize)

	return pos
}

func (position *Position) Point() image.Point {
	return image.Point{position.X / position.Cellsize, position.Y / position.Cellsize}
}

func (position *Position) Left() int {
	return position.X
}

func (position *Position) Right() int {
	return position.X + position.Cellsize
}

func (position *Position) Top() int {
	return position.Y
}

func (position *Position) Bottom() int {
	return position.Y + position.Cellsize
}

func (position *Position) String() string {
	return fmt.Sprintf("[%d,%d](Left:%d,Top:%d) x (Right:%d,Bottom:%d)",
		position.X/32,
		position.Y/32,
		position.X,
		position.Y,
		position.Right(),
		position.Bottom(),
	)
}

func (position *Position) Move(velocity *Velocity) {
	// if velocity.Direction != 0 {
	// 	slog.Debug("moving", "velocity", velocity, "speed", speed)
	// }
	position.Update(
		position.X+(velocity.Data.X*velocity.Speed),
		position.Y+(velocity.Data.Y*velocity.Speed),
	)
}

func (position *Position) Set(newpos *Position) {
	position.Update(newpos.X, newpos.Y)
}

func (tile *Position) Intersects(moving *Position, velocity *Velocity) (bool, *Position) {
	object := moving.GetMoved(velocity)

	is := tile.Rect.Bounds().Intersect(object.Rect.Bounds())
	if is != image.ZR {

		// collision, snap into neighbouring tile depending on the direction
		switch velocity.Direction {
		case West:
			object.Update(tile.Rect.Max.X, tile.Y)
		case East:
			object.Update(tile.Rect.Min.X-tile.Cellsize, tile.Y)
		case South:
			object.Update(tile.X, tile.Rect.Min.Y-tile.Cellsize)
		case North:
			object.Update(tile.X, tile.Rect.Max.Y)
		}

		// slog.Debug("Intersect",
		// 	"velocity", velocity.Data,
		// 	"player", moving,
		// 	"moved player", object,
		// 	"collision at", is,
		// 	"tilepos", tile,
		// )
		return true, object
	}

	return false, nil
}

func (tile *Position) Intersecting(position *Position, velocity *Velocity) bool {
	is := tile.Rect.Bounds().Intersect(position.Rect.Bounds())
	return is != image.ZR
}
