package main

import (
	"math/rand"
	"testing"
)

func TestRollEncounterMoreLikelyInDangerousSystems(t *testing.T) {
	safe := WayfarerSystem{Government: GovCorporateState}
	dangerous := WayfarerSystem{Government: GovAnarchy}

	safeCount, dangerousCount := 0, 0
	for seed := int64(0); seed < 1000; seed++ {
		if RollEncounter(safe, rand.New(rand.NewSource(seed))) != EncounterNone {
			safeCount++
		}
		if RollEncounter(dangerous, rand.New(rand.NewSource(seed))) != EncounterNone {
			dangerousCount++
		}
	}
	if dangerousCount <= safeCount {
		t.Errorf("в опасной системе встреч должно быть заметно больше: dangerous=%d safe=%d", dangerousCount, safeCount)
	}
}

func TestRollQuestOfferNoneWhenQuestActive(t *testing.T) {
	s := NewWayfarerShip(WayfarerSystemID{})
	s.StartQuest(WayfarerQuestDefs[0].Key)

	for seed := int64(0); seed < 200; seed++ {
		if _, ok := RollQuestOffer(s, rand.New(rand.NewSource(seed))); ok {
			t.Fatalf("не должно предлагаться заданий, пока уже есть активное")
		}
	}
}

func TestRollQuestOfferNoneWhenAllCompleted(t *testing.T) {
	s := NewWayfarerShip(WayfarerSystemID{})
	for _, q := range WayfarerQuestDefs {
		s.CompletedQuests[q.Key] = true
	}

	for seed := int64(0); seed < 200; seed++ {
		if _, ok := RollQuestOffer(s, rand.New(rand.NewSource(seed))); ok {
			t.Fatalf("не должно предлагаться заданий, если все уже выполнены")
		}
	}
}

func TestRollQuestOfferSkipsCompletedAndFailed(t *testing.T) {
	s := NewWayfarerShip(WayfarerSystemID{})
	for i, q := range WayfarerQuestDefs {
		if i%2 == 0 {
			s.CompletedQuests[q.Key] = true
		} else {
			s.FailedQuests[q.Key] = true
		}
	}
	// оставляем ровно одно доступное задание
	lastKey := WayfarerQuestDefs[len(WayfarerQuestDefs)-1].Key
	delete(s.CompletedQuests, lastKey)
	delete(s.FailedQuests, lastKey)

	found := false
	for seed := int64(0); seed < 500 && !found; seed++ {
		if key, ok := RollQuestOffer(s, rand.New(rand.NewSource(seed))); ok {
			if key != lastKey {
				t.Fatalf("предложено завершённое/провальное задание %q вместо единственного доступного %q", key, lastKey)
			}
			found = true
		}
	}
	if !found {
		t.Fatalf("за 500 попыток ни разу не предложилось единственное доступное задание")
	}
}

func TestRollQuestOfferHappensSometimesNotAlways(t *testing.T) {
	s := NewWayfarerShip(WayfarerSystemID{})
	offered, skipped := 0, 0
	for seed := int64(0); seed < 500; seed++ {
		if _, ok := RollQuestOffer(s, rand.New(rand.NewSource(seed))); ok {
			offered++
		} else {
			skipped++
		}
	}
	if offered == 0 {
		t.Errorf("за 500 попыток ни разу не предложилось задание — вероятность должна быть больше нуля")
	}
	if skipped == 0 {
		t.Errorf("за 500 попыток задание предлагалось абсолютно всегда — должны быть и тихие прилёты")
	}
}

func TestGeneratePirateStatsScaleWithDanger(t *testing.T) {
	safe := WayfarerSystem{Government: GovCorporateState}
	dangerous := WayfarerSystem{Government: GovAnarchy}

	safeSum, dangerousSum := 0, 0
	for seed := int64(0); seed < 100; seed++ {
		h1, _, _ := GeneratePirateStats(safe, rand.New(rand.NewSource(seed)))
		h2, _, _ := GeneratePirateStats(dangerous, rand.New(rand.NewSource(seed)))
		safeSum += h1
		dangerousSum += h2
	}
	if dangerousSum <= safeSum {
		t.Errorf("пираты в опасных системах должны быть в среднем крепче: dangerous=%d safe=%d", dangerousSum, safeSum)
	}
}

func TestHasIllegalCargoDetection(t *testing.T) {
	s := NewWayfarerShip(WayfarerSystemID{})
	if s.HasIllegalCargo() {
		t.Fatalf("новый корабль не должен везти незаконный груз")
	}
	idx := commodityIndexByKey(t, "commodity.contraband")
	s.Cargo[idx] = 3
	if !s.HasIllegalCargo() {
		t.Errorf("контрабанда в трюме должна была определиться как незаконный груз")
	}
}

func TestConfiscateIllegalCargoRemovesItAndReturnsValue(t *testing.T) {
	s := NewWayfarerShip(WayfarerSystemID{})
	idx := commodityIndexByKey(t, "commodity.contraband")
	s.Cargo[idx] = 4
	lost := s.ConfiscateIllegalCargo()
	if s.Cargo[idx] != 0 {
		t.Errorf("незаконный груз должен был полностью изыматься")
	}
	if lost <= 0 {
		t.Errorf("должна была вернуться положительная оценка изъятого, получено %v", lost)
	}
	legalIdx := commodityIndexByKey(t, "commodity.food")
	s.Cargo[legalIdx] = 10
	s.ConfiscateIllegalCargo()
	if s.Cargo[legalIdx] != 10 {
		t.Errorf("законный груз не должен был пострадать при конфискации")
	}
}

func TestDerelictFindAddsCredits(t *testing.T) {
	s := NewWayfarerShip(WayfarerSystemID{})
	before := s.Credits
	rnd := rand.New(rand.NewSource(1))
	found := s.DerelictFind(rnd)
	if found <= 0 {
		t.Errorf("находка должна быть положительной, получено %v", found)
	}
	if s.Credits != before+found {
		t.Errorf("кредиты должны были вырасти ровно на размер находки")
	}
}

func TestHelpDistressedEventuallyTrapsAndRewards(t *testing.T) {
	trapSeen, rewardSeen := false, false
	for seed := int64(0); seed < 200 && !(trapSeen && rewardSeen); seed++ {
		s := NewWayfarerShip(WayfarerSystemID{})
		before := s.Credits
		reward, wasTrap := s.HelpDistressed(rand.New(rand.NewSource(seed)))
		if wasTrap {
			trapSeen = true
			if s.Credits != before {
				t.Errorf("ловушка не должна была начислять кредиты")
			}
		} else {
			rewardSeen = true
			if reward <= 0 || s.Credits != before+reward {
				t.Errorf("честная помощь должна была начислить положительную награду")
			}
		}
	}
	if !trapSeen || !rewardSeen {
		t.Errorf("ожидались оба исхода помощи бедствующим: ловушка=%v награда=%v", trapSeen, rewardSeen)
	}
}
