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

#include "DismissUnitCommand.hpp"

#include "src/main/cpp/net/eagle0/shardok/library/unit/Unit.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/ActionResultFlatbufferHelpers.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/view_filters/OddsFilter.hpp"

namespace shardok {

using net::eagle0::shardok::common::ActionType;

auto DismissUnitCommand::InternalExecute(
        const GameStateW& currentState,
        const std::shared_ptr<RandomGenerator>& generator) const -> vector<ActionResult> {
    const auto roll = generator->Percentile();
    return ExecuteWithRoll(currentState, roll);
}

[[nodiscard]] auto DismissUnitCommand::ExecuteWithRoll(const GameStateW& currentState, double roll)
        const -> vector<ActionResult> {
    auto controllingUnitAfter = *currentState->units()->Get(actingUnitId);
    controllingUnitAfter.mutate_remaining_action_points(0);
    controllingUnitAfter.mutable_attached_hero().mutable_control_info().mutate_controlled_unit_id(
            -1);

    auto dismissedUnitAfter = *currentState->units()->Get(dismissedUnitId);
    dismissedUnitAfter.mutate_commanding_unit_id(-1);
    dismissedUnitAfter.mutate_remaining_action_points(0);

    ActionResult result{};
    result.mutable_player()->set_value(GetPlayerId());
    result.mutable_actor()->set_value(actingUnitId);
    AddChangedUnit(result, controllingUnitAfter);
    result.mutable_target_unit()->set_value(dismissedUnitId);

    if (PercentileRollSucceeds(odds, roll)) {
        result.set_type(ActionType::DISMISS_UNIT);

        dismissedUnitAfter.mutable_battalion().mutate_size(0);
        dismissedUnitAfter.mutate_player_id(UNCONTROLLED_PLAYER_ID);
    } else {
        result.set_type(ActionType::FAILED_DISMISS_UNIT);

        dismissedUnitAfter.mutate_player_id(UNCONTROLLED_PLAYER_ID);
        dismissedUnitAfter.mutate_targeted_unit(controllingUnitAfter.unit_id());
    }

    AddChangedUnit(result, dismissedUnitAfter);
    return {result};
}

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

    proto.set_player(GetPlayerId());
    proto.set_type(net::eagle0::shardok::common::DISMISS_UNIT_COMMAND);
    proto.mutable_actor()->set_value(actingUnitId);
    *proto.mutable_odds() = OddsFilteredForPlayer(odds, GetPlayerId());
    proto.mutable_target_unit()->set_value(dismissedUnitId);

    return proto;
}

int32_t DismissUnitCommand::GetOddsPercentile() const {
    return OddsFilteredForPlayer(odds, GetPlayerId()).success_chance();
}

}  // namespace shardok
