#ifndef DECK_JSON_H
#define DECK_JSON_H

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

/* Minimal, hand-rolled JSON reader - just enough to parse deck-engine's
 * own --format json output (engine/src/reading.c's reading_print_json).
 * Not a general-purpose/validating JSON library, and unlike the core
 * engine this is desktop-only (uses malloc) - the interpreter binary was
 * never meant to run on the watch itself. */

typedef enum {
  JSON_NULL,
  JSON_BOOL,
  JSON_NUMBER,
  JSON_STRING,
  JSON_ARRAY,
  JSON_OBJECT
} JsonType;

typedef struct JsonValue JsonValue;

struct JsonValue {
  JsonType type;
  union {
    bool boolean;
    double number;
    char *string;
    struct { JsonValue **items; int count; } array;
    struct { char **keys; JsonValue **values; int count; } object;
  } as;
};

/* Parses `text` into a JsonValue tree; `text` must be null-terminated at
 * text[length] (every caller here reads a whole file/stream into a
 * malloc'd buffer and NUL-terminates it before calling this). Returns
 * NULL on malformed input. On success the caller owns the result and
 * must free it with json_free(). */
JsonValue *json_parse(const char *text, size_t length);
void json_free(JsonValue *value);

/* NULL if `key` isn't present or `value` isn't an object. */
const JsonValue *json_object_get(const JsonValue *value, const char *key);
/* 0 if `value` isn't an array. */
int json_array_count(const JsonValue *value);
/* NULL if `value` isn't an array or `index` is out of range. */
const JsonValue *json_array_get(const JsonValue *value, int index);
/* 0.0 / "" if `value` is NULL or the wrong type - callers that need to
 * distinguish "missing" from "present but zero" should check
 * json_object_get()'s/json_array_get()'s NULL return first. */
double json_as_number(const JsonValue *value);
const char *json_as_string(const JsonValue *value);

#endif
