package yourock

import . "github.com/golangconf/gophers-and-dragons/game"

const MagicArrowMP = 1
const FireboltMP = 3
const HealMP = 4
const RestMP = 2

const HealAvg = 12.5

const DragonDmgAvg = 5.5
const PowerAttackDmgAvg = 4.5
const AttackDmgAvg = 3

func heroCanSurviveDragon(s State) bool {
	dragonHP := float64(s.Creep.HP)
	myHP := float64(s.Avatar.HP)

	manaLeft := s.Avatar.MP
	healsLeft := s.Deck[CardHeal].Count
	parriesLeft := s.Deck[CardParry].Count
	powersLeft := s.Deck[CardPowerAttack].Count
	stunsLeft := s.Deck[CardStun].Count

	for dragonHP > 0 && myHP > 0 {
		if myHP <= 25 && healsLeft > 0 && manaLeft >= HealMP {
			myHP += HealAvg - DragonDmgAvg
			healsLeft--
			manaLeft -= HealMP
			continue
		}

		if parriesLeft > 0 {
			dragonHP -= DragonDmgAvg
			continue
		}

		if stunsLeft > 0 {
			stunsLeft--
			if powersLeft > 0 {
				powersLeft--
				dragonHP -= PowerAttackDmgAvg
			} else {
				dragonHP -= AttackDmgAvg
			}
			continue
		}

		myHP -= DragonDmgAvg

		if powersLeft > 0 {
			powersLeft--
			dragonHP -= PowerAttackDmgAvg
			continue
		}

		dragonHP -= AttackDmgAvg
	}

	return myHP > 0 && dragonHP < 0
}

func fightDragon(s State) CardType {
	if s.Creep.IsFull() && !heroCanSurviveDragon(s) {
		if s.Can(CardHeal) {
			return CardHeal
		}

		return CardRetreat
	}

	if s.Avatar.HP <= 25 && s.Can(CardHeal) {
		return CardHeal
	}

	if !s.Creep.IsStunned() && s.Can(CardParry) {
		return CardParry
	}

	if !s.Creep.IsStunned() && s.Can(CardStun) {
		return CardStun
	}

	if s.Can(CardPowerAttack) {
		return CardPowerAttack
	}

	return CardAttack
}

func fightMummy(s State) CardType {
	if s.Creep.IsFull() {
		if s.Avatar.MP >= 2*FireboltMP && s.Deck[CardFirebolt].Count >= 2 {
			return CardFirebolt
		}

		return CardRetreat
	}

	if s.Creep.HP <= 2 {
		return CardAttack
	} else if s.Creep.HP <= 3 && s.Avatar.MP >= HealMP+MagicArrowMP {
		return CardMagicArrow
	} else if s.Can(CardFirebolt) {
		return CardFirebolt
	}

	return CardRetreat
}

func fightClaws(s State) CardType {
	if s.Creep.IsFull() {
		potentialHPLeft := float64(s.Avatar.HP)
		mpLeft := s.Avatar.MP
		for i := 0; i < s.Deck[CardHeal].Count && mpLeft >= HealMP; i++ {
			mpLeft -= HealMP
			potentialHPLeft += HealAvg
		}

		// Each turn Claws takes out 3 HP but only until your HP >= 20.
		// This variable estimates how many turns we have to kill Claws until
		// our HP drops below 20 and we would have to retreat.
		maxTurnsToFight := int((potentialHPLeft - 20.0) / 3.0)
		turnsToKillClaws := s.Creep.HP / AttackDmgAvg // should be precisely 4

		if turnsToKillClaws > maxTurnsToFight {
			return CardRetreat
		}
	}

	if s.Avatar.HP <= 20 && s.Creep.HP > 3 {
		return CardRetreat
	}

	if s.Creep.HP == 3 && s.Avatar.MP >= MagicArrowMP+HealMP && s.Can(CardMagicArrow) {
		return CardMagicArrow
	}

	return CardAttack
}

func fightKubus(s State) CardType {
	// not worth it most of the time
	return CardRetreat
}

func ChooseCard(s State) CardType {
	if s.Creep.Type == CreepCheepy {
		if s.Creep.IsFull() && s.Avatar.HP <= 25 && s.Can(CardHeal) {
			return CardHeal
		}

		if s.Creep.IsFull() && s.Avatar.HP <= 20 && s.Can(CardRest) {
			return CardRest
		}

		return CardAttack
	}

	if s.Creep.Type == CreepDragon {
		return fightDragon(s)
	}

	minHealHP := 10
	if s.Creep.Damage.High() <= 4 {
		minHealHP = 25
	} else if s.Creep.Traits.Has(TraitBloodlust) {
		minHealHP = 20
	}

	if s.Avatar.HP <= minHealHP && s.Can(CardHeal) {
		return CardHeal
	}

	if s.Creep.Type == CreepClaws {
		return fightClaws(s)
	}

	if s.Creep.Type == CreepKubus {
		return fightKubus(s)
	}

	if s.Creep.Type == CreepMummy {
		return fightMummy(s)
	}

	if s.Round >= 10 && s.Avatar.MP >= FireboltMP+HealMP && s.Can(CardFirebolt) {
		return CardFirebolt
	}

	if s.Creep.Damage.High() >= 5 && s.Can(CardPowerAttack) {
		return CardPowerAttack
	}

	if s.Creep.HP == 3 && s.Avatar.MP >= MagicArrowMP+HealMP && s.Can(CardMagicArrow) {
		return CardMagicArrow
	}

	return CardAttack
}