//
// Created by Dan Crosby on 5/17/20.
//

#include "LightningBoltCommandFactory.hpp"

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

namespace shardok {

auto CanLightningBolt(const SettingsGetter &settings, const Unit *unit) -> bool {
    if (!unit->has_attached_hero()) return false;
    return unit->attached_hero().profession_info().profession() ==
                   net::eagle0::shardok::storage::fb::Profession_MAGE &&
           settings.GetBattalionType(unit->battalion().type())->allowsCasting;
}

shardok::LightningBoltCommandFactory::LightningBoltCommandFactory(
        const shardok::SettingsGetter &getter)
    : settings(getter) {}

auto LightningBoltCommandFactory::MakeLightningBoltCommand(
        const Unit *attacker,
        const Unit *defender) const -> CommandSPtr {
    return std::make_shared<LightningBoltCommand>(
            settings,
            attacker->player_id(),
            attacker->unit_id(),
            defender->unit_id(),
            defender->location(),
            settings.Backing().lightning_bolt_damage_cap());
}

auto LightningBoltCommandFactory::AddAvailableLightningBoltCommands(
        CommandList &existingCommands,
        const Unit *unit,
        const ActionPoints remainingActionPoints,
        const Coords &position,
        const HexMap *hexMap,
        const Units *units,
        const vector<PlayerId> &allyPids) const -> void {
    if (!CanLightningBolt(settings, unit)) { return; }

    const ActionCost costForLightning =
            ActionCost::UsesAllActionCost(settings.Backing().lightning_action_point_cost());
    const int lightningRange = settings.Backing().lightning_range();
    if (costForLightning.IsPossible(remainingActionPoints)) {
        for (int distance = 1; distance <= lightningRange; distance++) {
            CoordsSet coords = TilesWithExactDistance(hexMap, position, distance);

            for (const Coords &lightningCoords : coords) {
                const auto &occupantOptional =
                        KnownEnemyOccupant(unit->player_id(), units, allyPids, lightningCoords);
                if (occupantOptional) {
                    existingCommands.emplace_back(MakeLightningBoltCommand(unit, occupantOptional));
                }
            }
        }
    }
}
void LightningBoltCommandFactory::AddAvailableCommands(
        CommandList &commands,
        const CommandFactory::CommandParams &params) const {
    AddAvailableLightningBoltCommands(
            commands,
            params.unit,
            params.remainingActionPoints,
            params.position,
            params.hexMap,
            params.units,
            params.allyPids);
}
}  // namespace shardok
