package game

import (
	"testing"
	"time"

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

func TestOrcWarriorBurstEveryThirdAttack(t *testing.T) {
	enemy := &model.Enemy{
		Type:             model.EnemyOrc,
		Attack:           12,
		Speed:            1.0,
		SpecialAbilities: []model.SpecialAbility{model.AbilityBurst},
	}

	// Attacks 1 and 2 should have multiplier 1.0
	m1 := EnemyAttackDamageMultiplier(enemy)
	if m1 != 1.0 {
		t.Fatalf("attack 1: expected multiplier 1.0, got %.2f", m1)
	}
	m2 := EnemyAttackDamageMultiplier(enemy)
	if m2 != 1.0 {
		t.Fatalf("attack 2: expected multiplier 1.0, got %.2f", m2)
	}

	// Attack 3 should deal 1.5x
	m3 := EnemyAttackDamageMultiplier(enemy)
	if m3 != 1.5 {
		t.Fatalf("attack 3: expected multiplier 1.5, got %.2f", m3)
	}

	// Attack 4 back to normal
	m4 := EnemyAttackDamageMultiplier(enemy)
	if m4 != 1.0 {
		t.Fatalf("attack 4: expected multiplier 1.0, got %.2f", m4)
	}
}

func TestLightningTitanChainLightning(t *testing.T) {
	enemy := &model.Enemy{
		Type:             model.EnemyLightningTitan,
		Attack:           30,
		Speed:            1.5,
		SpecialAbilities: []model.SpecialAbility{model.AbilityStun, model.AbilityChainLightning},
	}

	// Attacks 1-5 should be normal (no chain lightning)
	for i := 1; i <= 5; i++ {
		m := EnemyAttackDamageMultiplier(enemy)
		if m != 1.0 {
			t.Fatalf("attack %d: expected multiplier 1.0, got %.2f", i, m)
		}
	}

	// Attack 6 triggers chain lightning (3x)
	m6 := EnemyAttackDamageMultiplier(enemy)
	if m6 != 3.0 {
		t.Fatalf("attack 6: expected multiplier 3.0, got %.2f", m6)
	}
}

func TestIceGuardianAppliesIceSlow(t *testing.T) {
	hero := &model.Hero{
		ID: 1, HP: 100, MaxHP: 100,
		Attack: 10, Defense: 5, Speed: 1.0,
		Strength: 5, Constitution: 5, Agility: 5,
	}
	enemy := &model.Enemy{
		Type:             model.EnemyIceGuardian,
		Attack:           14,
		Defense:          15,
		Speed:            0.7,
		SpecialAbilities: []model.SpecialAbility{model.AbilityIceSlow},
	}

	now := time.Now()
	applied := false
	for i := 0; i < 200; i++ {
		hero.HP = hero.MaxHP
		hero.Debuffs = nil
		ProcessEnemyAttack(hero, enemy, now)
		for _, d := range hero.Debuffs {
			if d.Debuff.Type == model.DebuffIceSlow {
				applied = true
				if d.Debuff.Magnitude != 0.20 {
					t.Fatalf("IceSlow magnitude should be 0.20, got %.2f", d.Debuff.Magnitude)
				}
				break
			}
		}
		if applied {
			break
		}
	}
	if !applied {
		t.Fatal("Ice Guardian never applied IceSlow debuff in 200 attacks")
	}
}

func TestSkeletonKingSummonDamage(t *testing.T) {
	hero := &model.Hero{
		ID: 1, HP: 100, MaxHP: 100,
	}
	enemy := &model.Enemy{
		Type:             model.EnemySkeletonKing,
		Attack:           18,
		SpecialAbilities: []model.SpecialAbility{model.AbilityRegen, model.AbilitySummon},
	}

	start := time.Now()
	// Before 15 seconds: no summon damage.
	dmg := ProcessSummonDamage(hero, enemy, start, start, start.Add(10*time.Second))
	if dmg != 0 {
		t.Fatalf("expected no summon damage before 15s, got %d", dmg)
	}

	// At 15 seconds: summon damage should occur.
	dmg = ProcessSummonDamage(hero, enemy, start, start.Add(14*time.Second), start.Add(16*time.Second))
	if dmg == 0 {
		t.Fatal("expected summon damage after 15s boundary crossed")
	}
	expectedDmg := max(1, enemy.Attack/4)
	if dmg != expectedDmg {
		t.Fatalf("expected summon damage %d, got %d", expectedDmg, dmg)
	}
}

func TestLootGenerationOnEnemyDeath(t *testing.T) {
	drops := model.GenerateLoot(model.EnemyWolf, 1.0)
	if len(drops) == 0 {
		t.Fatal("expected at least one loot drop (gold)")
	}

	hasGold := false
	for _, d := range drops {
		if d.ItemType == "gold" {
			hasGold = true
			if d.GoldAmount <= 0 {
				t.Fatal("gold drop should have positive amount")
			}
		}
	}
	if !hasGold {
		t.Fatal("expected gold drop from GenerateLoot")
	}
}

func TestLuckMultiplierWithBuff(t *testing.T) {
	now := time.Now()
	hero := &model.Hero{
		Buffs: []model.ActiveBuff{{
			Buff:      mustBuffDef(model.BuffLuck),
			AppliedAt: now.Add(-time.Second),
			ExpiresAt: now.Add(10 * time.Second),
		}},
	}

	mult := LuckMultiplier(hero, now)
	if mult != 1.75 {
		t.Fatalf("expected luck multiplier 1.75, got %.2f", mult)
	}
}

func TestLuckMultiplierWithoutBuff(t *testing.T) {
	hero := &model.Hero{}
	mult := LuckMultiplier(hero, time.Now())
	if mult != 1.0 {
		t.Fatalf("expected luck multiplier 1.0 without buff, got %.1f", mult)
	}
}

func TestProcessDebuffDamageAppliesPoison(t *testing.T) {
	now := time.Now()
	hero := &model.Hero{
		HP: 100, MaxHP: 100,
		Debuffs: []model.ActiveDebuff{{
			Debuff:    mustDebuffDef(model.DebuffPoison),
			AppliedAt: now.Add(-time.Second),
			ExpiresAt: now.Add(4 * time.Second),
		}},
	}

	dmg := ProcessDebuffDamage(hero, time.Second, now)
	if dmg == 0 {
		t.Fatal("expected poison to deal damage over time")
	}
	if hero.HP >= 100 {
		t.Fatal("expected hero HP to decrease from poison")
	}
}

func TestDodgeAbilityCanAvoidDamage(t *testing.T) {
	now := time.Now()
	hero := &model.Hero{
		ID: 1, HP: 100, MaxHP: 100,
		Attack: 50, Defense: 0, Speed: 1.0,
		Strength: 10, Agility: 5,
	}
	enemy := &model.Enemy{
		Type:             model.EnemySkeletonArcher,
		MaxHP:            1000,
		HP:               1000,
		Attack:           10,
		Defense:          0,
		SpecialAbilities: []model.SpecialAbility{model.AbilityDodge},
	}

	dodged := false
	for i := 0; i < 200; i++ {
		enemy.HP = enemy.MaxHP
		evt := ProcessAttack(hero, enemy, now)
		if evt.Damage == 0 {
			dodged = true
			break
		}
	}
	if !dodged {
		t.Fatal("expected at least one dodge in 200 hero attacks against Skeleton Archer")
	}
}

func mustBuffDef(bt model.BuffType) model.Buff {
	b, ok := model.BuffDefinition(bt)
	if !ok {
		panic("missing buff def: " + string(bt))
	}
	return b
}

func mustDebuffDef(dt model.DebuffType) model.Debuff {
	d, ok := model.DebuffDefinition(dt)
	if !ok {
		panic("missing debuff def: " + string(dt))
	}
	return d
}
