#include "memory/offset_registry.hpp"

namespace {

// Tên khóa chuẩn trong tệp registry (đồng bộ với tools/re_pipeline/)
constexpr const char* kKeyBuildStamp = "build_time_date_stamp";
constexpr const char* kKeyBuildLayoutHash = "build_section_layout_hash";
constexpr const char* kKeyEntityMapOffset = "entity_map_offset";
constexpr const char* kKeyPlayerOffset = "player_offset";
constexpr const char* kKeyStatOffset = "stat_offset";
constexpr const char* kKeyPosOffset = "pos_offset";
constexpr const char* kPrefixStaticRoot = "static_root_";
constexpr const char* kPrefixAobPattern = "aob_pattern_";
constexpr const char* kPrefixAobRipOffset = "aob_rip_offset_";

// Giới hạn cứng để tránh vòng lặp vô hạn nếu tệp bị hỏng
constexpr int kMaxIndexedEntries = 256;

} // namespace

const char* OffsetRegistry::ToString(BuildMatch match) {
    switch (match) {
        case BuildMatch::NoRecord:        return "NoRecord";
        case BuildMatch::LiveUnavailable: return "LiveUnavailable";
        case BuildMatch::Match:           return "Match";
        case BuildMatch::StampMismatch:   return "StampMismatch";
        case BuildMatch::LayoutMismatch:  return "LayoutMismatch";
    }
    return "Unknown";
}

bool OffsetRegistry::Load(const std::string& tomlPath) {
    m_store = OffsetsStore{};
    m_path = tomlPath;
    m_loaded = false;
    m_buildStamp = 0;
    m_layoutHash = 0;
    m_entityMapOffset = 0;
    m_playerOffset = 0;
    m_statOffset = 0;
    m_posOffset = 0;

    if (!m_store.Load(tomlPath)) {
        return false;
    }
    m_loaded = true;

    m_buildStamp = static_cast<uint32_t>(m_store.Get(kKeyBuildStamp, 0));
    m_layoutHash = m_store.Get(kKeyBuildLayoutHash, 0);
    m_entityMapOffset = m_store.Get(kKeyEntityMapOffset, 0);
    m_playerOffset = m_store.Get(kKeyPlayerOffset, 0);
    m_statOffset = m_store.Get(kKeyStatOffset, 0);
    m_posOffset = m_store.Get(kKeyPosOffset, 0);

    return true;
}

OffsetRegistry::BuildMatch OffsetRegistry::CheckBuild(
    const pe_fingerprint::ClientBuildId& liveBuild) const {

    // Registry không có định danh build => không có bằng chứng => KHÔNG dùng được
    if (m_buildStamp == 0 && m_layoutHash == 0) {
        return BuildMatch::NoRecord;
    }
    if (!liveBuild.valid) {
        return BuildMatch::LiveUnavailable;
    }
    if (m_buildStamp != 0 && m_buildStamp != liveBuild.timeDateStamp) {
        return BuildMatch::StampMismatch;
    }
    if (m_layoutHash != 0 && m_layoutHash != liveBuild.SectionLayoutHash()) {
        return BuildMatch::LayoutMismatch;
    }
    return BuildMatch::Match;
}

std::vector<uintptr_t> OffsetRegistry::StaticRootCandidates() const {
    std::vector<uintptr_t> candidates;
    for (int index = 1; index <= kMaxIndexedEntries; ++index) {
        const std::string key = kPrefixStaticRoot + std::to_string(index);
        if (!m_store.Has(key)) {
            break;
        }
        const uintptr_t value = m_store.Get(key, 0);
        if (value != 0) {
            candidates.push_back(value);
        }
    }
    return candidates;
}

std::vector<std::string> OffsetRegistry::AobPatterns() const {
    std::vector<std::string> patterns;
    for (const auto& entry : AobEntries()) {
        patterns.push_back(entry.pattern);
    }
    return patterns;
}

std::vector<OffsetRegistry::AobEntry> OffsetRegistry::AobEntries() const {
    std::vector<AobEntry> entries;
    for (int index = 1; index <= kMaxIndexedEntries; ++index) {
        const std::string key = kPrefixAobPattern + std::to_string(index);
        if (!m_store.HasString(key)) {
            break;
        }
        const std::string value = m_store.GetString(key);
        if (value.empty()) {
            continue;
        }
        AobEntry entry;
        entry.index = index;
        entry.pattern = value;
        const std::string ripKey = kPrefixAobRipOffset + std::to_string(index);
        if (m_store.Has(ripKey)) {
            entry.ripOffset = static_cast<int>(m_store.Get(ripKey, 3));
        }
        entries.push_back(std::move(entry));
    }
    return entries;
}
