/*
 * platform_win32.c — Windows implementation
 *
 * Requires: Windows.h, mincore.lib (for CreateProcessA)
 */

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "platform.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

/* ── Helpers ─────────────────────────────────────────────────────────── */

static char last_error_msg[256] = { 0 };

static void set_last_error(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vsnprintf(last_error_msg, sizeof(last_error_msg), fmt, args);
    va_end(args);
}

/* ── Platform API ────────────────────────────────────────────────────── */

PlatformError Platform_SpawnChild(const char *program, const char **argv,
                                  PlatformSpawnHandle *out_handle) {
    last_error_msg[0] = '\0';

    /* Build a single command line from argv */
    char cmdline[2048] = { 0 };
    for (int i = 0; argv[i]; i++) {
        if (i > 0) strncat(cmdline, " ", sizeof(cmdline) - strlen(cmdline) - 1);
        /* Quote arguments that contain spaces */
        if (strchr(argv[i], ' ')) {
            strncat(cmdline, "\"", sizeof(cmdline) - strlen(cmdline) - 1);
            strncat(cmdline, argv[i], sizeof(cmdline) - strlen(cmdline) - 1);
            strncat(cmdline, "\"", sizeof(cmdline) - strlen(cmdline) - 1);
        } else {
            strncat(cmdline, argv[i], sizeof(cmdline) - strlen(cmdline) - 1);
        }
    }

    /* CreateProcess needs a mutable buffer */
    char cmd_copy[2048];
    strncpy(cmd_copy, cmdline, sizeof(cmd_copy) - 1);
    cmd_copy[sizeof(cmd_copy) - 1] = '\0';

    STARTUPINFOA si;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(pi));

    if (!CreateProcessA(NULL, cmd_copy, NULL, NULL, FALSE,
                        0, NULL, NULL, &si, &pi)) {
        DWORD err = GetLastError();
        char msg[256];
        sprintf(msg, "CreateProcess failed (code %lu)", err);
        strncpy(last_error_msg, msg, sizeof(last_error_msg) - 1);
        out_handle->last_error = (int)err;
        return PLATFORM_GENERAL;
    }

    out_handle->handle = (void *)pi.hProcess;
    out_handle->status = SPAWN_WAITING;
    /* Don't close the thread handle here — CloseSpawnHandle will */
    CloseHandle(pi.hThread);

    return PLATFORM_OK;
}

PlatformError Platform_WaitForChild(PlatformSpawnHandle *handle) {
    if (!handle || !handle->handle) return PLATFORM_GENERAL;

    DWORD wait_result = WaitForSingleObject((HANDLE)handle->handle, INFINITE);
    if (wait_result != WAIT_OBJECT_0) {
        handle->last_error = (int)GetLastError();
        return PLATFORM_GENERAL;
    }

    DWORD exit_code = 0;
    if (!GetExitCodeProcess((HANDLE)handle->handle, &exit_code)) {
        handle->status = SPAWN_EXIT_CODE_UNKNOWN;
        handle->last_error = (int)GetLastError();
        return PLATFORM_GENERAL;
    }

    handle->status = SPAWN_EXITED;
    handle->exit_code = (int)exit_code;
    handle->handle = NULL;
    return PLATFORM_OK;
}

SpawnStatus Platform_GetExitStatus(const PlatformSpawnHandle *handle, int *code) {
    if (!handle) return SPAWN_WAITING;
    if (code) *code = handle->exit_code;
    return handle->status;
}

void Platform_CloseSpawnHandle(PlatformSpawnHandle *handle) {
    if (!handle) return;
    if (handle->handle) {
        CloseHandle((HANDLE)handle->handle);
        handle->handle = NULL;
    }
    handle->status = SPAWN_WAITING;
    handle->exit_code = 0;
    handle->last_error = 0;
}

const char *Platform_GetLastErrorMessage(void) {
    return last_error_msg;
}

const char *Platform_GetTempDir(void) {
    /* Get temp directory path once and cache it */
    static char temp_path[MAX_PATH] = { 0 };
    if (temp_path[0] == '\0') {
        DWORD len = GetTempPathA(sizeof(temp_path), temp_path);
        if (len == 0 || len >= sizeof(temp_path)) {
            strncpy(temp_path, "C:\\Windows\\Temp", sizeof(temp_path) - 1);
        }
    }
    return temp_path;
}

void Platform_OfferFileToUser(const char *path) {
    /* Desktop: the file is already on disk where the user wanted it. */
    (void)path;
}

bool Platform_NeedsFileUpload(void) { return false; }

void Platform_RequestFileUpload(void) {
    /* Desktop has a real filesystem and a working file browser; nothing to do. */
}

bool Platform_TakeUploadedFile(char *outPath, int cap) {
    (void)outPath; (void)cap;
    return false;
}
