#include <store_mode/vstdlib/vstdlib.hpp>

namespace store::vstdlib {
    VIRTUAL(bool) SharedLicensesLockStatus(PARAMS(void* arg)) {
        LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg)
        ARGS();
        return true;
    }

    VIRTUAL(bool) SharedLibraryStopPlaying(PARAMS(void* arg)) {
        LOG_DEBUG("{}(this={}, arg={})", __func__, THIS, arg)
        ARGS();
        return true;
    }

    VIRTUAL(void) VStdLib_Callback_Interceptor(PARAMS(const char** name_ptr)) {
        GET_ORIGINAL_HOOKED_FUNCTION(VStdLib_Callback_Interceptor)
        VStdLib_Callback_Interceptor_o(ARGS(name_ptr));

        static auto lock_status_hooked = false;
        static auto stop_playing_hooked = false;

        if (lock_status_hooked && stop_playing_hooked) {
            return;
        }

        auto* const data = (CoroutineData*) THIS;

        if (data && data->get_callback_name()) {
            const auto name = String(data->get_callback_name());
            LOG_TRACE("{}(ecx={}, edx={}, name='{}')", __func__, ARGS(), name)
            if (name == "SharedLicensesLockStatus" && !lock_status_hooked) {
                DETOUR_ADDRESS(SharedLicensesLockStatus, data->get_callback_data()->get_callback_address())
                lock_status_hooked = true;
            } else if (name == "SharedLibraryStopPlaying" && !stop_playing_hooked) {
                DETOUR_ADDRESS(SharedLibraryStopPlaying, data->get_callback_data()->get_callback_address())
                stop_playing_hooked = true;
            }
        }
    }

    /**
     * Initially, callback data passed into this function is not complete,
     * hence we must hook an interface method that sets the callback name.
     */
    DLL_EXPORT(HCoroutine) Coroutine_Create(void* callback_address, CoroutineData* data) {
        GET_ORIGINAL_HOOKED_FUNCTION(Coroutine_Create)

        const auto result = Coroutine_Create_o(callback_address, data);

        // Coroutine callback appears to be always the same
        CALL_ONCE({
            LOG_DEBUG("Coroutine_Create -> callback: {}, data: {}", callback_address, fmt::ptr(data));

            DETOUR_ADDRESS(
                VStdLib_Callback_Interceptor,
                data->get_callback_data()->get_callback_intercept_address()
            )
        })

        return result;
    }

}
