package controller

import (
	"iter"

	e "galaxy/error"

	"galaxy/game/internal/model/game"

	"github.com/google/uuid"
)

func (c *Cache) CreateShips(ri int, shipTypeName string, planetNumber uint, quantity int) error {
	class, _, ok := c.ShipClass(ri, shipTypeName)
	if !ok {
		return e.NewEntityNotExistsError("ship class q", shipTypeName)
	}

	p, ok := c.Planet(planetNumber)
	if !ok {
		return e.NewEntityNotExistsError("planet #%d", planetNumber)
	}
	if !p.OwnedBy(c.g.Race[ri].ID) {
		return e.NewEntityNotOwnedError("planet #%d", planetNumber)
	}

	c.unsafeCreateShips(ri, class.ID, p.Number, uint(quantity))

	return nil
}

func (c *Cache) AddRace(n string) (int, uuid.UUID) {
	id := uuid.New()
	r := &game.Race{
		ID:        id,
		VoteFor:   id,
		Name:      n,
		Tech:      game.NewTechSet(),
		Relations: make([]game.RaceRelation, len(c.g.Race)),
	}
	c.g.Race = append(c.g.Race, *r)
	for i := range c.listRaceIdx() {
		if c.g.Race[i].ID != id {
			c.g.Race[i].Relations = append(c.g.Race[i].Relations, game.RaceRelation{RaceID: id, Relation: game.RelationPeace})
			continue
		}
		for j := range c.g.Race[i].Relations {
			c.g.Race[i].Relations[j].RaceID = c.g.Race[j].ID
			c.g.Race[i].Relations[j].Relation = game.RelationPeace
		}
	}
	return len(c.g.Race) - 1, id
}

func (c *Cache) Race(i int) *game.Race {
	c.validateRaceIndex(i)
	return &c.g.Race[i]
}

func (c *Cache) RaceShipGroups(ri int) iter.Seq[*game.ShipGroup] {
	return c.listShipGroups(ri)
}

func (c *Cache) RaceScience(ri int) []game.Science {
	return c.raceScience(ri)
}

func (c *Cache) ListFleets(ri int) iter.Seq[*game.Fleet] {
	return c.listFleets(ri)
}

func (c *Cache) MustFleetID(ri int, name string) uuid.UUID {
	for f := range c.listFleets(ri) {
		if f.Name == name {
			return f.ID
		}
	}
	panic("fleet not found")
}

func (c *Cache) MustShipClass(ri int, name string) *game.ShipType {
	st, _, ok := c.ShipClass(ri, name)
	if !ok {
		panic("ship class not found")
	}
	return st
}

func (c *Cache) PutPopulation(pn uint, v float64) {
	c.putPopulation(pn, v)
}

func (c *Cache) PutColonists(pn uint, v float64) {
	c.putColonists(pn, v)
}

func (c *Cache) PutMaterial(pn uint, v float64) {
	c.putMaterial(pn, v)
}

func (c *Cache) RaceTechLevel(ri int, t game.Tech, v float64) {
	c.raceTechLevel(ri, t, v)
}

func (c *Cache) ListRoutedSendGroupIds(pn uint) iter.Seq[int] {
	return c.listRoutedSendGroupIds(pn)
}

func (c *Cache) ListRoutedUnloadShipGroupIds(pn uint, rt game.RouteType) iter.Seq[int] {
	return c.listRoutedUnloadShipGroupIds(pn, rt)
}

func (c *Cache) SelectColUnloadGroup(groups []int) (result iter.Seq[int]) {
	return c.selectColUnloadGroup(groups)
}

func (c *Cache) ListMoveableGroupIds() iter.Seq[int] {
	return c.listMoveableGroupIds()
}

func (c *Cache) CollectBombingGroups() map[uint]map[int][]int {
	return c.collectBombingGroups()
}

func BombPlanet(p *game.Planet, power float64) {
	bombPlanet(p, power)
}

func (c *Cache) ListProducingPlanets() iter.Seq[uint] {
	return c.listProducingPlanets()
}

func (c *Cache) VotesByRace() map[int]float64 {
	return c.votesByRace()
}

func VotingWinners(calc []*VoteGroup, gameVotes float64) []int {
	return votingWinners(calc, gameVotes)
}

func (c *Cache) CreateShipsUnsafe_T(ri int, classID uuid.UUID, planet uint, quantity uint) int {
	return c.unsafeCreateShips(ri, classID, planet, quantity)
}

func (c *Cache) WipeRace(ri int) {
	c.wipeRace(ri)
}

func (c *Cache) UnsafeDeleteShipGroup(sgi int) {
	c.unsafeDeleteShipGroup(sgi)
}
