package tactic

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

func ChooseCard(s game.State) game.CardType {

	// coef := s.Creep.Damage.High() + s.Creep.Damage.Low()
	// coef := s.Creep.Damage.High() + s.Creep.Damage.Low() + s.Creep.Damage.Low()
	coef := 25
	if s.Avatar.HP < coef {
		// If have a Heal card and enough MP to cast it, use it.
		if s.Can(game.CardHeal) {
			return game.CardHeal
		}
	}

	if shouldRest(s) {
		return game.CardRest
	}

	// Fight only weak monsters and run away from everything else.
	switch s.Creep.Type {
	case game.CreepCheepy, game.CreepImp:
		return game.CardAttack
	default:
		return chooseAttack(s)
	}
}

func shouldRest(s game.State) bool {

	canRecoverOnCoward := hasTrait(s, game.TraitCoward) && s.Creep.IsFull() && s.Avatar.HP < s.Avatar.MaxHP-3

	whileStunned := s.Creep.Stun == 2

	return (canRecoverOnCoward || whileStunned) && s.Avatar.MP >= 14
}

func chooseAttack(s game.State) game.CardType {
	if s.Creep.HP <= 2 {
		return game.CardAttack
	}
	switch {
	case s.Creep.Type == game.CreepKubus:
		return fightKubus(s)
	case s.Creep.Type == game.CreepDragon:
		return fightDragon(s)

	// for mummies
	case hasTrait(s, game.TraitWeakToFire) &&
		!hasTrait(s, game.TraitMagicImmunity) &&
		s.Creep.HP >= 3 &&
		s.Can(game.CardFirebolt):
		return game.CardFirebolt

	case s.Can(game.CardParry) &&
		!hasTrait(s, game.TraitRanged) &&
		((s.Creep.Damage.Low() > 2 && s.Creep.Damage.High() > 4) || s.Avatar.HP < 10):
		return game.CardParry

	case s.Can(game.CardStun) &&
		!s.Creep.IsStunned():
		return game.CardStun

	case s.Can(game.CardPowerAttack):
		return game.CardPowerAttack

	// case s.Can(game.CardMagicArrow) &&
	// 	hasTrait(s, game.TraitMagicAura) &&
	// 	!hasTrait(s, game.TraitMagicImmunity) &&
	// 	s.Avatar.MP >= 16:
	// 	return game.CardMagicArrow

	default:
		return game.CardAttack
	}
}

func fightKubus(s game.State) game.CardType {
	if s.Creep.IsFull() {
		if s.Avatar.HP <= 30 {
			return game.CardRetreat
		}
		// fight or flight
	}
	switch {
	case s.Creep.Damage.Low() >= 5 && s.Can(game.CardParry):
		return game.CardParry
	case canStun(s):
		return game.CardStun
	case s.Can(game.CardPowerAttack):
		return game.CardPowerAttack
	default:
		return game.CardAttack
	}
}

func canStun(s game.State) bool {
	return s.Can(game.CardStun) && !s.Creep.IsStunned()
}

func hasTrait(s game.State, trait game.CreepTrait) bool {
	return s.Creep.Traits.Has(trait)
}

func fightDragon(s game.State) game.CardType {
	switch {
	case s.Can(game.CardParry):
		return game.CardParry
	case canStun(s):
		return game.CardStun
	case s.Can(game.CardHeal):
		return game.CardHeal
	case s.Can(game.CardPowerAttack):
		return game.CardPowerAttack
	default:
		return game.CardAttack
	}
}