package controller

import (
	"fmt"
	"iter"

	"galaxy/util"

	"galaxy/game/internal/model/game"
)

func (c *Cache) MoveShipGroups() {
	moved := make(map[int]bool)
	for i := range c.listMoveableGroupIds() {
		if v, ok := moved[i]; ok && v {
			continue
		}
		sg := c.ShipGroup(i)

		if sg.FleetID != nil {
			fi := c.MustFleetIndex(*sg.FleetID)
			delta, _ := c.FleetSpeedAndMass(fi)
			for fgi := range c.fleetGroupIds(c.RaceIndex(sg.OwnerID), c.MustFleetIndex(*sg.FleetID)) {
				c.moveShipGroup(fgi, delta)
				moved[fgi] = true
			}
			continue
		}

		c.moveShipGroup(i, sg.Speed(c.ShipGroupShipClass(i)))
		moved[i] = true
	}
}

func (c *Cache) moveShipGroup(i int, delta float64) {
	sg := c.ShipGroup(i)
	originX, originY, ok := sg.Coord()
	if !ok {
		panic(fmt.Sprintf("ship group state invalid: %v", sg.State()))
	}
	destPlanet := c.MustPlanet(sg.Destination)
	arrived := false
	var x, y float64
	x, y, arrived =
		util.NextTravelCoord(c.g.Map.Width, c.g.Map.Height, originX, originY, destPlanet.X.F(), destPlanet.Y.F(), delta)
	fx, fy := game.F(x), game.F(y)
	sg.StateInSpace.X = &fx
	sg.StateInSpace.Y = &fy
	if arrived {
		sg.StateInSpace = nil
	}
}

func (c *Cache) listMoveableGroupIds() iter.Seq[int] {
	return func(yield func(int) bool) {
		for i := range c.ShipGroupsIndex() {
			sg := c.ShipGroup(i)
			state := sg.State()
			if !(state == game.StateInOrbit || state == game.StateLaunched || state == game.StateInSpace) {
				continue
			}
			if !yield(i) {
				return
			}
		}
	}
}
