//
// Created by Dan Crosby on 1/5/22.
//

#include "AIWaterCrossingCommandChooser.hpp"

#include "src/main/cpp/net/eagle0/shardok/ai/AIWaterCrossingCalculator.hpp"

namespace shardok {

using Unit = net::eagle0::shardok::storage::fb::Unit;

auto AIWaterCrossingCommandChooser::StartCrossingFrom(
        const BattalionTypeGetter &battalionTypeGetter,
        const GameStateW &gameState,
        const CoordsSet &castleCoords) const -> CoordsSet {
    CoordsSet startCrossingFrom(gameState->hex_map());

    uint32_t castleClaimCount = 0;
    for (const auto *unit : *gameState->units()) {
        if (unit->player_id() != playerId) continue;
        const auto status = unit->status();
        if (status != net::eagle0::shardok::storage::fb::UnitStatus_NORMAL_UNIT &&
            status != net::eagle0::shardok::storage::fb::UnitStatus_RESERVE_UNIT)
            continue;
        if (!unit->has_attached_hero()) continue;

        ++castleClaimCount;
    }

    CoordsSet destinations = castleCoords;
    if (castleClaimCount < castleCoords.size()) {
        destinations = CoordsSet(gameState->hex_map());
        for (const auto *enemyUnit : *gameState->units()) {
            if (enemyUnit->player_id() == playerId) continue;
            const auto status = enemyUnit->status();
            if (status != net::eagle0::shardok::storage::fb::UnitStatus_NORMAL_UNIT) continue;
            AssertValid(enemyUnit->location(), gameState->hex_map());
            destinations.Add(enemyUnit->location());
        }
    }

    const auto unitIdsRequiringCrossing = UnitIdsRequiringWaterCrossing(
            gameState,
            playerId,
            castleCoords,
            apdCache,
            battalionTypeGetter);
    if (unitIdsRequiringCrossing.empty()) return startCrossingFrom;

    const auto unitIdsCreatingCrossing =
            UnitIdsToCreateWaterCrossing(gameState, playerId, battalionTypeGetter);

    for (const UnitId uid : unitIdsRequiringCrossing) {
        const Unit *unit = gameState->units()->Get(uid);
        const auto &battalionType = battalionTypeGetter(unit->battalion().type());
        Coords origin = unit->location();

        // FIXME: this is just grabbing the first starting position, ideally we'd try them all
        if (origin.row() < 0) {
            origin = *gameState->hex_map()
                              ->attacker_starting_positions()
                              ->Get(unit->starting_position_index())
                              ->positions()
                              ->Get(0);
        }

        if (!destinations.empty()) {
            Coords destination = *destinations.begin();
            AssertValid(destination, gameState->hex_map());

            auto frozenWaterCrossingTiles = FrozenWaterCrossingTiles(
                    origin,
                    destination,
                    gameState->hex_map(),
                    apdCache,
                    battalionType);
            startCrossingFrom +=
                    CrossingStartLocations(gameState->hex_map(), frozenWaterCrossingTiles);

            if (unitIdsCreatingCrossing.empty()) continue;

            auto waterCrossingTiles = WaterCrossingTiles(
                    origin,
                    destination,
                    gameState->hex_map(),
                    apdCache,
                    battalionType);
            // FIXME: this isn't really the right calculation, this will get anything that works
            // for any one unit
            startCrossingFrom += CrossingStartLocations(gameState->hex_map(), waterCrossingTiles);
        }
    }

    return startCrossingFrom;
}

}  // namespace shardok
