#include "reading.h"
#include "i18n.h"

#include <math.h>

/* UI-label keys ("ui.*") are looked up here rather than in i18n.h/.c
 * because they're specific to these two renderers, not part of the
 * portable astro/tarot vocabulary. */
static const char *ui(const char *key, const char *fallback) {
  return i18n_get(key, fallback);
}

void reading_generate(const char *tarot_seed, const BirthData *birth,
                       time_t utc_moment, DailyReading *out) {
  astro_compute_natal_chart(birth, &out->natal);
  astro_compute_daily_transits(utc_moment, &out->natal, &out->transits);
  tarot_draw_celtic_cross(tarot_seed, &out->spread);
}

static void print_position_deg(FILE *out, const PlanetPosition *p) {
  fprintf(out, "%5.1f%s %-11s (%s %d)", p->degree_in_sign, "\xc2\xb0",
          astro_sign_name(p->sign), ui("ui.house", "House"), p->house);
}

void reading_print_text(const DailyReading *r, FILE *out) {
  fprintf(out, "===== %s =====\n", ui("ui.natal_chart", "Natal Chart"));
  for (int b = 0; b < NUM_BODIES; b++) {
    fprintf(out, "%-8s ", astro_body_name((Body)b));
    print_position_deg(out, &r->natal.bodies[b]);
    fprintf(out, "\n");
  }
  fprintf(out, "%s %5.1f%s %s\n", ui("ui.ascendant", "Ascendant"),
          fmod(r->natal.ascendant_longitude, 30.0), "\xc2\xb0",
          astro_sign_name(r->natal.houses[0]));
  fprintf(out, "\n");

  fprintf(out, "===== %s =====\n", ui("ui.todays_sky", "Today's Sky"));
  fprintf(out, "%s %s\n", ui("ui.moon_phase", "Moon phase:"),
          astro_moon_phase_name(r->transits.moon_phase));
  for (int b = 0; b < NUM_BODIES; b++) {
    fprintf(out, "%-8s ", astro_body_name((Body)b));
    print_position_deg(out, &r->transits.bodies[b]);
    fprintf(out, "\n");
  }
  fprintf(out, "\n");

  fprintf(out, "===== %s =====\n", ui("ui.todays_aspects", "Today's Aspects to Natal Chart"));
  if (r->transits.aspect_count == 0) {
    fprintf(out, "%s\n", ui("ui.no_aspects", "(none within orb)"));
  }
  for (int i = 0; i < r->transits.aspect_count; i++) {
    const Aspect *a = &r->transits.aspects[i];
    fprintf(out, "%s %s %s %s %s (%s %.1f%s)\n", ui("ui.transiting", "Transiting"),
            astro_body_name(a->transiting_planet), astro_aspect_name(a->type),
            ui("ui.natal", "natal"), astro_body_name(a->natal_planet),
            ui("ui.orb", "orb"), a->orb, "\xc2\xb0");
  }
  fprintf(out, "\n");

  fprintf(out, "===== %s =====\n", ui("ui.celtic_cross", "Celtic Cross"));
  for (int i = 0; i < TAROT_SPREAD_SIZE; i++) {
    const TarotDraw *draw = &r->spread.positions[i];
    fprintf(out, "%-16s %s%s%s\n", tarot_position_name((CelticCrossPosition)i),
            tarot_card_name(draw->card), draw->reversed ? " " : "",
            draw->reversed ? ui("ui.reversed", "(Reversed)") : "");
    fprintf(out, "  %s\n", tarot_position_description((CelticCrossPosition)i));
    fprintf(out, "  %s\n", tarot_card_meaning(draw->card, draw->reversed));
  }
}

static void print_body_row_html(FILE *out, const char *label, const PlanetPosition *p) {
  fprintf(out, "<tr><td>%s</td><td>%.1f&deg; %s</td><td>%s %d</td></tr>\n", label,
          p->degree_in_sign, astro_sign_name(p->sign), ui("ui.house", "House"), p->house);
}

