//
//  FireManager.cpp
//  eagle0
//
//  Created by Dan Crosby on 3/14/18.
//  Copyright © 2018 none. All rights reserved.
//

#include "FireUtils.hpp"

#include "src/main/cpp/net/eagle0/shardok/library/map/TileModifier.hpp"

namespace shardok {
constexpr double BASE_FIRE_DAMAGE_PER_TROOP = 112.5;
constexpr double BASE_PENETRATING_FIRE_DAMAGE_PER_TROOP = 175.0;
constexpr double RANDOMNESS_FACTOR = 0.3;

auto PropensityByTerrain(const Terrain *terrain, const SettingsGetter &settings) -> int {
    if (terrain->modifier().castle().present()) {
        return settings.Backing().fire_propensity_castle();
    } else if (terrain->modifier().bridge().present()) {
        return settings.Backing().fire_propensity_bridge();
    } else if (terrain->modifier().ice().present()) {
        return settings.Backing().fire_propensity_ice();
    }

    return settings.GetFirePropensityByTerrainType(static_cast<TerrainType>(terrain->type()));
}

auto PropensityByTerrain(const TerrainProto &terrain, const SettingsGetter &settings) -> int {
    if (HasCastle(terrain.modifier())) {
        return settings.Backing().fire_propensity_castle();
    } else if (HasBridge(terrain.modifier())) {
        return settings.Backing().fire_propensity_bridge();
    } else if (IsFrozen(terrain.modifier())) {
        return settings.Backing().fire_propensity_ice();
    }

    return settings.GetFirePropensityByTerrainType(terrain.type());
}

auto PropensityByTerrain(
        const TerrainType &terrainType,
        const TileModifierProto &modifier,
        const SettingsGetter &settings) -> int {
    if (modifier.has_castle()) {
        return settings.Backing().fire_propensity_castle();
    } else if (modifier.has_bridge()) {
        return settings.Backing().fire_propensity_bridge();
    } else if (modifier.has_ice()) {
        return settings.Backing().fire_propensity_ice();
    }

    return settings.GetFirePropensityByTerrainType(terrainType);
}

auto PropensityByTerrain(const SettingsGetter &settings, const TerrainProto &terrain) -> int {
    if (HasCastle(terrain.modifier())) {
        return settings.Backing().fire_propensity_castle();
    } else if (HasBridge(terrain.modifier())) {
        return settings.Backing().fire_propensity_bridge();
    } else if (IsFrozen(terrain.modifier())) {
        return settings.Backing().fire_propensity_ice();
    }

    return settings.GetFirePropensityByTerrainType(terrain.type());
}

auto GetFireDamage(
        const int troops,
        const double openEndedPercentileRoll1,
        const double openEndedPercentileRoll2) -> CombatDamage {
    double randomSwing = 1.0 + (2 * openEndedPercentileRoll1 - 100.0) * RANDOMNESS_FACTOR / 100.0;
    const double basicDamage = BASE_FIRE_DAMAGE_PER_TROOP * randomSwing * troops;

    randomSwing = 1.0 + (2 * openEndedPercentileRoll2 - 100.0) * RANDOMNESS_FACTOR / 100.0;
    const double penetratingDamage = BASE_PENETRATING_FIRE_DAMAGE_PER_TROOP * randomSwing * troops;

    return CombatDamage::Builder()
            .SetFire(basicDamage)
            .SetPenetratingFire(penetratingDamage)
            .Build();
}

auto GetExtinguishOdds(
        const SettingsGetter &settings,
        const Terrain *terrain,
        const WeatherFb *weather,
        const double agility,
        const double intelligence,
        const bool ownTile) -> PercentileRollOdds {
    const int16_t base = settings.Backing().extinguish_base_odds();

    const int16_t terrainFactor = -PropensityByTerrain(terrain, settings);

    const int16_t weatherFactor =
            -settings.GetFirePropensityByWeatherConditions(weather->conditions());

    const int16_t windFactor = -weather->wind().speed_in_mph();

    std::vector<OtherFactor> others;
    if (ownTile) {
        others.push_back(MakeOtherFactor(settings.Backing().extinguish_own_tile_buf(), "ownTile"));
    }

    const std::vector<double> stats = {agility, agility, intelligence};

    return MakeOdds(base, terrainFactor, weatherFactor, windFactor, stats, others);
}

auto GetStartFireOdds(
        const SettingsGetter &settings,
        const Terrain &terrain,
        const WeatherFb &currentWeather,
        const double agility,
        const double intelligence,
        const bool isMage) -> PercentileRollOdds {
    const int16_t base = settings.Backing().start_fire_base_odds();

    const int16_t terrainFactor = PropensityByTerrain(&terrain, settings);
    const int16_t weatherFactor =
            settings.GetFirePropensityByWeatherConditions(currentWeather.conditions());

    const int16_t windFactor = -currentWeather.wind().speed_in_mph();

    std::vector<OtherFactor> otherFactors;
    if (isMage) { otherFactors.push_back(MakeOtherFactor(+20, "mage")); }

    const std::vector<double> stats = {agility, intelligence, intelligence};

    return MakeOdds(base, terrainFactor, weatherFactor, windFactor, stats, otherFactors);
}

}  // namespace shardok
