//
// Created by Dan Crosby on 2/16/21.
//

#include "IceAdjustmentAction.hpp"

#include <utility>

#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/TileModifierHelpers.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/TileModifier.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/TileModifierWithCoords.hpp"
#include "src/main/protobuf/net/eagle0/shardok/common/terrain.pb.h"

namespace shardok {

using TerrainProto = net::eagle0::shardok::common::Terrain;

IceAdjustmentAction::IceAdjustmentAction(
        const Coords coords,
        const Terrain* terrain,
        const double adjustment,
        std::shared_ptr<ShardokAction> fallAction,
        std::shared_ptr<ShardokAction> frozenAction)
    : coords(coords),
      terrain(*terrain),
      adjustment(adjustment),
      fallAction(std::move(fallAction)),
      frozenAction(std::move(frozenAction)) {}

auto effectiveIce(const Terrain& terr) -> double {
    if (terr.modifier().ice().present()) return terr.modifier().ice().integrity();
    return 0.0;
}

auto effectiveIce(const TerrainProto& terr) -> double {
    if (!terr.has_modifier()) return 0.0;
    if (!terr.modifier().has_ice()) return 0.0;
    if (!terr.modifier().ice().has_integrity()) return 0.0;
    return terr.modifier().ice().integrity().value();
}

auto IceAdjustmentAction::InternalExecute(
        const GameStateW& currentState,
        const std::shared_ptr<RandomGenerator>& generator) const -> vector<ActionResult> {
    vector<ActionResult> results{};

    TerrainProto newTerrain{};
    newTerrain.set_type(static_cast<net::eagle0::shardok::common::Terrain_Type>(terrain.type()));
    *newTerrain.mutable_modifier() = fb::ToTileModifierProto(terrain.modifier());

    MutatingAdjustIceIntegrity(newTerrain.mutable_modifier(), adjustment);
    if (effectiveIce(terrain) == effectiveIce(newTerrain)) return results;

    ActionResult resultProto;
    resultProto.set_type(net::eagle0::shardok::common::ICE_ADJUSTED);
    *resultProto.mutable_target_coords() = ToCoordsProto(coords);
    *resultProto.add_changed_tile_modifiers() = MakeTmc(coords, newTerrain.modifier());

    results.push_back(resultProto);

    if (terrain.modifier().ice().present() && !IsFrozen(newTerrain.modifier()) &&
        fallAction != nullptr) {
        auto fallResults = fallAction->Execute(currentState, generator);
        results.insert(std::end(results), std::begin(fallResults), std::end(fallResults));
    } else if (
            !terrain.modifier().ice().present() && IsFrozen(newTerrain.modifier()) &&
            frozenAction != nullptr) {
        auto frozenResults = frozenAction->Execute(currentState, generator);
        results.insert(std::end(results), std::begin(frozenResults), std::end(frozenResults));
    }

    return results;
}
}  // namespace shardok