void reading_print_html(const DailyReading *r, FILE *out) {
  fprintf(out,
    "<!doctype html>\n<html><head><meta charset=\"utf-8\">\n"
    "<title>%s</title>\n"
    "<style>\n"
    "body { font-family: sans-serif; max-width: 900px; margin: 2em auto; }\n"
    "table { border-collapse: collapse; margin-bottom: 1.5em; }\n"
    "td { padding: 2px 10px 2px 0; }\n"
    "h1, h2 { border-bottom: 1px solid #ccc; }\n"
    ".spread { display: flex; flex-wrap: wrap; gap: 1.5em; }\n"
    ".card { width: 160px; }\n"
    ".card img { width: 140px; display: block; }\n"
    ".card img.reversed { transform: rotate(180deg); }\n"
    ".card .position { font-weight: bold; }\n"
    ".card .name { font-style: italic; }\n"
    "</style></head><body>\n",
    ui("ui.page_title", "Deck in a Dash - Daily Reading"));

  fprintf(out, "<h1>%s</h1>\n", ui("ui.daily_reading", "Daily Reading"));

  fprintf(out, "<h2>%s</h2>\n<table>\n", ui("ui.natal_chart", "Natal Chart"));
  for (int b = 0; b < NUM_BODIES; b++) {
    print_body_row_html(out, astro_body_name((Body)b), &r->natal.bodies[b]);
  }
  fprintf(out, "<tr><td>%s</td><td>%.1f&deg; %s</td></tr>\n", ui("ui.ascendant", "Ascendant"),
          fmod(r->natal.ascendant_longitude, 30.0), astro_sign_name(r->natal.houses[0]));
  fprintf(out, "</table>\n");

  fprintf(out, "<h2>%s</h2>\n<p>%s %s</p>\n<table>\n", ui("ui.todays_sky", "Today's Sky"),
          ui("ui.moon_phase", "Moon phase:"), astro_moon_phase_name(r->transits.moon_phase));
  for (int b = 0; b < NUM_BODIES; b++) {
    print_body_row_html(out, astro_body_name((Body)b), &r->transits.bodies[b]);
  }
  fprintf(out, "</table>\n");

  fprintf(out, "<h2>%s</h2>\n<table>\n", ui("ui.todays_aspects", "Today's Aspects to Natal Chart"));
  for (int i = 0; i < r->transits.aspect_count; i++) {
    const Aspect *a = &r->transits.aspects[i];
    fprintf(out, "<tr><td>%s %s</td><td>%s</td><td>%s %s</td><td>%s %.1f&deg;</td></tr>\n",
            ui("ui.transiting", "Transiting"), astro_body_name(a->transiting_planet),
            astro_aspect_name(a->type), ui("ui.natal", "natal"),
            astro_body_name(a->natal_planet), ui("ui.orb", "orb"), a->orb);
  }
  fprintf(out, "</table>\n");

  fprintf(out, "<h2>%s</h2>\n<div class=\"spread\">\n", ui("ui.celtic_cross", "Celtic Cross"));
  for (int i = 0; i < TAROT_SPREAD_SIZE; i++) {
    const TarotDraw *draw = &r->spread.positions[i];
    fprintf(out,
      "<div class=\"card\">\n"
      "  <div class=\"position\">%s</div>\n"
      /* Expects card art at img/<file> next to the HTML file itself -
       * `make images` copies res/img/ there alongside the binary in
       * dist/. */
      "  <img class=\"%s\" src=\"img/%s\" alt=\"%s\">\n"
      "  <div class=\"name\">%s%s%s</div>\n"
      "  <div class=\"desc\">%s</div>\n"
      "  <div class=\"meaning\">%s</div>\n"
      "</div>\n",
      tarot_position_name((CelticCrossPosition)i),
      draw->reversed ? "reversed" : "",
      tarot_card_image_file(draw->card), tarot_card_name(draw->card),
      tarot_card_name(draw->card), draw->reversed ? " " : "",
      draw->reversed ? ui("ui.reversed", "(Reversed)") : "",
      tarot_position_description((CelticCrossPosition)i),
      tarot_card_meaning(draw->card, draw->reversed));
  }
  fprintf(out, "</div>\n</body></html>\n");
}

static void print_body_position_json(FILE *out, const char *indent, Body body,
                                      const PlanetPosition *p) {
  fprintf(out,
    "%s{\"body\": \"%s\", \"sign\": \"%s\", \"degree_in_sign\": %.4f, "
    "\"ecliptic_longitude\": %.4f, \"house\": %d}",
    indent, astro_body_slug(body), astro_sign_slug(p->sign),
    p->degree_in_sign, p->ecliptic_longitude, p->house);
}

void reading_print_json(const DailyReading *r, FILE *out) {
  fprintf(out, "{\n");

  fprintf(out, "  \"natal\": {\n    \"bodies\": [\n");
  for (int b = 0; b < NUM_BODIES; b++) {
    print_body_position_json(out, "      ", (Body)b, &r->natal.bodies[b]);
    fprintf(out, "%s\n", b + 1 < NUM_BODIES ? "," : "");
  }
  fprintf(out, "    ],\n    \"ascendant_longitude\": %.4f,\n    \"houses\": [",
          r->natal.ascendant_longitude);
  for (int h = 0; h < 12; h++) {
    fprintf(out, "\"%s\"%s", astro_sign_slug(r->natal.houses[h]), h + 1 < 12 ? ", " : "");
  }
  fprintf(out, "]\n  },\n");

  fprintf(out, "  \"transits\": {\n    \"bodies\": [\n");
  for (int b = 0; b < NUM_BODIES; b++) {
    print_body_position_json(out, "      ", (Body)b, &r->transits.bodies[b]);
    fprintf(out, "%s\n", b + 1 < NUM_BODIES ? "," : "");
  }
  fprintf(out, "    ],\n    \"moon_phase\": \"%s\",\n    \"aspects\": [\n",
          astro_moon_phase_slug(r->transits.moon_phase));
  for (int i = 0; i < r->transits.aspect_count; i++) {
    const Aspect *a = &r->transits.aspects[i];
    fprintf(out,
      "      {\"transiting_planet\": \"%s\", \"natal_planet\": \"%s\", "
      "\"type\": \"%s\", \"orb\": %.4f}%s\n",
      astro_body_slug(a->transiting_planet), astro_body_slug(a->natal_planet),
      astro_aspect_slug(a->type), a->orb,
      i + 1 < r->transits.aspect_count ? "," : "");
  }
  fprintf(out, "    ]\n  },\n");

  fprintf(out, "  \"spread\": {\n    \"positions\": [\n");
  for (int i = 0; i < TAROT_SPREAD_SIZE; i++) {
    const TarotDraw *draw = &r->spread.positions[i];
    fprintf(out, "      {\"position\": \"%s\", \"card\": \"%s\", \"reversed\": %s}%s\n",
            tarot_position_slug((CelticCrossPosition)i), tarot_card_slug(draw->card),
            draw->reversed ? "true" : "false", i + 1 < TAROT_SPREAD_SIZE ? "," : "");
  }
  fprintf(out, "    ]\n  }\n}\n");
}
