#pragma once

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>

#include <array>
#include <cstdint>
#include <string>
#include <vector>

// ==========================================================
// pe_fingerprint - Định danh phiên bản client PathOfExile.exe
// ==========================================================

namespace pe_fingerprint {

struct SectionInfo {
    std::string name;
    uint32_t virtualAddress = 0;
    uint32_t virtualSize = 0;
    uint32_t rawSize = 0;
    uint32_t rawPointer = 0;
    uint32_t characteristics = 0;

    bool Executable() const { return (characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; }
    bool Writable() const { return (characteristics & IMAGE_SCN_MEM_WRITE) != 0; }
};

struct ClientBuildId {
    bool valid = false;
    uint16_t machine = 0;
    uint16_t numberOfSections = 0;
    uint32_t timeDateStamp = 0;
    uint32_t sizeOfImage = 0;
    uint32_t sizeOfHeaders = 0;
    uint64_t fileSize = 0;
    std::string path;
    std::vector<SectionInfo> sections;

    std::array<uint8_t, 32> fileSha256{};
    bool sha256Computed = false;

    std::string ShortId() const;
    uint64_t SectionLayoutHash() const;
    bool SameBuildAs(const ClientBuildId& other) const;
    const SectionInfo* FindSection(const std::string& sectionName) const;
};

class Sha256Context {
public:
    void Update(const uint8_t* data, size_t length);
    std::array<uint8_t, 32> Final();

private:
    void Transform(const uint8_t* block);

    uint32_t m_state[8] = {
        0x6a09e667u, 0xbb67ae85u, 0x3c6ef372u, 0xa54ff53au,
        0x510e527fu, 0x9b05688cu, 0x1f83d9abu, 0x5be0cd19u
    };
    uint8_t m_buffer[64] = {};
    size_t m_bufferLength = 0;
    uint64_t m_totalBytes = 0;
};

std::array<uint8_t, 32> Sha256(const uint8_t* data, size_t length);
bool Sha256File(const std::string& path, std::array<uint8_t, 32>& outHash);
std::string ToHex(const uint8_t* data, size_t length);
inline std::string ToHex(const std::array<uint8_t, 32>& hash) {
    return ToHex(hash.data(), hash.size());
}

bool LoadPeHeaders(const std::string& path, ClientBuildId& outBuild, std::string& outError);
bool LoadPeHeadersWithHash(const std::string& path, ClientBuildId& outBuild, std::string& outError);
bool LocatePoe2Executable(std::string& outPath);

} // namespace pe_fingerprint
