#pragma once

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>

#include <cstdint>
#include <vector>

#include "memory/imemory_reader.hpp"

// ==========================================================
// PlayerFinder - Tự động định vị stat block nhân vật
// (Giai đoạn 2 - chiến lược "findplayer" đã verify thực địa)
//
// Pattern: triple u32 {currentHP, maxHP, maxHP} trong memory.
// maxHP là "dấu vân tay" ổn định theo nhân vật -> mỗi session
// chỉ cần: Scan(maxHP) -> user mất máu 1 lần -> Rescan(newHP)
// -> còn duy nhất 1 block = PlayerState.
// Backend-agnostic: chạy trên SIM (test) và RPM (thật).
// ==========================================================
class PlayerFinder {
public:
    explicit PlayerFinder(IMemoryReader& reader);

    // Lượt 1: quét toàn bộ region readable tìm {X ≤ maxHP, maxHP, maxHP}
    size_t Scan(uint32_t maxHP);

    // Lượt 2+: chỉ giữ các block có giá trị HP hiện tại == newHP
    size_t Rescan(uint32_t newHP);

    size_t CandidateCount() const { return m_candidates.size(); }
    const std::vector<uintptr_t>& Candidates() const { return m_candidates; }

    // Đọc HP + maxHP từ candidate đầu tiên còn đọc được
    bool ReadStats(uint32_t& outHP, uint32_t& outMaxHP) const;

    // Tự động tìm stat block HP của nhân vật quanh một địa chỉ (như xyz_addr) hoặc toàn vùng nhớ
    uintptr_t AutoScanHP(uintptr_t center = 0, size_t window = 16 * 1024 * 1024, uint32_t targetMaxHP = 0);

    // Bổ sung ExpectedMaxES từ Optical Sensor cho nhân vật CI
    void SetExpectedMaxES(uint32_t es) { m_expectedMaxES = es; }
    uint32_t ExpectedMaxES() const { return m_expectedMaxES; }

    // Multi-Vital pool candidates thu thập từ bộ nhớ trong một lần quét
    struct VitalCandidate {
        uintptr_t addr = 0;
        uint32_t cur = 0;
        uint32_t max = 0;
    };
    const std::vector<VitalCandidate>& ShieldCandidates() const { return m_shieldCandidates; }
    const std::vector<VitalCandidate>& ManaCandidates() const { return m_manaCandidates; }

    // ---- Float XYZ calibration ----
    // Quét float trong cửa sổ ±window/2 quanh center, lọc [fmin, fmax]
    size_t ScanFloats(uintptr_t center, size_t window, float fmin, float fmax);

    // Giữ float đã thay đổi ≥ minDelta (so với lần đọc trước)
    size_t FilterMoved(float minDelta);

    // Giữ float chưa thay đổi (< maxDelta)
    size_t FilterStill(float maxDelta);

    // Giữ lại các float thuộc triple liên tiếp (A, A+4, A+8) = nghi XYZ
    size_t FindXYZTriples();

    size_t TripleCount() const { return m_xyz.size(); }
    const std::vector<uintptr_t>& XYZAddresses() const { return m_xyz; }

    // ---- Entity Array discovery (đã verify thực địa 2026-09-06) ----
    struct EntityArrayInfo {
        uintptr_t slotAddr = 0;   // ô chứa entry của player trong array
        uintptr_t statOff = 0;    // khoảng cách từ entity base tới stat block
        int plausible = 0;        // số entry có HP hợp lệ
        int totalRead = 0;        // tổng entry non-null đọc được
        std::vector<std::pair<int, uintptr_t>> slots;  // (index, entity base)
        std::vector<std::pair<int, uint32_t>> hps;     // (index, HP)
    };

    // Tìm Entity Pointer Array: quét các ô chứa con trỏ trỏ vào player entity
    // object, rồi đi dọc mảng ±128 entry (stride 8) đếm HP hợp lệ tại cùng statOff.
    // Đã verify thực địa: statOff=0x3B8, player = entity[0], 22 entity sống.
    bool FindEntityArray(uintptr_t statAddr, EntityArrayInfo& out);

    // Đọc X/Y/Z từ triple đầu tiên còn đọc được
    bool ReadPosition(float& x, float& y, float& z) const;

    // Đọc X/Y/Z từ một địa chỉ cụ thể kèm kiểm tra IsValidXYZ
    bool ReadPositionAt(uintptr_t addr, float& x, float& y, float& z) const;

    // ---- XYZ Sanity & Validity Filters ----
    // Kiểm tra tính hợp lệ toán lý của bộ 3 tọa độ (loại bỏ vector tỷ lệ đồ họa 9.3, 9.3, 9.3 và vector 0)
    static bool IsValidXYZ(float x, float y, float z);

    // ---- Tự động phát hiện (không cần user canh thời gian) ----
    // Đợi user di chuyển: lấy mẫu 400ms/lần; khi ≥ minMatches float đổi ≥ minDelta
    // giữa 2 mẫu liên tiếp -> cập nhật m_floats và trả về số match. Hết giờ -> trả best.
    size_t WaitForMoved(float minDelta, int timeoutSec, size_t minMatches);

    // Đợi user đứng yên: khi số float thay đổi nhỏ trong `stableSamples` mẫu liên tiếp
    // -> lọc still và trả về số ứng viên còn lại
    size_t WaitForStable(float maxDelta, int stableSamples, int timeoutSec);

    // ---- Zero-User-Input Auto Scan (khi vừa tải xong map) ----
    // Chụp baseline float trong cửa sổ hẹp quanh center (mặc định 16MB)
    size_t SnapshotBaselineFloats(uintptr_t center, size_t window = 16 * 1024 * 1024);

    // Lọc các float đã di chuyển so với baseline (khi người chơi bước bước chân đầu tiên)
    size_t FindMovedFromBaseline(float minDelta = 0.8f, float maxDelta = 5000.0f);

private:
    IMemoryReader& m_reader;
    std::vector<uintptr_t> m_candidates;
    uint32_t m_maxHP = 0;
    uint32_t m_expectedMaxES = 0;
    std::vector<std::pair<uintptr_t, float>> m_floats;         // (addr, giá trị lần đọc trước)
    std::vector<std::pair<uintptr_t, float>> m_baselineFloats; // baseline float khi vừa tải màn hình (Grace Period)
    std::vector<uintptr_t> m_xyz;                              // địa chỉ float X (Y=X+4, Z=X+8)
    std::vector<VitalCandidate> m_shieldCandidates;
    std::vector<VitalCandidate> m_manaCandidates;
};