#pragma once
#include <cstdint>
#include "../../../templeware/utils/math/vector/vector.h"

#pragma pack(push, 1)
// --- Протобуферные структуры для сабтиков (CS2) ---

struct CCmdQAnglePB {
    QAngle_t angValue;
};

struct CCmdVectorPB {
    Vector4D_t vecValue;
};

struct CBasePB_CS2 {
    void* vtable;
    uint32_t nHasBits;
    uint64_t nCachedBits;
};

struct CInButtonStatePB_CS2 : CBasePB_CS2 {
    uint64_t nValue;
    uint64_t nValueChanged;
    uint64_t nValueScroll;
};

struct CSubtickMoveStepPB_CS2 : CBasePB_CS2 {
    uint64_t nButton;
    bool bPressed;
    float flWhen;
    float flAnalogForwardDelta;
    float flAnalogLeftDelta;
};

struct CCSGOInterpolationInfoPB_CS2 : CBasePB_CS2 {
    float flFraction;
    int nSrcTick;
    int nDstTick;
};

struct CMsgQAnglePB_CS2 { QAngle_t angValue; };
struct CMsgVectorPB_CS2 { Vector4D_t vecValue; };

struct CCSGOInputHistoryEntryPB_CS2 {
    CMsgQAnglePB_CS2* pViewAngles;
    CMsgVectorPB_CS2* pShootPosition;
    CMsgVectorPB_CS2* pTargetHeadPositionCheck;
    CMsgVectorPB_CS2* pTargetAbsPositionCheck;
    CMsgQAnglePB_CS2* pTargetAngPositionCheck;
    CCSGOInterpolationInfoPB_CS2* cl_interp;
    CCSGOInterpolationInfoPB_CS2* sv_interp0;
    CCSGOInterpolationInfoPB_CS2* sv_interp1;
    CCSGOInterpolationInfoPB_CS2* player_interp;
    int nRenderTickCount;
    float flRenderTickFraction;
    int nPlayerTickCount;
    float flPlayerTickFraction;
    int nFrameNumber;
    int nTargetEntIndex;
};

template <typename T>
struct RepeatedPtrFieldPB_CS2 {
    struct Rep_t {
        int nAllocatedSize;
        T* tElements[128];
    };
    void* pArena;      // 0x0 (8 байт)
    int nCurrentSize;  // 0x8 (4 байта)
    int nTotalSize;    // 0xC (4 байта)
    Rep_t* pRep;       // 0x10 (8 байт)
    // 0x18
};
static_assert(sizeof(RepeatedPtrFieldPB_CS2<int>) == 0x18, "RepeatedPtrFieldPB_CS2 size mismatch!");

struct CBaseUserCmdPB_CS2 {
    RepeatedPtrFieldPB_CS2<int> subtickMovesField; // 0x0 (0x18)
    void* strMoveCrc; // 0x18
    void* pInButtonState; // 0x20
    CMsgQAnglePB_CS2* pViewAngles; // 0x28
    int32_t nLegacyCommandNumber; // 0x30
    int32_t nClientTick; // 0x34
    float flForwardMove; // 0x38
    float flSideMove; // 0x3C
    float flUpMove; // 0x40
    int32_t nImpulse; // 0x44
    int32_t nWeaponSelect; // 0x48
    int32_t nRandomSeed; // 0x4C
    int32_t nMousedX; // 0x50
    int32_t nMousedY; // 0x54
    uint32_t nConsumedServerAngleChanges; // 0x58
    int32_t nCmdFlags; // 0x5C
    uint32_t nPawnEntityHandle; // 0x60
    char pad[0x80 - 0x64]; // паддинг до 0x80
};
static_assert(sizeof(CBaseUserCmdPB_CS2) == 0x80, "CBaseUserCmdPB_CS2 size mismatch!");

struct CCSGOUserCmdPB_CS2 {
    uint32_t nHasBits; // 0x0
    uint64_t nCachedSize; // 0x8
    RepeatedPtrFieldPB_CS2<CCSGOInputHistoryEntryPB_CS2> inputHistoryField; // 0x10 (0x18)
    CBaseUserCmdPB_CS2* pBaseCmd; // 0x28
    bool bLeftHandDesired; // 0x30
    char pad1[3]; // 0x31-0x33
    int32_t nAttack3StartHistoryIndex; // 0x34
    int32_t nAttack1StartHistoryIndex; // 0x38
    int32_t nAttack2StartHistoryIndex; // 0x3C
    char pad2[4]; // 0x40-0x43 (чтобы размер стал 0x40)
};
static_assert(sizeof(CCSGOUserCmdPB_CS2) == 0x40, "CCSGOUserCmdPB_CS2 size mismatch!");

struct CInButtonState_CS2 {
    void* vtable; // 0x0
    uint64_t nValue; // 0x8
    uint64_t nValueChanged; // 0x10
    uint64_t nValueScroll; // 0x18
};
static_assert(sizeof(CInButtonState_CS2) == 0x20, "CInButtonState_CS2 size mismatch!");

class CUserCmd {
public:
    char pad_0x00[0x8]; // 0x0
    char pad_0x08[0x10]; // 0x8
    CCSGOUserCmdPB_CS2 csgoUserCmd; // 0x18
    CInButtonState_CS2 nButtons; // 0x58
    char pad_0x78[0x20]; // 0x78

    CCSGOInputHistoryEntryPB_CS2* GetInputHistoryEntry(int nIndex) {
        if (!csgoUserCmd.inputHistoryField.pRep) return nullptr;
        if (nIndex < 0 || nIndex >= csgoUserCmd.inputHistoryField.nCurrentSize) return nullptr;
        return csgoUserCmd.inputHistoryField.pRep->tElements[nIndex];
    }

    void SetSubTickAngle(const QAngle_t& angView) {
        if (!csgoUserCmd.inputHistoryField.pRep) return;
        for (int i = 0; i < csgoUserCmd.inputHistoryField.nCurrentSize; ++i) {
            CCSGOInputHistoryEntryPB_CS2* pInputEntry = GetInputHistoryEntry(i);
            if (!pInputEntry || !pInputEntry->pViewAngles) continue;
            pInputEntry->pViewAngles->angValue = angView;
        }
    }
};
static_assert(sizeof(CUserCmd) == 0x98, "CUserCmd size mismatch! Проверь паддинг и порядок полей.");

// static_assert(sizeof(CUserCmd) == 0x98, "CUserCmd size mismatch! Проверь паддинг и порядок полей."); 

// Для overlay/hud:
// extern size_t g_szCBaseUserCmdPB_CS2;
// extern size_t g_szRepeatedPtrFieldPB_CS2; 