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

#include "RepairCommand.hpp"

#include "src/main/cpp/net/eagle0/shardok/library/actions/ActionRequiresHeroException.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/TileModifierHelpers.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/util/HexMapUtils.hpp"

namespace shardok {

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

auto RepairCommand::InternalExecute(
        const GameStateW& currentState,
        const std::shared_ptr<RandomGenerator>& generator) const -> vector<ActionResult> {
    const auto* actor = currentState->units()->Get(actorId);

    if (!actor->has_attached_hero()) { throw ActionRequiresHeroException("repair"); }

    auto actorAfter = *actor;
    MutatingSpendActionPoints(&actorAfter, cost);

    MutatingBumpAgilityXp(&actorAfter, agilityXp);
    MutatingBumpStrengthXp(&actorAfter, strengthXp);
    MutatingBumpAllKnowledgeToMinimum(&actorAfter, minimumKnowledge);

    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.set_type(REPAIR);

    TileModifierProto newTileModifier =
            fb::ToTileModifierProto(GetTerrain(currentState->hex_map(), target)->modifier());
    if (HasBridge(newTileModifier)) {
        SetBridge(newTileModifier, newTileModifier.bridge().integrity().value() + repairBuf);
    } else if (HasCastle(newTileModifier)) {
        SetCastle(newTileModifier, newTileModifier.castle().integrity().value() + repairBuf);
    }
    *result.add_changed_tile_modifiers() = MakeTmc(target, newTileModifier);

    return {result};
}

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

    proto.set_player(GetPlayerId());
    proto.set_type(net::eagle0::shardok::common::REPAIR_COMMAND);
    proto.mutable_actor()->set_value(actorId);
    *proto.mutable_target() = ToCoordsProto(target);

    return proto;
}
}  // namespace shardok
