#include "adapters/hooks/HookLifecycle.h"

#include <utility>

#include "adapters/hooks/game/GameLoopHooks.h"
#include "adapters/hooks/game/LocalRaidHooks.h"
#include "adapters/hooks/items/ItemHooks.h"
#include "adapters/hooks/player/PlayerHooks.h"
#include "adapters/windows/Hooking.h"
#include "foundation/diagnostics/Logger.h"

#ifdef INCLUDE_AIMBOT
#include "adapters/hooks/combat/AimbotHooks.h"
#endif

namespace ta::adapters::hooks::lifecycle
{
    namespace
    {
        InstallResult rollback_failure(const InstallStage stage, std::string detail)
        {
            ta::foundation::logger::error(
                "Hook installation failed | stage=" + std::string(to_string(stage)) + " | detail=" + detail);
            const bool rollback_complete = detach_all();
            if (rollback_complete)
                reset_all();
            else
                ta::foundation::logger::error("Hook installation rollback failed; hook state was preserved");
            return {false, !rollback_complete, stage, std::move(detail)};
        }
    }

    InstallResult install_all(const ta::adapters::hooks::RuntimeCallbacks& callbacks)
    {
        if (!ta::adapters::hooks::publish_runtime_callbacks(callbacks))
            return rollback_failure(InstallStage::PublishCallbacks, "callback binding is invalid");
        if (!ta::adapters::hooks::local_raid::init())
            return rollback_failure(InstallStage::LocalRaid, "local raid hook initialization failed");
        if (!ta::adapters::hooks::game_loop::install())
            return rollback_failure(InstallStage::GameLoop, "game loop hook installation failed");
        if (!ta::adapters::hooks::player::install())
            return rollback_failure(InstallStage::Player, "player hook installation failed");
        if (!ta::adapters::hooks::items::install())
            return rollback_failure(InstallStage::Items, "item hook installation failed");
#ifdef INCLUDE_AIMBOT
        if (!ta::adapters::eft::aimbot::hooks::install())
            return rollback_failure(InstallStage::Aimbot, "aimbot hook installation failed");
#endif
        return {true, true, InstallStage::None, {}};
    }

    bool detach_all()
    {
        return ta::adapters::windows::hooks::unhook_all();
    }

    void reset_all()
    {
        ta::adapters::hooks::local_raid::reset();
        ta::adapters::hooks::game_loop::reset();
        ta::adapters::hooks::player::reset();
        ta::adapters::hooks::items::reset();
        ta::adapters::hooks::clear_runtime_callbacks();
#ifdef INCLUDE_AIMBOT
        ta::adapters::eft::aimbot::hooks::uninstall();
#endif
    }

    const char* to_string(const InstallStage stage) noexcept
    {
        switch (stage)
        {
        case InstallStage::None: return "none";
        case InstallStage::PublishCallbacks: return "publish_callbacks";
        case InstallStage::LocalRaid: return "local_raid";
        case InstallStage::GameLoop: return "game_loop";
        case InstallStage::Player: return "player";
        case InstallStage::Items: return "items";
        case InstallStage::Aimbot: return "aimbot";
        default: return "unknown";
        }
    }
}
