#pragma once
#include "Mod.h"

#include "SDK/ItemRenderer.h"
#include "SDK/BaseActorRenderContext.h"
#include "SDK/ActorRenderData.h"
#include "SDK/ItemActor.h"

class ItemPhysics : public Mod {
public:
    float speed = 1.f;
    bool spin = false;

    ItemPhysics() : Mod(_("Item Physics"), _("Adapt the rotation to the item."), Category::RENDER) {
        settings.push_back(new Setting{ _("Speed"), &speed, new float(2.f), new int(0.f), 2, {}, true, 15.f });
        settings.push_back(new Setting{ _("Spin"), &spin, 0, 0, 0, {}, true });

        {
            if (Utils::File::getVersion() == _("1.21.80")) {
                itempositionconst_ = Utils::Memory::FindPattern(_("F3 0F 10 15 EA 91"));

                itempositionconst_ = reinterpret_cast<void*>(
                    reinterpret_cast<uintptr_t>(itempositionconst_) + 4
                    );
            }
            else if (Utils::File::getVersion() == _("1.21.73")) {
                itempositionconst_ = Utils::Memory::FindPattern(_("F3 0F 10 15 02 EC"));

                itempositionconst_ = reinterpret_cast<void*>(
                    reinterpret_cast<uintptr_t>(itempositionconst_) + 4
                    );
            }
            else if (Utils::File::getVersion() == _("1.21.72")) {
                itempositionconst_ = Utils::Memory::FindPattern(_("F3 0F 10 15 02 EB"));

                itempositionconst_ = reinterpret_cast<void*>(
                    reinterpret_cast<uintptr_t>(itempositionconst_) + 4
                    );
            }
            else if (Utils::File::getVersion() == _("1.21.71")) {
                itempositionconst_ = Utils::Memory::FindPattern(_("F3 0F 10 15 7A F1"));

                itempositionconst_ = reinterpret_cast<void*>(
                    reinterpret_cast<uintptr_t>(itempositionconst_) + 4
                    );
            }
            else if (Utils::File::getVersion() == _("1.21.70")) {
                itempositionconst_ = Utils::Memory::FindPattern(_("F3 0F 10 15 E2 10"));

                itempositionconst_ = reinterpret_cast<void*>(
                    reinterpret_cast<uintptr_t>(itempositionconst_) + 4
                    );
            }
            else {
                itempositionconst_ = Utils::Memory::FindPattern(_("F3 0F 10 15 12 AB"));

                itempositionconst_ = reinterpret_cast<void*>(
                    reinterpret_cast<uintptr_t>(itempositionconst_) + 4
                    );
            }
        }

        {
            if (Utils::File::getVersion() == _("1.21.80"))
                glm_rotateRef_ = Utils::Memory::FindPattern(_("E8 F0 B6 3F FF"));
            else if (Utils::File::getVersion() == _("1.21.73"))
                glm_rotateRef_ = Utils::Memory::FindPattern(_("E8 F0 14 FE"));
            else if (Utils::File::getVersion() == _("1.21.72"))
                glm_rotateRef_ = Utils::Memory::FindPattern(_("E8 90 13 FE FE"));
            else if (Utils::File::getVersion() == _("1.21.71"))
                glm_rotateRef_ = Utils::Memory::FindPattern(_("E8 10 2C FE"));
            else if (Utils::File::getVersion() == _("1.21.70"))
                glm_rotateRef_ = Utils::Memory::FindPattern(_("E8 20 2C FE"));
            else
                glm_rotateRef_ = Utils::Memory::FindPattern(_("E8 10 2C FE"));
        }

        {
            if (Utils::File::getVersion() == _("1.21.80"))
                glm_translateRef_ = Utils::Memory::FindPattern(_("E8 E1 69 24"));
            else if (Utils::File::getVersion() == _("1.21.73"))
                glm_translateRef_ = Utils::Memory::FindPattern(_("E8 41 47 D5 FE"));
            else if (Utils::File::getVersion() == _("1.21.72"))
                glm_translateRef_ = Utils::Memory::FindPattern(_("E8 11 46 D5"));
            else if (Utils::File::getVersion() == _("1.21.71"))
                glm_translateRef_ = Utils::Memory::FindPattern(_("E8 11 60 D5"));
            else if (Utils::File::getVersion() == _("1.21.70"))
                glm_translateRef_ = Utils::Memory::FindPattern(_("E8 21 60 D5"));
            else
                glm_translateRef_ = Utils::Memory::FindPattern(_("E8 51 F8 DD"));

            {
                DWORD oldprotect;
                VirtualProtect(glm_translateRef_, 5, PAGE_EXECUTE_READWRITE, &oldprotect);
                memcpy(ogBytes, glm_translateRef_, 5);
                VirtualProtect(glm_translateRef_, 5, oldprotect, &oldprotect);
            }
        }

        enabled = false;
    }

private:
    void* itempositionconst_;

    void* glm_rotateRef_;
    void* glm_translateRef_;

    void* itemrenderer_render_;

    uint32_t posRel = 0;
    float* newposRel = nullptr;

    ActorRenderData* renderData = nullptr;
    std::unordered_map<Actor*, std::tuple<float, glm::vec3, glm::ivec3>> actorData;


    bool patched = false;

    virtual auto onItemRenderer_render(ActorRenderData* data) -> void override;
    virtual auto onClient() -> void override;
    virtual auto onDisabled() -> void override;



    class HookClass {
    public:
        void* pointer = nullptr;
        void* trampoline = nullptr;
        bool valid = false;

        HookClass(void* function, void* hook) {
            pointer = function;

            if (IsBadReadPtr(pointer, sizeof(pointer)))
                return;

            if (const auto status = MH_CreateHook(pointer, hook, &trampoline); status == MH_OK)
                valid = true;
        }

        ~HookClass() {
            disable();
        }

        void enable() const {
            if (valid)
                MH_QueueEnableHook(pointer);
            MH_ApplyQueued();
        }

        void disable() const {
            if (valid)
                MH_DisableHook(pointer);
        }
    };
    void* ogBytes[5] = { 0 };


    inline static std::unique_ptr<HookClass> glm_rotateHook;

    static glm::mat4x4 glm_rotate(glm::mat4x4& mat, float angle, const glm::vec3& axis);
};
