#pragma once
#include "stdafx.h"

#define NOMINMAX

#include <unordered_map>
#include <vector>
#include <utility>
#include <Exam_HelperStructs.h>
#include <IExamInterface.h>

class WorldExplorationGrid {
public:
    WorldExplorationGrid(float cellSize = 35);

    void Update(const AgentInfo& agentInfo, const std::vector<HouseInfo>& visibleHouses);

    Elite::Vector2 FindNearestUnexplored(const Elite::Vector2& fromPosition);
    Elite::Vector2 FindUnexploredInHouse(const Elite::Vector2& fromPosition, const HouseInfo& house) const;

    bool IsExplored(const Elite::Vector2& position) const;
    float GetExploredPercentage() const;
    float GetHouseExploredPercentage(const HouseInfo& house) const;

    void Reset();
    void SetCellSize(float newCellSize);
    float GetCellSize() const { return m_CellSize; }

    void SetWorldInfo(const WorldInfo& info);
	void SetInterfacePtr(IExamInterface* pInterface) { m_pRenderer = pInterface; }

    void RenderDebug();



private:
    IExamInterface* m_pRenderer{ nullptr };
    float m_CellSize;
    WorldInfo m_WorldInfo{};
    int m_MaxSearchRadius = 100;


    struct GridCoords {
        int x, y;
        bool operator==(const GridCoords& other) const {
            return x == other.x && y == other.y;
        }
    };

    struct GridHash {
        size_t operator()(const GridCoords& coords) const {
            return static_cast<size_t>(coords.x) << 32 | coords.y;
        }
    };

    struct GridCoordsHash {
        size_t operator()(const GridCoords& coords) const {
            return std::hash<int>()(coords.x) ^ (std::hash<int>()(coords.y) << 1);
        }
    };

    WorldExplorationGrid::GridCoords ClampToWorldBounds(const GridCoords& coords) const {
        int gridWidth = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.x / m_CellSize));
        int gridHeight = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.y / m_CellSize));

        return {
            std::clamp(coords.x, 0, gridWidth - 1),
            std::clamp(coords.y, 0, gridHeight - 1)
        };
    }
    std::unordered_map<GridCoords, bool, GridHash> m_ExploredGrid;

    GridCoords WorldToGrid(const Elite::Vector2& pos) const;
    Elite::Vector2 GridToWorld(const GridCoords& gridCoords) const;
    void MarkExplored(const std::vector<GridCoords>& cells);
    std::vector<GridCoords> GetCellsInRadius(const Elite::Vector2& center, float radius) const;
    std::vector<GridCoords> GetCellsInRect(const Elite::Vector2& center, const Elite::Vector2& size) const;
    int CountExploredNeighbors(const GridCoords& coords) const;

    GridCoords m_LastUnexploredCell = { 0,0 };
};