//
// Created by Dan Crosby on 3/8/21.
//

#include "BuildBridgeCommandFactory.hpp"

#include "src/main/cpp/net/eagle0/shardok/library/commands/BuildBridgeCommand.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"

namespace shardok {

[[nodiscard]] auto GetBuildBridgeOdds(
        const SettingsGetter &settings,
        double strength,
        double agility,
        double intelligence,
        bool hasForestAccess) -> PercentileRollOdds;

void BuildBridgeCommandFactory::AddAvailableBuildBridgeCommands(
        CommandList &commands,
        const Unit *unit,
        const ActionPoints remainingActionPoints,
        const Coords &position,
        const HexMap *hexMap,
        const Units *units,
        const vector<PlayerId> &allyPids) const {
    const PlayerId playerId = unit->player_id();
    if (!unit->has_attached_hero()) return;
    const auto &hero = unit->attached_hero();

    if (const auto *currentTerrain = GetTerrain(hexMap, position);
        hero.profession_info().profession() ==
                net::eagle0::shardok::storage::fb::Profession_ENGINEER &&
        !IsWater(currentTerrain->type())) {
        const ActionCost cost =
                settings.ActionCostFor(settings.Backing().build_bridge_action_point_cost());

        if (cost.IsPossible(remainingActionPoints)) {
            const bool nearbyForest = HasForestAccess(position, units, hexMap, allyPids, playerId);

            for (const Coords &adjCoords : HexMapUtils::GetAdjacentCoords(hexMap, position)) {
                if (IsWater(GetTerrain(hexMap, adjCoords)->type()) &&
                    !GetTerrain(hexMap, adjCoords)->modifier().bridge().present()) {
                    commands.push_back(std::make_shared<BuildBridgeCommand>(
                            settings.ActionCostFor(
                                    settings.Backing().build_bridge_action_point_cost()),
                            unit->player_id(),
                            unit->unit_id(),
                            adjCoords,
                            *GetTerrain(hexMap, adjCoords),
                            nearbyForest,
                            settings.Backing().build_bridge_agility_xp(),
                            settings.Backing().build_bridge_strength_xp(),
                            settings.Backing().minimum_knowledge_for_profession()));
                }
            }
        }
    }
}
void BuildBridgeCommandFactory::AddAvailableCommands(
        CommandList &commands,
        const CommandParams &params) const {
    AddAvailableBuildBridgeCommands(
            commands,
            params.unit,
            params.remainingActionPoints,
            params.position,
            params.hexMap,
            params.units,
            params.allyPids);
}

auto GetBuildBridgeOdds(
        const SettingsGetter &settings,
        const double strength,
        const double agility,
        const double intelligence,
        const bool hasForestAccess) -> PercentileRollOdds {
    const int16_t base = settings.Backing().build_bridge_base_odds();
    constexpr int16_t terrainFactor = 0;
    constexpr int16_t weatherFactor = 0;
    constexpr int16_t windFactor = 0;
    const std::vector stats = {strength, agility, intelligence};
    std::vector<OtherFactor> otherFactors;
    if (hasForestAccess) {
        otherFactors.push_back(
                MakeOtherFactor(settings.Backing().build_bridge_forest_bonus(), "forest nearby"));
    }

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

}  // namespace shardok
