#include <Core/Common/String.h>
#include <Core/HAL/Filesystem/Filesystem_Platform.h>
#include <Core/HAL/Win32.h>
#include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h>
#include <Core/Memory/Allocator.h>

namespace Juliet::Platform
{
    String GetBasePath()
    {
        // Allocate a buffer that could fit the module size.
        // Max Path is a good start but could be bigger if the path include long path prefix
        size_t bufferSize = MAX_PATH;
        auto   buffer     = static_cast<char*>(Calloc(MAX_PATH, sizeof(char)));
        if (buffer == nullptr)
        {
            return {};
        }

        size_t moduleFilenameLength = 0;
        while (true)
        {
            moduleFilenameLength = GetModuleFileNameA(nullptr, buffer, static_cast<uint32>(bufferSize));

            // If the module filename length is bigger than the buffer size, we need to reallocate a bigger buffer
            if (moduleFilenameLength >= bufferSize - 1)
            {
                bufferSize *= 2;
                buffer = static_cast<char*>(Realloc(buffer, bufferSize * sizeof(char)));
            }
            else
            {
                break;
            }
        }

        if (moduleFilenameLength == 0)
        {
            SafeFree(buffer);
            Log(LogLevel::Error, LogCategory::Core, "Filesystem: Cannot locate executable path");
        }

        size_t idx = 0;
        for (idx = moduleFilenameLength - 1; idx > 0; --idx)
        {
            if (buffer[idx] == '\\')
            {
                break;
            }
        }

        Assert(idx > 0 && "Path is not absolute!");
        buffer[idx + 1] = '\0'; // Chop chop

        return WrapString(buffer);
    }

    bool IsAbsolutePath(String path)
    {
        if (!path.Data || path.Size == 0)
        {
            return false;
        }

        // From https://learn.microsoft.com/en-ca/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#fully_qualified_vs._relative_paths
        // Windows path starts with either:
        // A UNC name of any format, which always start with two backslash characters ("\\"). For more information, see the next section.
        // A disk designator with a backslash, for example "C:\" or "d:\".
        // A single backslash, for example, "\directory" or "\file.txt". This is also referred to as an absolute path.
        // We will only handle the first two. Single backslash is weird.
        const char* pathStr = path.Data;
        size_t      pathLen = path.Size;

        if (pathLen > 1)
        {
            if (pathStr[0] == '\\' && pathStr[1] == '\\')
            {
                return true;
            }

            if (pathLen > 2)
            {
                char first  = pathStr[0];
                char second = pathStr[1];
                char third  = pathStr[2];
                return ((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')) && second == ':' &&
                       (third == '\\' || third == '/');
            }
        }

        return false;
    }
} // namespace Juliet::Platform
