package controller

import (
	"galaxy/calc"
	e "galaxy/error"

	"galaxy/game/internal/model/game"

	"github.com/google/uuid"
)

func (c *Cache) shipGroupSend(ri int, groupID uuid.UUID, planetNumber uint) error {
	c.validateRaceIndex(ri)

	sgi, ok := c.raceShipGroupIndex(ri, groupID)
	if !ok {
		return e.NewEntityNotExistsError("group %s", groupID)
	}
	st := c.ShipGroupShipClass(sgi)

	pcount := 0
	for i := range c.g.Map.Planet {
		if c.g.Map.Planet[i].OwnedBy(c.g.Race[ri].ID) {
			pcount++
			break
		}
	}
	if pcount == 0 {
		return e.NewSendShipOwnerHasNoPlanetsError()
	}

	if st.DriveBlockMass() == 0 {
		return e.NewSendShipHasNoDrivesError()
	}

	sourcePlanet, ok := c.ShipGroup(sgi).AtPlanet()
	if !ok {
		return e.NewShipsBusyError("state: %s", c.ShipGroup(sgi).State())
	}

	p1, ok := c.Planet(sourcePlanet)
	if !ok {
		return e.NewGameStateError("source planet #%d does not exists", sourcePlanet)
	}
	p2, ok := c.Planet(planetNumber)
	if !ok {
		return e.NewEntityNotExistsError("destination planet #%d", planetNumber)
	}
	rangeToDestination := calc.ShortDistance(c.g.Map.Width, c.g.Map.Height, p1.X.F(), p1.Y.F(), p2.X.F(), p2.Y.F())
	if rangeToDestination > c.g.Race[ri].FlightDistance() {
		return e.NewSendUnreachableDestinationError("range=%.03f", rangeToDestination)
	}

	if p1.Number == p2.Number {
		c.UnsendShips(sgi)
		c.shipGroupMerge(ri)
		return nil
	}

	c.LaunchShips(sgi, planetNumber)

	return nil
}

func (c *Cache) LaunchShips(sgi int, destination uint) *game.ShipGroup {
	sg := c.ShipGroup(sgi)
	var p *game.Planet
	switch sg.State() {
	case game.StateInOrbit:
		p = c.MustPlanet(sg.Destination)
	case game.StateLaunched:
		p = c.MustPlanet(sg.StateInSpace.Origin)
	default:
		panic("state invalid")
	}
	c.g.ShipGroups[sgi] = LaunchShips(*sg, destination, p.X.F(), p.Y.F())
	return &c.g.ShipGroups[sgi]
}

func (c *Cache) UnsendShips(sgi int) *game.ShipGroup {
	sg := c.ShipGroup(sgi)
	if sg.State() != game.StateLaunched {
		panic("state invalid")
	}
	c.g.ShipGroups[sgi] = UnsendShips(*sg)
	return &c.g.ShipGroups[sgi]
}

func LaunchShips(sg game.ShipGroup, destination uint, originX, originY float64) game.ShipGroup {
	sg.StateInSpace = &game.InSpace{
		Origin: sg.Destination,
		X:      nil,
		Y:      nil,
	}
	sg.Destination = destination
	return sg
}

func UnsendShips(sg game.ShipGroup) game.ShipGroup {
	sg.Destination = sg.StateInSpace.Origin
	sg.StateInSpace = nil
	return sg
}
