//
//  ReinforceCommandFactory.cpp
//  eagle0
//
//  Created by Dan Crosby on 12/30/19.
//  Copyright © 2019 none. All rights reserved.
//

#include "ReinforceCommandFactory.hpp"

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

namespace shardok {

auto ReinforceCommandFactory::MakeReinforceCommand(
        PlayerId playerId,
        UnitId actingUnitId,
        UnitId joiningUnitId,
        const Coords &position) const -> CommandSPtr {
    return std::make_shared<ReinforceCommand>(
            settings.ActionCostFor(settings.Backing().reinforce_action_point_cost()),
            playerId,
            actingUnitId,
            joiningUnitId,
            position);
}

auto ReinforceCommandFactory::AddAvailableReinforceCommands(
        CommandList &existingCommands,
        const Unit *reinforcingUnit,
        const ActionPoints remainingActionPoints,
        const HexMap *hexMap,
        const Units *units) const -> void {
    const ActionCost cost =
            settings.ActionCostFor(settings.Backing().reinforce_action_point_cost());
    if (!cost.IsPossible(remainingActionPoints)) return;

    int ownUnitCount = 0;
    for (const auto *checkUnit : *units) {
        if (checkUnit->status() == net::eagle0::shardok::storage::fb::UnitStatus_NORMAL_UNIT &&
            checkUnit->player_id() == reinforcingUnit->player_id() &&
            checkUnit->has_attached_hero())
            ownUnitCount++;
    }

    if (ownUnitCount >= 10) return;
    for (const Unit *reserveUnit : *units) {
        if (reserveUnit->status() != net::eagle0::shardok::storage::fb::UnitStatus_RESERVE_UNIT)
            continue;
        if (reserveUnit->player_id() != reinforcingUnit->player_id()) continue;

        const auto startingPositions =
                reserveUnit->starting_position_index() != -1
                        ? hexMap->attacker_starting_positions()
                                  ->Get(reserveUnit->starting_position_index())
                                  ->positions()
                        : hexMap->defender_starting_positions()->positions();

        for (const auto &position : *startingPositions) {
            const int positionIndex = position->row() * hexMap->column_count() + position->column();
            // Position must not be occupied and must not be on fire
            if (!Occupant(units, *position) &&
                !hexMap->terrain()->Get(positionIndex)->modifier().fire().present()) {
                existingCommands.push_back(MakeReinforceCommand(
                        reinforcingUnit->player_id(),
                        reinforcingUnit->unit_id(),
                        reserveUnit->unit_id(),
                        *position));
            }
        }
    }
}
void ReinforceCommandFactory::AddAvailableCommands(
        CommandList &commands,
        const CommandParams &params) const {
    AddAvailableReinforceCommands(
            commands,
            params.unit,
            params.remainingActionPoints,
            params.hexMap,
            params.units);
}

}  // namespace shardok
