#pragma once

#include <stddef.h>
#include <stdbool.h>

/* ── Public API ─────────────────────────────────────────────────────────── */

/**
 * Platform identification (for build-time selection).
 * Only one should be defined: PLATFORM_LINUX, PLATFORM_WIN32, PLATFORM_WEB.
 * Undefined means unknown / desktop fallback.
 */
enum Platform {
    PLATFORM_UNKNOWN = 0,
    PLATFORM_LINUX,
    PLATFORM_WIN32,
    PLATFORM_WEB,
};

/**
 * Error codes returned by platform functions.
 */
enum PlatformError {
    PLATFORM_OK          =  0,   /**< Success                                         */
    PLATFORM_GENERAL     = -1,   /**< Non-specific failure                            */
    PLATFORM_NOT_SUPPORTED = -2, /**< Function not available on this platform         */
};
typedef int PlatformError;

/* ── Process / spawning ─────────────────────────────────────────────────── */

/**
 * Result of waiting for a spawned process.
 */
enum SpawnStatus {
    SPAWN_WAITING,           /**< Process still running                   */
    SPAWN_EXITED,            /**< Process has exited, exitCode is valid   */
    SPAWN_EXIT_CODE_UNKNOWN, /**< Exited but we could not determine code  */
};
typedef int SpawnStatus;

/**
 * Opaque handle to a spawned child process.
 */
typedef struct {
    void *handle;
    enum SpawnStatus status;
    int exit_code;
    int last_error;
} PlatformSpawnHandle;

/**
 * Spawn a child process synchronously. Blocks until the child
 * exits — without going through a shell, so user-controlled
 * arguments cannot inject commands.
 *
 * @param program  Program to run (passed directly to execvp /
 *                 CreateProcess, never split by a shell).
 * @param argv     NULL-terminated argument array. argv[0] is the
 *                 program name, argv[1..n] are arguments.
 * @param[out] out_handle  Fill with a handle for status queries.
 * @return PLATFORM_OK on success, PLATFORM_GENERAL on failure.
 */
PlatformError Platform_SpawnChild(const char *program, const char **argv,
                                  PlatformSpawnHandle *out_handle);

/**
 * Wait for a spawned process to exit.
 */
PlatformError Platform_WaitForChild(PlatformSpawnHandle *handle);

/**
 * Get the exit status of a spawned process.
 */
SpawnStatus Platform_GetExitStatus(const PlatformSpawnHandle *handle,
                                   int *code);

/**
 * Clean up resources associated with a spawn handle.
 */
void Platform_CloseSpawnHandle(PlatformSpawnHandle *handle);

/* ── Error description ─────────────────────────────────────────────────── */

/**
 * Human-readable description of the last platform error.
 * Returns a static string (caller does not free).
 */
const char *Platform_GetLastErrorMessage(void);

/* ── Paths ──────────────────────────────────────────────────────────────── */

/**
 * Temporary directory for the platform.
 * Static string — do not modify or free.
 */
const char *Platform_GetTempDir(void);

/* ── File delivery ──────────────────────────────────────────────────────── */

/**
 * Hand a just-written file to the user.
 *
 * On desktop this is a no-op: the file is already on disk at `path` where the
 * user asked for it. On the web there is no local disk the user can see, so
 * this reads the file back from the virtual filesystem, triggers a browser
 * "save as" download named after the file, and removes the temporary copy.
 *
 * @param path  Path the file was just written to.
 */
void Platform_OfferFileToUser(const char *path);

/**
 * Whether this platform needs an explicit "upload" affordance to get a file in.
 *
 * True only on the web, where the app's filesystem is an in-memory sandbox the
 * user cannot see: a file browser there lists nothing useful, so the UI offers
 * a native file picker instead.
 */
bool Platform_NeedsFileUpload(void);

/**
 * Open the host's file picker and copy the chosen file into a place this
 * process can read.
 *
 * Asynchronous by nature on the web (the picker resolves in a browser event),
 * so this returns immediately; poll Platform_TakeUploadedFile() for the result.
 * No-op on desktop, where the built-in file browser already works.
 */
void Platform_RequestFileUpload(void);

/**
 * Collect a file delivered by Platform_RequestFileUpload, if one is ready.
 *
 * @param outPath  Buffer receiving the path within the app's filesystem.
 * @param cap      Size of `outPath`.
 * @return true exactly once per uploaded file; false when nothing is pending.
 */
bool Platform_TakeUploadedFile(char *outPath, int cap);
