//
//  MeleeCommandFactory.cpp
//  eagle0_engine
//
//  Created by Dan Crosby on 1/3/19.
//  Copyright © 2019 none. All rights reserved.
//

#include "src/main/cpp/net/eagle0/shardok/library/command_factories/melee_command_factory/MeleeCommandFactory.hpp"

#include "src/main/cpp/net/eagle0/shardok/library/command_factories/ambush_odds/AmbushOdds.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/commands/MeleeCommand.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/ZoneOfControlCalculator.hpp"

namespace shardok {
MeleeCommandFactory::MeleeCommandFactory(const SettingsGetter &getter) : settings(getter) {}

auto MeleeCommandFactory::MakeMeleeCommand(
        const Unit *attacker,
        const Unit *defender,
        const HexMap *hexMap) const -> CommandSPtr {
    PercentileRollOdds ambushOdds;
    if (attacker->hidden()) {
        if (attacker->has_attached_hero()) {
            const auto &hero = attacker->attached_hero();
            ambushOdds = AmbushOdds::GetAmbushOdds(
                    settings,
                    *GetTerrain(hexMap, defender->location()),
                    hero.agility(),
                    hero.wisdom());
        } else {
            const BattalionTypeSPtr &battalionType =
                    settings.GetBattalionType(attacker->battalion().type());
            ambushOdds = MakeOdds((int)battalionType->ambushOddsWithoutHero);
        }
    }

    return std::make_shared<MeleeCommand>(
            settings.ActionCostFor(settings.Backing().melee_action_point_cost()),
            settings,
            attacker->player_id(),
            attacker->unit_id(),
            defender->unit_id(),
            defender->location(),
            ambushOdds);
}

void MeleeCommandFactory::AddAvailableMeleeCommands(
        CommandList &commands,
        const Unit *unit,
        const ActionPoints remainingActionPoints,
        const Coords &position,
        const HexMap *hexMap,
        const Units *units,
        const vector<PlayerId> &allyPids) const {
    for (const Coords &adjCoords : HexMapUtils::GetAdjacentCoords(hexMap, position)) {
        const auto *enemyOccupant =
                KnownEnemyOccupant(unit->player_id(), units, allyPids, adjCoords);

        if (enemyOccupant) {
            ActionCost costForMelee =
                    settings.ActionCostFor(settings.Backing().melee_action_point_cost());
            if (costForMelee.IsPossible(remainingActionPoints)) {
                commands.push_back(MakeMeleeCommand(unit, enemyOccupant, hexMap));
            }
        }
    }
}
void MeleeCommandFactory::AddAvailableCommands(
        CommandList &commands,
        const CommandFactory::CommandParams &params) const {
    AddAvailableMeleeCommands(
            commands,
            params.unit,
            params.remainingActionPoints,
            params.position,
            params.hexMap,
            params.units,
            params.allyPids);
}

}  // namespace shardok
