#include <assert.h>
#include <stdio.h>
#include <string.h>

#include "../src/json.h"
#include "../src/reading_io.h"

static void test_json_parse_basic_shapes(void) {
  const char *text = "{\"a\": 1, \"b\": [true, false, null, \"text\"], \"c\": {\"nested\": 2.5}}";
  JsonValue *root = json_parse(text, strlen(text));
  assert(root && root->type == JSON_OBJECT);

  assert(json_as_number(json_object_get(root, "a")) == 1.0);

  const JsonValue *b = json_object_get(root, "b");
  assert(json_array_count(b) == 4);
  assert(json_array_get(b, 0)->type == JSON_BOOL && json_array_get(b, 0)->as.boolean == true);
  assert(json_array_get(b, 1)->type == JSON_BOOL && json_array_get(b, 1)->as.boolean == false);
  assert(json_array_get(b, 2)->type == JSON_NULL);
  assert(strcmp(json_as_string(json_array_get(b, 3)), "text") == 0);

  const JsonValue *c = json_object_get(root, "c");
  assert(json_as_number(json_object_get(c, "nested")) == 2.5);

  json_free(root);
  printf("PASS test_json_parse_basic_shapes\n");
}

static void test_json_parse_rejects_malformed(void) {
  const char *bad_inputs[] = {
    "{not valid json",
    "[1, 2,]",
    "{\"a\": }",
    "",
  };
  for (size_t i = 0; i < sizeof(bad_inputs) / sizeof(bad_inputs[0]); i++) {
    JsonValue *root = json_parse(bad_inputs[i], strlen(bad_inputs[i]));
    assert(root == NULL);
  }
  printf("PASS test_json_parse_rejects_malformed\n");
}

/* A trimmed-but-structurally-faithful fixture matching deck-engine's real
 * --format json shape: natal/spread sections are present with decoy
 * content the loader must skip over without understanding their schema,
 * to prove it navigates by key path rather than assuming any position. */
static const char *k_fixture =
  "{"
  "  \"natal\": {\"bodies\": [{\"body\": \"sun\", \"sign\": \"taurus\"}], \"houses\": []},"
  "  \"transits\": {"
  "    \"bodies\": [{\"body\": \"sun\", \"sign\": \"cancer\"}],"
  "    \"moon_phase\": \"full\","
  "    \"aspects\": ["
  "      {\"transiting_planet\": \"pluto\", \"natal_planet\": \"moon\", \"type\": \"opposition\", \"orb\": 0.2},"
  "      {\"transiting_planet\": \"saturn\", \"natal_planet\": \"sun\", \"type\": \"square\", \"orb\": 0.5}"
  "    ]"
  "  },"
  "  \"spread\": {\"positions\": [{\"position\": \"present\", \"card\": \"devil\", \"reversed\": false}]}"
  "}";

static void test_reading_load_json_extracts_aspects(void) {
  DailyReading reading;
  bool ok = reading_load_json(k_fixture, strlen(k_fixture), &reading);

  assert(ok);
  assert(reading.transits.aspect_count == 2);
  assert(reading.transits.aspects[0].transiting_planet == PLANET_PLUTO);
  assert(reading.transits.aspects[0].natal_planet == PLANET_MOON);
  assert(reading.transits.aspects[0].type == ASPECT_OPPOSITION);
  assert(reading.transits.aspects[0].orb == 0.2);
  assert(reading.transits.aspects[1].transiting_planet == PLANET_SATURN);
  assert(reading.transits.aspects[1].natal_planet == PLANET_SUN);
  assert(reading.transits.aspects[1].type == ASPECT_SQUARE);

  printf("PASS test_reading_load_json_extracts_aspects\n");
}

static void test_reading_load_json_empty_aspects_is_valid(void) {
  const char *text = "{\"transits\": {\"aspects\": []}}";
  DailyReading reading;
  bool ok = reading_load_json(text, strlen(text), &reading);

  assert(ok);
  assert(reading.transits.aspect_count == 0);

  printf("PASS test_reading_load_json_empty_aspects_is_valid\n");
}

static void test_reading_load_json_rejects_missing_transits(void) {
  const char *text = "{\"natal\": {}, \"spread\": {}}";
  DailyReading reading;
  bool ok = reading_load_json(text, strlen(text), &reading);

  assert(!ok);

  printf("PASS test_reading_load_json_rejects_missing_transits\n");
}

static void test_reading_load_json_rejects_unknown_slug(void) {
  const char *text =
    "{\"transits\": {\"aspects\": ["
    "  {\"transiting_planet\": \"xenu\", \"natal_planet\": \"moon\", \"type\": \"square\", \"orb\": 1.0}"
    "]}}";
  DailyReading reading;
  bool ok = reading_load_json(text, strlen(text), &reading);

  assert(!ok);

  printf("PASS test_reading_load_json_rejects_unknown_slug\n");
}

int main(void) {
  test_json_parse_basic_shapes();
  test_json_parse_rejects_malformed();
  test_reading_load_json_extracts_aspects();
  test_reading_load_json_empty_aspects_is_valid();
  test_reading_load_json_rejects_missing_transits();
  test_reading_load_json_rejects_unknown_slug();
  printf("All JSON tests passed.\n");
  return 0;
}
