#pragma once
#include <vector>
#include <unordered_map>
#include <chrono>

#include "Core/Models.h"
#include "Core/RuntimeSession.h"
#include "Memory/VmmAccessor.h"
#include "Readers/EntityTypeCache.h"

// -------------------------------------------------------------------------
// SlowEntityListReader
// Incremental reader for the world's slow-entity table.
// Entries use the SlowTable format: 0x18-byte slots, uint16_t flag at +0x0
// (valid == 1), entity pointer at +0x8.
// Processing stops early when validEntriesSeenInScan reaches safeValidCount.
// -------------------------------------------------------------------------

class SlowEntityListReader {
public:
    SlowEntityListReader(int batchSize    = 64,
                         int readBudgetMs = 5,
                         int staleAfterMs = 5000);

    /// Incrementally read slow entities into @p entries.
    /// Returns false only when the table pointer itself cannot be read.
    bool TryRead(VmmAccessor&                       mem,
                 const RuntimeSession&              session,
                 std::vector<DayZSlowEntityEntry>&  entries);

    /// Reset all state. Call when the game session restarts.
    void Reset();

private:
    // ------------------------------------------------------------------
    // Per-entity bookkeeping
    // ------------------------------------------------------------------
    struct CachedEntity {
        DayZSlowEntityEntry                    entry;
        int                                    lastSeenGeneration   = 0;
        std::chrono::steady_clock::time_point  lastSuccessfulRead;
        int                                    failedTypeReads      = 0;
    };

    // ------------------------------------------------------------------
    // Internal helpers
    // ------------------------------------------------------------------
    void ProcessEntity(VmmAccessor&             mem,
                       const RuntimeSession&    session,
                       uint64_t                 entityAddr,
                       std::chrono::steady_clock::time_point now);

    void CompleteScan(std::chrono::steady_clock::time_point now);

    void PruneExpiredEntities(std::chrono::steady_clock::time_point now);

    std::vector<DayZSlowEntityEntry>& BuildResult();

    void MarkTypeReadFailure(uint64_t                              entityAddr,
                             CachedEntity*                         cached,
                             std::chrono::steady_clock::time_point now);

    // ------------------------------------------------------------------
    // State
    // ------------------------------------------------------------------
    std::unordered_map<uint64_t, CachedEntity> m_entities;
    EntityTypeCache                            m_typeCache;
    std::vector<DayZSlowEntityEntry>           m_cachedResult;
    std::vector<uint64_t>                      m_sortedAddresses;

    int  m_cursorOffset           = 0;
    int  m_validEntriesSeenInScan = 0;
    int  m_scanGeneration         = 1;
    bool m_hasCompletedScan       = false;
    bool m_sortDirty              = true;
    bool m_resultDirty            = true;

    int                         m_batchSize;
    std::chrono::milliseconds   m_readBudget;
    std::chrono::milliseconds   m_staleAfter;

    // Minimum number of table entries to read per chunk (ensures we always
    // make meaningful progress even with a small batchSize).
    static constexpr int kMinTableChunkEntries = 256;
    static constexpr int kMaxEntities          = 4096;
};
