package game

import (
	"testing"
	"time"

	"github.com/denisovdennis/autohero/internal/model"
)

func TestSimulateOneFight_HeroSurvives(t *testing.T) {
	hero := &model.Hero{
		Level: 1, XP: 0,
		MaxHP: 10000, HP: 10000,
		Attack: 100, Defense: 60, Speed: 1.0,
		Strength: 10, Constitution: 10, Agility: 10, Luck: 5,
		State: model.StateWalking,
	}

	now := time.Now()
	survived, enemy, xpGained, goldGained := SimulateOneFight(hero, now, nil, nil, nil)

	if !survived {
		t.Fatalf("overpowered hero should survive, enemy was %s", enemy.Name)
	}
	if xpGained <= 0 {
		t.Fatal("expected positive XP gain")
	}
	if goldGained <= 0 {
		t.Fatal("expected positive gold gain")
	}
	if enemy.Name == "" {
		t.Fatal("expected enemy with a name")
	}
}

func TestSimulateOneFight_HeroDies(t *testing.T) {
	hero := &model.Hero{
		Level: 1, XP: 0,
		MaxHP: 1, HP: 1,
		Attack: 1, Defense: 0, Speed: 1.0,
		State: model.StateWalking,
	}

	now := time.Now()
	survived, _, _, _ := SimulateOneFight(hero, now, nil, nil, nil)

	if survived {
		t.Fatal("1 HP hero should die to any enemy")
	}
	if hero.HP != 0 {
		t.Fatalf("expected HP 0 after death, got %d", hero.HP)
	}
	if hero.State != model.StateDead {
		t.Fatalf("expected state dead, got %s", hero.State)
	}
}

func TestSimulateOneFight_LevelUp(t *testing.T) {
	// Seed XP just below L1->L2 threshold (180 in v3).
	hero := &model.Hero{
		Level: 1, XP: 179,
		MaxHP: 10000, HP: 10000,
		Attack: 100, Defense: 60, Speed: 1.0,
		Strength: 10, Constitution: 10, Agility: 10, Luck: 5,
		State: model.StateWalking,
	}

	now := time.Now()
	survived, _, xpGained, _ := SimulateOneFight(hero, now, nil, nil, nil)

	if !survived {
		t.Fatal("overpowered hero should survive")
	}
	if xpGained <= 0 {
		t.Fatal("expected XP gain")
	}
	if hero.Level < 2 {
		t.Fatalf("expected level 2+ after gaining %d XP from 179 base, got level %d", xpGained, hero.Level)
	}
}

func TestSimulateOneFight_PotionUsage(t *testing.T) {
	// Create a hero that will take significant damage but survive.
	hero := &model.Hero{
		Level: 1, XP: 0,
		MaxHP: 100, HP: 100,
		Attack: 50, Defense: 3, Speed: 1.0,
		Potions: 5,
		State:   model.StateWalking,
	}

	now := time.Now()
	startPotions := hero.Potions

	// Run multiple fights — at least one should use a potion.
	for i := 0; i < 20; i++ {
		if hero.HP <= 0 {
			break
		}
		hero.HP = 25 // force low HP to trigger potion usage
		SimulateOneFight(hero, now, nil, nil, nil)
	}

	if hero.Potions >= startPotions {
		t.Log("no potions used after 20 fights with low HP — may be probabilistic, not a hard failure")
	}
}

func TestPickEnemyForLevel(t *testing.T) {
	tests := []struct {
		level int
	}{
		{1}, {5}, {10}, {20}, {50},
	}

	for _, tt := range tests {
		enemy := PickEnemyForLevel(tt.level)
		if enemy.Name == "" {
			t.Errorf("PickEnemyForLevel(%d) returned enemy with empty name", tt.level)
		}
		if enemy.MaxHP <= 0 {
			t.Errorf("PickEnemyForLevel(%d) returned enemy with MaxHP=%d", tt.level, enemy.MaxHP)
		}
		if enemy.HP != enemy.MaxHP {
			t.Errorf("PickEnemyForLevel(%d) returned enemy with HP=%d != MaxHP=%d", tt.level, enemy.HP, enemy.MaxHP)
		}
	}
}

func TestScaleEnemyTemplate(t *testing.T) {
	tmpl := model.EnemyTemplates[model.EnemyWolf]
	scaled := ScaleEnemyTemplate(tmpl, 5)

	if scaled.MaxHP <= tmpl.MaxHP {
		t.Errorf("scaled MaxHP %d should exceed base %d at level 5", scaled.MaxHP, tmpl.MaxHP)
	}
	if scaled.HP != scaled.MaxHP {
		t.Errorf("scaled HP %d should equal MaxHP %d", scaled.HP, scaled.MaxHP)
	}
}
