#pragma once

#include <string>

#include "adapters/eft/esp/EspLootScanner.h"
#include "adapters/eft/esp/EspNavigationScanner.h"
#include "adapters/eft/esp/EspPlayerScanner.h"
#include "features/esp/contracts/EspTypes.h"

#include "adapters/eft/common/PlayerWorldReader.h"
#include "adapters/eft/world/WorldAccess.h"
#include "features/items/contracts/WishlistSnapshot.h"

namespace ta::adapters::eft::esp
{
class EspWorldScanner
{
public:
    void update_world(const Il2CppClass* game_world_class,
                      ta::adapters::il2cpp::Il2CppObjectInstance game_world_instance,
                      ta::adapters::il2cpp::Il2CppObjectInstance main_player,
                      const ta::features::esp::EspSettingsSnapshot& settings,
                      const ta::features::items::contracts::WishlistSnapshot& wishlist,
                      ta::features::esp::EspWorldSnapshot& snapshot,
                      bool refresh_local_position,
                      bool refresh_players,
                      bool refresh_dynamic,
                      bool refresh_exfil_status,
                      bool refresh_static)
    {
        (void)game_world_class;

        if (refresh_local_position)
            update_local_position(main_player, snapshot);

        Il2CppObject* main_profile = ta::adapters::eft::common::get_profile(main_player.get_instance());
        const std::string main_nickname = ta::adapters::eft::common::get_profile_nickname(main_profile);

        if (refresh_static)
        {
            snapshot.exfils = settings.extracts_enabled
                ? EspNavigationScanner::scan_exfils(game_world_instance, main_profile)
                : std::vector<ta::features::esp::EspExfil>{};
            snapshot.transits = settings.transits_enabled
                ? EspNavigationScanner::scan_transits(game_world_instance)
                : std::vector<ta::features::esp::EspTransit>{};
        }
        else
        {
            if (refresh_exfil_status)
            {
                snapshot.exfils = settings.extracts_enabled
                    ? EspNavigationScanner::scan_exfils(game_world_instance, main_profile)
                    : std::vector<ta::features::esp::EspExfil>{};
            }
            else if (!settings.extracts_enabled)
            {
                snapshot.exfils.clear();
            }

            if (!settings.transits_enabled)
                snapshot.transits.clear();
        }

        if (refresh_players)
        {
            snapshot.players = settings.scan_players()
                ? EspPlayerScanner::scan_players(game_world_instance, main_nickname)
                : std::vector<ta::features::esp::EspPlayer>{};
        }
        else if (!settings.scan_players())
        {
            snapshot.players.clear();
        }

        loot_scanner_.update_loot(
            game_world_instance,
            settings,
            wishlist,
            snapshot,
            refresh_dynamic,
            refresh_static);
    }

    void clear_caches() noexcept
    {
        loot_scanner_.clear_caches();
    }

private:
    EspLootScanner loot_scanner_;

    static void update_local_position(ta::adapters::il2cpp::Il2CppObjectInstance main_player, ta::features::esp::EspWorldSnapshot& snapshot)
    {
        ta::adapters::unity::vector3 position = {};
        if (ta::adapters::eft::common::get_component_position(main_player.get_instance(), position))
            snapshot.local_position = position;
    }
};
}
