#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include "memory/offsets_store.hpp"
#include "memory/pe_fingerprint.hpp"

// ==========================================================
// OffsetRegistry - Sổ đăng ký tri thức Reverse Engineering
// (TASK-RE-PIPELINE-2026 / Invariant INV-BUILD-01)
//
// VAI TRÒ:
//   Là tầng nạp dữ liệu (data-driven) cho Thang Fallback 4 cấp của
//   PointerChainResolver. Toàn bộ tri thức RE (static root RVA, AOB pattern,
//   offset component) được đọc từ tệp TOML đã "build-keyed" thay vì hardcode
//   trong mã nguồn C++, nhờ đó một bản patch của client chỉ cần cập nhật dữ
//   liệu mà KHÔNG cần biên dịch lại Core Engine.
//
// INVARIANT INV-BUILD-01 (Build-Keyed Offset Knowledge):
//   Tri thức offset chỉ được phép sử dụng khi build fingerprint của client
//   đang chạy KHỚP với build fingerprint đã ghi trong registry.
//   Bằng chứng thực địa 10/09/2026: .data section dịch -0x1000 giữa hai build
//   (.text VSize 0x2E840BE -> 0x2E83B6E) đã làm 8 static root RVA hardcode
//   lệch hoàn toàn, khiến cả 4 AOB pattern [MISS] và player_addr = 0x0.
//   -> Không có bằng chứng khớp build => KHÔNG được dùng tri thức cũ.
//
// Xem: docs/development/25_static_reverse_engineering_pipeline_and_offset_registry.md
// ==========================================================
class OffsetRegistry {
public:
    // Kết quả đối chiếu build fingerprint (INV-BUILD-01)
    enum class BuildMatch {
        NoRecord,          // Registry chưa ghi build fingerprint nào
        LiveUnavailable,   // Không đọc được fingerprint của client đang chạy
        Match,             // KHỚP - được phép dùng tri thức
        StampMismatch,     // Lệch TimeDateStamp (client đã được build lại)
        LayoutMismatch     // Lệch bảng section (section đã dịch chuyển)
    };

    static const char* ToString(BuildMatch match);

    // Nạp registry từ tệp TOML (thường là bin/Release/offsets.toml
    // hoặc offsets_<BUILD_ID>.toml do pipeline PyGhidra sinh ra)
    bool Load(const std::string& tomlPath);

    bool Loaded() const { return m_loaded; }
    const std::string& Path() const { return m_path; }

    // Định danh build mà tri thức này thuộc về
    uint32_t BuildTimeDateStamp() const { return m_buildStamp; }
    uint64_t BuildSectionLayoutHash() const { return m_layoutHash; }

    // INV-BUILD-01: đối chiếu với client đang chạy
    BuildMatch CheckBuild(const pe_fingerprint::ClientBuildId& liveBuild) const;
    bool IsUsableFor(const pe_fingerprint::ClientBuildId& liveBuild) const {
        return CheckBuild(liveBuild) == BuildMatch::Match;
    }

    struct AobEntry {
        int index = 0;          // 1-based, khớp khóa aob_pattern_N
        std::string pattern;
        int ripOffset = 3;      // mặc định disp32 của `48 8B 05 ?? ?? ?? ??`
    };

    // Tri thức RE (chỉ có ý nghĩa khi IsUsableFor() == true)
    std::vector<uintptr_t> StaticRootCandidates() const;   // static_root_1..N
    std::vector<std::string> AobPatterns() const;          // aob_pattern_1..N
    std::vector<AobEntry> AobEntries() const;              // kèm aob_rip_offset_N
    uintptr_t EntityMapOffset() const { return m_entityMapOffset; }
    uintptr_t PlayerOffset() const { return m_playerOffset; }
    uintptr_t StatOffset() const { return m_statOffset; }
    uintptr_t PosOffset() const { return m_posOffset; }

    size_t EntryCount() const { return m_store.NumericCount() + m_store.StringCount(); }
    const OffsetsStore& Store() const { return m_store; }

private:
    OffsetsStore m_store;
    std::string m_path;
    bool m_loaded = false;

    uint32_t m_buildStamp = 0;
    uint64_t m_layoutHash = 0;

    uintptr_t m_entityMapOffset = 0;
    uintptr_t m_playerOffset = 0;
    uintptr_t m_statOffset = 0;
    uintptr_t m_posOffset = 0;
};
