#pragma once
#include <windows.h>
#include <synchapi.h>
#include <wincon.h>
#include <winreg.h>

#ifdef _WIN32
namespace plog
{
    using DWORD = ::DWORD;
    using WORD = ::WORD;
    using UINT = ::UINT;
    using BOOL = ::BOOL;
    using LSTATUS = ::LSTATUS;
    using LPSTR = ::LPSTR;
    using LPWSTR = ::LPWSTR;
    using LPCSTR = ::LPCSTR;
    using LPCWSTR = ::LPCWSTR;
    using HANDLE = ::HANDLE;
    using HKEY = ::HKEY;
    using ULONG_PTR = ::ULONG_PTR;
    using REGSAM = ::REGSAM;
    using LPSECURITY_ATTRIBUTES = ::LPSECURITY_ATTRIBUTES;

    using CRITICAL_SECTION = ::CRITICAL_SECTION;
    using COORD = ::COORD;
    using SMALL_RECT = ::SMALL_RECT;
    using CONSOLE_SCREEN_BUFFER_INFO = ::CONSOLE_SCREEN_BUFFER_INFO;

    namespace codePage
    {
        const UINT kActive = 0;
        const UINT kUTF8 = CP_UTF8;
    }

    namespace eventLog
    {
        constexpr WORD kErrorType = EVENTLOG_ERROR_TYPE;
        constexpr WORD kWarningType = EVENTLOG_WARNING_TYPE;
        constexpr WORD kInformationType = EVENTLOG_INFORMATION_TYPE;
    }

    namespace hkey
    {
        const HKEY kLocalMachine = HKEY_LOCAL_MACHINE;
    }

    namespace regSam
    {
        constexpr DWORD kQueryValue = KEY_QUERY_VALUE;
        constexpr DWORD kSetValue = KEY_SET_VALUE;
    }

    namespace regType
    {
        constexpr DWORD kExpandSz = REG_EXPAND_SZ;
        constexpr DWORD kDword = REG_DWORD;
    }

    namespace stdHandle
    {
        constexpr DWORD kOutput = STD_OUTPUT_HANDLE;
    }

    namespace foreground
    {
        constexpr WORD kBlue = FOREGROUND_BLUE;
        constexpr WORD kGreen = FOREGROUND_GREEN;
        constexpr WORD kRed = FOREGROUND_RED;
        constexpr WORD kIntensity = FOREGROUND_INTENSITY;
    }

    namespace background
    {
        constexpr WORD kBlue = BACKGROUND_BLUE;
        constexpr WORD kGreen = BACKGROUND_GREEN;
        constexpr WORD kRed = BACKGROUND_RED;
        constexpr WORD kIntensity = BACKGROUND_INTENSITY;
    }

    namespace winapi
    {
        inline int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar) noexcept
        {
            return ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr, cchWideChar);
        }

        inline int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const char* lpDefaultChar, BOOL* lpUsedDefaultChar) noexcept
        {
            return ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
        }

        inline DWORD GetCurrentThreadId() noexcept
        {
            return ::GetCurrentThreadId();
        }

        inline BOOL MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName) noexcept
        {
            return ::MoveFileW(lpExistingFileName, lpNewFileName);
        }

        inline void InitializeCriticalSection(CRITICAL_SECTION* lpCriticalSection) noexcept
        {
            ::InitializeCriticalSection(lpCriticalSection);
        }

        inline void EnterCriticalSection(CRITICAL_SECTION* lpCriticalSection) noexcept
        {
            ::EnterCriticalSection(lpCriticalSection);
        }

        inline void LeaveCriticalSection(CRITICAL_SECTION* lpCriticalSection) noexcept
        {
            ::LeaveCriticalSection(lpCriticalSection);
        }

        inline void DeleteCriticalSection(CRITICAL_SECTION* lpCriticalSection) noexcept
        {
            ::DeleteCriticalSection(lpCriticalSection);
        }

        inline HANDLE RegisterEventSourceW(LPCWSTR lpUNCServerName, LPCWSTR lpSourceName) noexcept
        {
            return ::RegisterEventSourceW(lpUNCServerName, lpSourceName);
        }

        inline BOOL DeregisterEventSource(HANDLE hEventLog) noexcept
        {
            return ::DeregisterEventSource(hEventLog);
        }

        inline BOOL ReportEventW(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, void* lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCWSTR* lpStrings, void* lpRawData) noexcept
        {
            return ::ReportEventW(hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData);
        }

        inline LSTATUS RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition) noexcept 
        {
            return ::RegCreateKeyExW(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
        }

        inline LSTATUS RegSetValueExW(HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE* lpData, DWORD cbData) noexcept
        {
            return ::RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData, cbData);
        }

        inline LSTATUS RegCloseKey(HKEY hKey) noexcept
        {
            return ::RegCloseKey(hKey);
        }

        inline LSTATUS RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, DWORD samDesired, HKEY* phkResult) noexcept
        {
            return ::RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
        }

        inline LSTATUS RegDeleteKeyW(HKEY hKey, LPCWSTR lpSubKey) noexcept
        {
            return ::RegDeleteKeyW(hKey, lpSubKey);
        }

        inline HANDLE GetStdHandle(DWORD nStdHandle) noexcept
        {
            return ::GetStdHandle(nStdHandle);
        }

        inline BOOL WriteConsoleW(HANDLE hConsoleOutput, const void* lpBuffer, DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved) noexcept
        {
            return ::WriteConsoleW(hConsoleOutput, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpReserved);
        }

        inline BOOL GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO* lpConsoleScreenBufferInfo) noexcept
        {
            return ::GetConsoleScreenBufferInfo(hConsoleOutput, lpConsoleScreenBufferInfo);
        }

        inline BOOL SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes) noexcept
        {
            return ::SetConsoleTextAttribute(hConsoleOutput, wAttributes);
        }

        inline void OutputDebugStringW(LPCWSTR lpOutputString) noexcept
        {
            return ::OutputDebugStringW(lpOutputString);
        }
    }
}
#endif // _WIN32
