#include "narrative.h"

#include <stdbool.h>
#include <stdio.h>

/* i18n_get() only - narrative.h already pulls in astro.h; this is the
 * one additional engine header needed to route k_narratives/
 * k_house_area through the same translation catalog tarot_data.c uses
 * (see the Makefile's INTERP_TAROT_TEXT_OBJS comment for why i18n.c is
 * linked into this binary). */
#include "../../engine/src/i18n.h"

typedef struct {
  const char *slug;        /* builds "narrative.<slug>.*" i18n keys */
  const char *base;        /* always relevant, may be "" (see the Sun) */
  const char *harmonious;  /* shown only under a trine/sextile; may be "" */
  const char *discordant;  /* shown only under a square/opposition; may be "" */
} TransitNarrative;

/* Fallback (English) text, also the source of truth when no translation
 * catalog is loaded - see narrative.h's doc comment for sourcing
 * (Sepharial, "Transits and Planetary Periods", 1920, Chapter VIII) and
 * the Moon/Pluto exception. German translations live in
 * engine/i18n/de.lang under the same "narrative.<slug>.*" keys. */
static const TransitNarrative k_narratives[NUM_BODIES] = {
  [PLANET_SUN] = {
    "sun", "",
    "Benefits from superiors and advancement in your sphere of "
    "life and work - honours, emoluments, and successful new "
    "associations.",
    "Degradation and dishonour, loss of position, and adverse "
    "judgement from superiors.",
  },
  [PLANET_MOON] = {
    /* Original text, not from Sepharial - see narrative.h. */
    "moon",
    "Colours the everyday and domestic sphere of life, often "
    "coinciding with the opening of new avenues.",
    "These changes tend to be advantageous.",
    "These changes tend to be adverse, with some indisposition "
    "or domestic friction.",
  },
  [PLANET_MERCURY] = {
    "mercury",
    "Affects writings, journeys, commerce, and everyday activities - "
    "a neutral messenger whose effect follows the nature of the "
    "aspect it makes.",
    "", "",
  },
  [PLANET_VENUS] = {
    "venus",
    "Brings domestic and social affairs to the fore - happiness, "
    "comforts, and favours.",
    "Success in love affairs and artistic pursuits is likely.",
    "Grief and disappointment are more likely.",
  },
  [PLANET_MARS] = {
    "mars",
    "A strenuous time of quarrels, contention, strife and anger, with "
    "some risk of hurts or injuries depending on the sign it "
    "occupies.",
    "Can bring benefits from doctors, surgeons, or new projects "
    "and enterprises.",
    "",
  },
  [PLANET_JUPITER] = {
    "jupiter",
    "Brings increase and expansion - fullness of fortune and health, "
    "and a generally fortunate time.",
    "", "",
  },
  [PLANET_SATURN] = {
    "saturn",
    "Brings depression, stagnation, hindrances and obstacles, and "
    "some deprivation of the usual benefits.",
    "Favours from older connections and past associations are "
    "still possible.",
    "",
  },
  [PLANET_URANUS] = {
    "uranus",
    "Brings separations, estrangements, sudden dislocations and "
    "violent upsets.",
    "Success through official or civic channels, and "
    "beneficial changes or appointments, are possible.",
    "",
  },
  [PLANET_NEPTUNE] = {
    "neptune",
    "Brings a state of chaos and confusion - an involved, uncertain "
    "condition of affairs, with plots, subtlety, or unseen "
    "influences at work.",
    "", "",
  },
  [PLANET_PLUTO] = {
    /* Original text, not from Sepharial - see narrative.h. */
    "pluto",
    "Brings deep, often hidden transformation - the surfacing or "
    "dismantling of something that has outgrown its old form.",
    "", "",
  },
};

static bool aspect_is_harmonious(AspectType type) {
  return type == ASPECT_TRINE || type == ASPECT_SEXTILE;
}

static bool aspect_is_discordant(AspectType type) {
  return type == ASPECT_SQUARE || type == ASPECT_OPPOSITION;
}

/* Traditional whole-sign house significations - the "area of life" each
 * house governs. This is centuries-old, uncredited astrological
 * convention (the same status as the sign/aspect names already baked
 * into engine/src/astro.c), not text drawn from Sepharial or any other
 * single source. Indexed house - 1; fallback (English) text only, keyed
 * as "narrative.house.<1-12>" in engine/i18n's .lang files. */
static const char *const k_house_area[12] = {
  "your sense of self, identity, and outward appearance",
  "money, possessions, and personal values",
  "communication, siblings, and everyday learning",
  "home, family, and your roots",
  "romance, creativity, and children",
  "daily work, routine, and health",
  "partnerships and close relationships",
  "shared resources, intimacy, and transformation",
  "travel, higher learning, and beliefs",
  "career, reputation, and public standing",
  "friendships, community, and hopes for the future",
  "solitude, the subconscious, and hidden matters",
};

static const char *narrative_field(const char *slug, const char *field, const char *fallback) {
  char key[48];
  snprintf(key, sizeof key, "narrative.%s.%s", slug, field);
  return i18n_get(key, fallback);
}

void narrative_print(FILE *out, const char *indent, const Aspect *aspect,
                      int transiting_house) {
  const TransitNarrative *n = &k_narratives[aspect->transiting_planet];
  const char *base = narrative_field(n->slug, "base", n->base);

  const char *extra = "";
  if (aspect_is_harmonious(aspect->type)) extra = narrative_field(n->slug, "harmonious", n->harmonious);
  else if (aspect_is_discordant(aspect->type)) extra = narrative_field(n->slug, "discordant", n->discordant);

  if (base[0] == '\0' && extra[0] == '\0') return;

  fprintf(out, "%s", indent);
  if (transiting_house >= 1 && transiting_house <= 12) {
    char house_key[24];
    snprintf(house_key, sizeof house_key, "narrative.house.%d", transiting_house);
    const char *area = i18n_get(house_key, k_house_area[transiting_house - 1]);

    char frame[256];
    snprintf(frame, sizeof frame, i18n_get("narrative.house_frame", "In matters of %s (house %d)."),
             area, transiting_house);
    fprintf(out, "%s ", frame);
  }
  if (base[0] != '\0') fprintf(out, "%s", base);
  if (extra[0] != '\0') fprintf(out, "%s%s", base[0] != '\0' ? " " : "", extra);
  fprintf(out, "\n");
}
