/**
 * garden.js — the garden model, one shared copy.  [Lane A]
 *
 * SPRINT13 gate 1.2 — B's export ask, granted. These were module-locals in
 * main.js, which made the audit's garden prediction impossible without copying
 * three constants "C is about to change this very sprint" (B's words) — the
 * exact drift sweep.js exists to prevent on the winnability side. Now main.js
 * and tools/site_audit read the SAME model, so "same number, two harnesses"
 * is structural rather than aspirational. B: the TEMPORARY COPY in
 * garden_probe.html can die now.
 *
 * Nothing here changed in the move — this is a mechanical lift. The one thing
 * that DID change this sprint is the comment on GARDEN_DRAIN, because the
 * gate-1 rulings resolved what it is for.
 */

/**
 * How fast an unprotected garden dies, in HP per second at full exposure.
 *
 * SPRINT13 gate 1.4 RULING: **this constant does not move.** My old comment
 * here said "the lever that actually needs moving is the shadow geometry, not
 * this" — C measured the geometry and it was never wrong (probe2: raycast and
 * rasteriser agree at 1.0000). What was wrong was the LINE the yard offered:
 * the canonical p1..p4 covers 25% of what hail sees, and no drain value can
 * separate a 25% line from a bare bed because the drain scales BOTH sides.
 * The separation now comes from anchor placement (backyard_01's p5, its
 * `separation` block, and the a.test assert that flies it), which is where it
 * always had to come from.
 *
 * What 0.9 actually owns is the week's bare-bed arc — the difficulty curve of
 * neglect, measured: gentle 97.6 · southerly 83.7 · buster 82.6 · wildnight
 * 35.7 · icenight 0.0. Move this and all five nights retune at once; the
 * wildnight bare bed must stay under the win line (< 50) for the pinned
 * separation target to mean anything, and the early nights must stay
 * survivable-by-default or night 1 stops being a tutorial. Retunes go through
 * THREADS with that table, not through this number quietly.
 */
export const GARDEN_DRAIN = 0.9;

/**
 * Decision 13's weights. Hail is what actually kills a garden and cloth honestly
 * stops it (stones fall ≤20° off vertical; rain leans 73° in a gale and walks
 * straight under the sail — Lane C's numbers). Rain is demoted to a drizzle of
 * damage so the night still costs you something when it isn't hailing.
 *
 * SPRINT6 gate 1 lists these first among the balance levers.
 */
export const HAIL_WEIGHT = 5.0;
export const RAIN_WEIGHT = 0.25;

/**
 * The garden: the thing you are actually protecting, and the only score that
 * matters. Deliberately not inside hud.js — the HUD reads, it doesn't decide.
 *
 * It keeps its damage split by CAUSE, and that isn't bookkeeping for its own
 * sake: the aftermath verdict is the game's entire feedback channel, and a
 * verdict that guesses teaches the wrong lesson. A garden that only knows it
 * went from 100 to 39 cannot tell a player whether their hardware let go or
 * their perfectly-held sail simply wasn't over the bed — and those are opposite
 * mistakes with opposite fixes.
 *
 * @param {{ setPlants(state: string): void }} world
 */
export function createGarden(world) {
  let hp = 100;
  let state = 'full';
  let byHail = 0;
  let byRain = 0;

  return {
    get hp() { return hp; },
    get state() { return state; },
    /** HP lost to each cause this run. The verdict reads these. */
    get damage() { return { hail: byHail, rain: byRain }; },

    reset() { hp = 100; state = 'full'; byHail = 0; byRain = 0; world.setPlants('full'); },

    /**
     * Decision 13, and the two terms stay SEPARATE on the way in rather than
     * being pre-summed by the caller — that sum is exactly the information the
     * verdict needs and can never recover afterwards.
     *
     * @param {number} dt
     * @param {number} hail 0..1  sky.gardenHailExposure(bed, t)
     * @param {number} rain 0..1  sky.gardenExposure(bed, t)
     */
    step(dt, hail, rain) {
      const dHail = HAIL_WEIGHT * hail * GARDEN_DRAIN * dt;
      const dRain = RAIN_WEIGHT * rain * GARDEN_DRAIN * dt;
      const total = Math.min(hp, dHail + dRain);
      if (total > 0) {
        // Attribute proportionally, so the split still adds up on the last tick
        // when the garden bottoms out at 0 mid-step.
        const scale = total / (dHail + dRain);
        byHail += dHail * scale;
        byRain += dRain * scale;
        hp -= total;
      }
      const next = hp > 66 ? 'full' : hp > 33 ? 'tattered' : 'dead';
      if (next !== state) { state = next; world.setPlants(next); }
    },
  };
}
