//
// Created by Dan Crosby on 6/19/23.
//

#ifndef EAGLE0_SHARDOK_AI_AI_ATTACK_GROUPS_HPP
#define EAGLE0_SHARDOK_AI_AI_ATTACK_GROUPS_HPP

#include <functional>
#include <vector>

#include "src/main/cpp/net/eagle0/shardok/ai/AIAttackLocations.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/ActionPointDistancesCache.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/CoordsSet.hpp"
#include "src/main/flatbuffer/net/eagle0/shardok/storage/game_state.hpp"
#include "src/main/flatbuffer/net/eagle0/shardok/storage/player_info.hpp"
#include "src/main/flatbuffer/net/eagle0/shardok/storage/unit.hpp"

namespace shardok {

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

using BattalionTypeGetter = std::function<BattalionTypeSPtr(BattalionTypeId)>;

struct TargetAndAttackLocations {
    Coords target;
    CoordsSet attackLocations;

    [[nodiscard]] auto operator==(const TargetAndAttackLocations& rhs) const -> bool = default;
};

struct TargetPriorityList {
    UnitId attackingUnitId;
    std::vector<TargetAndAttackLocations> priorityOrder;

    TargetPriorityList(const UnitId uid, const std::vector<TargetAndAttackLocations>& po)
        : attackingUnitId(uid),
          priorityOrder(po) {}
};

[[nodiscard]] auto EffectiveDistance(
        const Unit* unit,
        const HexMap* map,
        const AttackLocations& attackLocations,
        const APDCache& apdCache,
        const BattalionTypeGetter& battalionTypeGetter,
        ActionPoints braveWaterCost) -> DIST_T;

[[nodiscard]] auto EffectiveDistance(
        const Unit* unit,
        const HexMap* map,
        const CoordsSet& locations,
        const APDCache& apdCache,
        const BattalionTypeGetter& battalionTypeGetter,
        ActionPoints braveWaterCost) -> DIST_T;

[[nodiscard]] auto EffectiveDistance(
        const Unit* unit,
        const ActionPointDistances* notBravingApd,
        const ActionPointDistances* bravingApd,
        const CoordsSet& locations) -> DIST_T;

// Chooses a list of targets in priority order for each unit.
[[nodiscard]] auto GenerateTargetPriorities(
        const std::vector<const Unit*>& occupants,
        const HexMap* map,
        const CoordsSet& targets,
        PlayerId attackerId,
        const std::vector<const Unit*>& remainingUnits,
        const APDCache& apdCache,
        const ALCache& alCache,
        const BattalionTypeGetter& battalionTypeGetter,
        ActionPoints braveWaterCost,
        bool isLateGame = false) -> std::vector<TargetPriorityList>;

}  // namespace shardok

#endif  // EAGLE0_SHARDOK_AI_AI_ATTACK_GROUPS_HPP
