package util

import (
	"galaxy/calc"
	"math"
)

// WrapF maps value into the half-open interval [0, float64(size)).
// It supports negative input values and is used for torus coordinates
// when the coordinate is represented as float64.
//
// size must be greater than zero.
func WrapF(value float64, size int) float64 {
	if size <= 0 {
		panic("WrapF: size must be > 0")
	}

	s := float64(size)

	r := math.Mod(value, s)
	if r < 0 {
		r += s
	}

	// Protect against a possible boundary artifact and keep result in [0, s).
	// In normal cases math.Mod already gives a value with |r| < s.
	if r >= s {
		r -= s
	}

	return r
}

func NextTravelCoord(w, h uint32, x1, y1, x2, y2, delta float64) (float64, float64, bool) {
	deltaX, deltaY := calc.Deltas(w, h, x1, y1, x2, y2)
	distance := math.Hypot(deltaX, deltaY)
	if distance <= delta {
		return x2, y2, true
	}
	// [ ] refactor - remove extra vars
	xa := 0.
	ya := 0.
	xb := deltaX
	yb := deltaY
	d := distance
	d2 := delta
	xc := xa - (d2*(xa-xb))/d
	yc := ya - (d2*(ya-yb))/d

	// ---
	var tx, ty float64

	if math.Abs(x2-x1) > float64(w/2) {
		// moving across X boundary
		if x2 < x1 {
			// moving across higher border
			tx = math.Mod(x1+xc, float64(w))
		} else {
			// moving across lower border
			tx = x1 - xc
			if tx < 0 {
				tx = float64(w) + tx
			}
		}
	} else {
		if x2 < x1 {
			tx = x1 - xc
		} else {
			tx = x1 + xc
		}
	}

	if math.Abs(y2-y1) > float64(h/2) {
		// moving across Y boundary
		if y2 < y1 {
			// moving across higher border
			ty = math.Mod(y1+yc, float64(h))
		} else {
			// moving across lower border
			ty = y1 - yc
			if ty < 0 {
				ty = float64(h) + ty
			}
		}
	} else {
		if y2 < y1 {
			ty = y1 - yc
		} else {
			ty = y1 + yc
		}
	}

	return tx, ty, false
}
