//
//  Hero.cpp
//  eagle0
//
//  Created by Dan Crosby on 11/18/14.
//  Copyright (c) 2014 none. All rights reserved.
//

#include "src/main/cpp/net/eagle0/shardok/library/unit/Hero.hpp"

namespace shardok {
#define HERO_DAMAGE_AMBUSH_ADJUSTMENT ((50.0))
#define HERO_BRAVERY_SWING ((25.0))
#define HERO_MORTALITY_FACTOR ((0.005))
#define MIN_VIGOR_NOT_DESTROYED 0.001

[[nodiscard]] auto IsDestroyed(const Hero &hero) -> bool {
    return hero.vigor() < MIN_VIGOR_NOT_DESTROYED;
}

inline auto factorIntoAdjustment(const double factorPercentile, const double swingPercentile)
        -> double {
    return 1.0 + ((factorPercentile - 50.0) * swingPercentile / 100.0) / 100.0;
}

void MutatingAdjustVigor(Hero *mutableHero, const double vigorDelta) {
    auto newVigor = mutableHero->vigor() + vigorDelta;
    if (newVigor < 0.0) newVigor = 0.0;
    if (newVigor > mutableHero->starting_vigor()) newVigor = mutableHero->starting_vigor();

    mutableHero->mutate_vigor(newVigor);
}

auto IsMage(const Hero &hero) -> bool {
    return hero.profession_info().profession() ==
           net::eagle0::shardok::storage::fb::Profession_MAGE;
}

auto MutatingTakeDamage(
        Hero *mutableHero,
        const CombatDamage &damage,
        const int battalionSize,
        const bool isAmbush) -> CombatDamage {
    const double braveryAdjustment =
            factorIntoAdjustment(mutableHero->bravery(), HERO_BRAVERY_SWING);

    double heroDamageRatio = braveryAdjustment / (battalionSize + 1);
    if (isAmbush) heroDamageRatio *= HERO_DAMAGE_AMBUSH_ADJUSTMENT;
    if (heroDamageRatio > 1.0) heroDamageRatio = 1.0;
    if (heroDamageRatio < 0.0) heroDamageRatio = 0.0;

    const CombatDamage heroDamage = heroDamageRatio * damage;

    double vigorHit = 0.0;
    for (int i = 0; i < NUM_DAMAGE_TYPES; i++) {
        vigorHit += heroDamage.GetNormalDamageOfType(DamageType(i)) * HERO_MORTALITY_FACTOR;
        vigorHit += heroDamage.GetPenetratingDamageOfType(DamageType(i)) * HERO_MORTALITY_FACTOR;
        // TODO: hero should have adjustments for damage types too
    }

    if (vigorHit > mutableHero->vigor()) vigorHit = mutableHero->vigor();

    MutatingAdjustVigor(mutableHero, -vigorHit);

    return (1.0 - heroDamageRatio) * damage;
}

}  // namespace shardok
