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

#include "StartFireCommand.hpp"

#include "src/main/cpp/net/eagle0/shardok/library/actions/ActionRequiresHeroException.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/TileModifierWithCoords.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 {

StartFireCommand::StartFireCommand(
        const SettingsGetter& getter,
        const Unit* actor,
        Coords target,
        Terrain targetTerrain,
        PercentileRollOdds odds)
    : ShardokCommand(actor->player_id()),
      settings(getter),
      actor(actor),
      target(target),
      targetTerrain(std::move(targetTerrain)),
      odds(std::move(odds)){};

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

[[nodiscard]] auto StartFireCommand::ExecuteWithRoll(double roll) const -> vector<ActionResult> {
    if (!actor->has_attached_hero()) { throw ActionRequiresHeroException("start fire"); }

    auto actorAfter = *actor;

    MutatingSpendActionPoints(
            &actorAfter,
            ActionCost::UsesAllActionCost(settings.Backing().start_fire_action_point_cost()));
    MutatingBumpWisdomXp(&actorAfter, settings.Backing().start_fire_wisdom_xp());
    MutatingBumpAgilityXp(&actorAfter, settings.Backing().start_fire_agility_xp());

    actorAfter.mutate_hidden(false);

    ActionResult result{};
    result.mutable_player()->set_value(GetPlayerId());
    result.mutable_actor()->set_value(actorAfter.unit_id());
    *result.mutable_target_coords() = ToCoordsProto(target);
    AddChangedUnit(result, actorAfter);
    result.mutable_roll()->set_value(roll);
    *result.mutable_odds() = odds;

    if (PercentileRollSucceeds(odds, roll)) {
        auto newTileModifier = targetTerrain.modifier();
        newTileModifier.mutable_fire().mutate_present(true);

        result.set_type(net::eagle0::shardok::common::START_FIRE);
        *result.add_changed_tile_modifiers() = MakeTmc(target, newTileModifier);
    } else {
        result.set_type(net::eagle0::shardok::common::START_FIRE_FAILED);
    }

    return {result};
}

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

    proto.set_player(GetPlayerId());
    proto.set_type(net::eagle0::shardok::common::START_FIRE_COMMAND);
    proto.mutable_actor()->set_value(actor->unit_id());
    *proto.mutable_target() = ToCoordsProto(target);
    *proto.mutable_odds() = OddsFilteredForPlayer(odds, GetPlayerId());

    return proto;
}

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

}  // namespace shardok
