#pragma once

#include <filesystem>
#include <string>
#include <Windows.h>

namespace module_paths
{
    inline HMODULE& dll_handle()
    {
        static HMODULE handle = nullptr;
        return handle;
    }

    inline void init(const HMODULE module)
    {
        dll_handle() = module;
    }

    inline bool is_system_directory(const std::filesystem::path& dir)
    {
        if (dir.empty()) return true;

        const std::wstring w = dir.wstring();
        return w.find(L"\\System32") != std::wstring::npos
            || w.find(L"\\SysWOW64") != std::wstring::npos
            || w.find(L"\\WinSxS\\") != std::wstring::npos;
    }

    inline std::string wide_to_utf8(const std::wstring& wide)
    {
        if (wide.empty()) return {};
        const int size = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, nullptr, 0, nullptr, nullptr);
        if (size <= 1) return {};
        std::string out(static_cast<size_t>(size - 1), '\0');
        WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, out.data(), size, nullptr, nullptr);
        return out;
    }

    inline std::filesystem::path dll_directory_wide()
    {
        auto resolve_from_module = [](const HMODULE module) -> std::filesystem::path
        {
            if (!module) return {};

            wchar_t path[MAX_PATH]{};
            if (GetModuleFileNameW(module, path, MAX_PATH) == 0)
                return {};

            const std::filesystem::path module_path(path);
            if (!module_path.has_parent_path())
                return {};

            const std::filesystem::path dir = module_path.parent_path();
            return is_system_directory(dir) ? std::filesystem::path{} : dir;
        };

        if (const std::filesystem::path from_init = resolve_from_module(dll_handle()); !from_init.empty())
            return from_init;

        if (const std::filesystem::path from_name = resolve_from_module(GetModuleHandleW(L"TarkovAddons.dll"));
            !from_name.empty())
            return from_name;

        HMODULE from_address = nullptr;
        if (GetModuleHandleExW(
            GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
            reinterpret_cast<LPCWSTR>(&dll_directory_wide), &from_address))
        {
            if (const std::filesystem::path from_addr = resolve_from_module(from_address); !from_addr.empty())
                return from_addr;
        }

        return {};
    }

    inline std::string dll_directory_utf8()
    {
        return wide_to_utf8(dll_directory_wide().wstring());
    }
}