#include "platform/process.h"

#include "platform/paths_platform.h"

#include <windows.h>

#include <filesystem>
#include <string>
#include <system_error>

namespace nebula::platform {
namespace {

std::wstring Utf8ToWide(const std::string& utf8) {
    if (utf8.empty()) {
        return {};
    }

    const int size = MultiByteToWideChar(
        CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), nullptr, 0);
    if (size <= 0) {
        return {};
    }

    std::wstring result(static_cast<size_t>(size), L'\0');
    MultiByteToWideChar(
        CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), result.data(), size);
    return result;
}

}  // namespace

bool LaunchSiblingExecutable(const std::string& executable_name) {
    const auto directory = ExecutableDirectory();
    if (directory.empty() || executable_name.empty()) {
        return false;
    }

    const std::wstring exe_name = Utf8ToWide(executable_name);
    if (exe_name.empty()) {
        return false;
    }

    const std::filesystem::path path = directory / exe_name;
    std::error_code error;
    if (!std::filesystem::exists(path, error)) {
        return false;
    }

    const std::wstring path_wide = path.wstring();
    const std::wstring dir_wide = directory.wstring();

    STARTUPINFOW startup_info = {};
    startup_info.cb = sizeof(startup_info);
    PROCESS_INFORMATION process_info = {};

    // CreateProcess requires a writable command line buffer.
    std::wstring command_line = L"\"" + path_wide + L"\"";
    const BOOL created = CreateProcessW(
        path_wide.c_str(),
        command_line.data(),
        nullptr,
        nullptr,
        FALSE,
        0,
        nullptr,
        dir_wide.c_str(),
        &startup_info,
        &process_info);
    if (!created) {
        return false;
    }

    CloseHandle(process_info.hThread);
    CloseHandle(process_info.hProcess);
    return true;
}

}  // namespace nebula::platform
