package controller_test

import (
	"fmt"

	"galaxy/game/internal/controller"
	"galaxy/game/internal/model/game"

	"github.com/google/uuid"
)

var (
	Race_0 = game.Race{
		ID:      Race_0_ID,
		VoteFor: Race_0_ID,
		Name:    "Race_0",
		TTL:     10,
		Tech: map[game.Tech]game.Float{
			game.TechDrive:   1.1,
			game.TechWeapons: 1.2,
			game.TechShields: 1.3,
			game.TechCargo:   1.4,
		},
		Relations: []game.RaceRelation{
			{RaceID: Race_1_ID, Relation: game.RelationWar},
			{RaceID: Race_2_ID, Relation: game.RelationWar},
		},
	}
	Race_1 = game.Race{
		ID:      Race_1_ID,
		VoteFor: Race_1_ID,
		Name:    "Race_1",
		TTL:     10,
		Tech: map[game.Tech]game.Float{
			game.TechDrive:   2.1,
			game.TechWeapons: 2.2,
			game.TechShields: 2.3,
			game.TechCargo:   2.4,
		},
		Relations: []game.RaceRelation{
			{RaceID: Race_0_ID, Relation: game.RelationPeace},
			{RaceID: Race_2_ID, Relation: game.RelationPeace},
		},
	}
	Race_Extinct = game.Race{
		ID:      Race_2_ID,
		VoteFor: Race_2_ID,
		Name:    "Race_Extinct",
		Extinct: true,
		TTL:     0,
		Tech: map[game.Tech]game.Float{
			game.TechDrive:   3.1,
			game.TechWeapons: 3.2,
			game.TechShields: 3.3,
			game.TechCargo:   3.4,
		},
		Relations: []game.RaceRelation{
			{RaceID: Race_0_ID, Relation: game.RelationPeace},
			{RaceID: Race_1_ID, Relation: game.RelationWar},
		},
	}

	Race_0_ID                 = uuid.New()
	Race_0_idx                = 0
	Race_0_Gunship            = "R0_Gunship"
	Race_0_Freighter          = "R0_Freighter"
	R0_Planet_0_num      uint = 0
	R0_Planet_2_num      uint = 2
	Race_0_Gunship_idx        = 0
	Race_0_Freighter_idx      = 1
	Race_0_Cruiser_idx        = 2

	Race_1_ID                 = uuid.New()
	Race_1_idx                = 1
	Race_1_Gunship            = "R1_Gunship"
	Race_1_Freighter          = "R1_Freighter"
	R1_Planet_1_num      uint = 1
	Race_1_Gunship_idx        = 0
	Race_1_Freighter_idx      = 1
	Race_1_Cruiser_idx        = 2

	Race_2_ID = uuid.New()

	Uninhabited_Planet_3_num uint = 3
	Uninhabited_Planet_4_num uint = 4

	ShipType_Cruiser = "Cruiser"

	Cruiser = game.ShipType{
		Name:     "Cruiser",
		Drive:    15,
		Armament: 1,
		Weapons:  15,
		Shields:  15,
		Cargo:    0,
	}

	BadEntityName = "_Bad_entitty_Name"
	UnknownRace   = "UnknownRace"

	InSpace = game.InSpace{Origin: 2, X: floatRef(1.23), Y: floatRef(1.23)}
)

func assertNoError(err error) {
	if err != nil {
		panic(fmt.Sprintf("init assertion failed: %v", err))
	}
}

func newGame() *game.Game {
	g := &game.Game{
		Race: []game.Race{
			Race_0,
			Race_1,
			Race_Extinct,
		},
		Map: game.Map{
			Width:  1000,
			Height: 1000,
			Planet: []game.Planet{
				controller.NewPlanet(R0_Planet_0_num, "Planet_0", &Race_0.ID, 1, 1, 100, 100, 100, 0, game.ProductionCapital.AsType(uuid.Nil)),
				controller.NewPlanet(R1_Planet_1_num, "Planet_1", &Race_1.ID, 2, 2, 100, 0, 0, 0, game.ProductionCapital.AsType(uuid.Nil)),
				controller.NewPlanet(R0_Planet_2_num, "Planet_2", &Race_0.ID, 3, 3, 100, 0, 0, 0, game.ProductionCapital.AsType(uuid.Nil)),
				controller.NewPlanet(Uninhabited_Planet_3_num, "Planet_3", &uuid.Nil, 500, 500, 100, 0, 0, 0, game.ProductionNone.AsType(uuid.Nil)),
				controller.NewPlanet(Uninhabited_Planet_4_num, "Planet_4", nil, 10, 10, 500, 0, 0, 10, game.ProductionNone.AsType(uuid.Nil)),
			},
		},
	}
	return g
}

func newCache() (*controller.Cache, *controller.Controller) {
	ctl := &controller.Controller{
		RepoController: nil,
		Cache:          controller.NewCache(newGame()),
	}
	assertNoError(ctl.Cache.ShipClassCreate(Race_0_idx, Race_0_Gunship, 60, 3, 30, 100, 0))
	assertNoError(ctl.Cache.ShipClassCreate(Race_0_idx, Race_0_Freighter, 8, 0, 0, 2, 10))
	assertNoError(ctl.Cache.ShipClassCreate(Race_0_idx, ShipType_Cruiser, Cruiser.Drive.F(), int(Cruiser.Armament), Cruiser.Weapons.F(), Cruiser.Shields.F(), Cruiser.Cargo.F()))

	assertNoError(ctl.Cache.ShipClassCreate(Race_1_idx, Race_1_Gunship, 60, 3, 30, 100, 0))
	assertNoError(ctl.Cache.ShipClassCreate(Race_1_idx, Race_1_Freighter, 8, 0, 0, 2, 10))
	assertNoError(ctl.Cache.ShipClassCreate(Race_1_idx, ShipType_Cruiser, 15, 2, 15, 15, 0)) // same name - different type (why.)

	return ctl.Cache, ctl
}

func floatRef(v float64) *game.Float {
	f := game.Float(v)
	return &f
}
