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

#include "ChargeCommand.hpp"

#include "src/main/cpp/net/eagle0/shardok/library/map/Coordinates.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/unit/Unit.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/CombatUtils.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"

namespace shardok {
ChargeCommand::ChargeCommand(
        const ActionCost& cost,
        const SettingsGetter& settingsGetter,
        const PlayerId playerId,
        const UnitId attackerId,
        const UnitId defenderId,
        const Coords& defenderCoords,
        const AttackOrientation orientation)
    : ShardokCommand(playerId),
      cost(cost),
      settings(settingsGetter),
      attackerId(attackerId),
      defenderId(defenderId),
      defenderCoords(defenderCoords),
      attackOrientation(orientation) {}

auto ChargeCommand::InternalExecuteWithRoll(
        const GameStateW& currentState,
        const std::shared_ptr<RandomGenerator>& generator,
        const std::optional<int32_t> roll) const -> vector<ActionResult> {
    const auto attackerRoll = roll.value_or(generator->OpenEndedPercentile());
    const auto defenderRoll = generator->OpenEndedPercentile();
    return ExecuteWithRolls(currentState, attackerRoll, defenderRoll);
}

[[nodiscard]] auto ChargeCommand::ExecuteWithRolls(
        const GameStateW& currentState,
        double attackerRoll,
        double defenderRoll) const -> vector<ActionResult> {
    const Unit* attackerBefore = currentState->units()->Get(attackerId);
    const Unit* defenderBefore = currentState->units()->Get(defenderId);

    auto results = CombatUtils::InternalPerformMelee(
            cost,
            attackerBefore,
            defenderBefore,
            *GetTerrain(currentState->hex_map(), defenderCoords),
            attackOrientation,
            attackerRoll,
            defenderRoll,
            true /* isCharge */,
            false /* isAmbush */,
            settings);

    return vector<ActionResult>{CombatUtils::ChargeResult(results)};
}

auto ChargeCommand::GetCommandProto() const -> CommandProto {
    CommandProto proto{};

    proto.set_player(GetPlayerId());
    proto.set_type(net::eagle0::shardok::common::CHARGE_COMMAND);
    proto.mutable_actor()->set_value(attackerId);
    *proto.mutable_target() = ToCoordsProto(defenderCoords);
    proto.mutable_roll_request()->set_roll_type(
            net::eagle0::shardok::api::ROLL_TYPE_D100_OPEN_ENDED);
    proto.mutable_roll_request()->set_command_type(net::eagle0::shardok::common::CHARGE_COMMAND);
    proto.mutable_roll_request()->set_acting_unit_id(attackerId);

    return proto;
}
}  // namespace shardok
