/* eslint-disable */
// today.jsx — the Today screen's live wiring.
//
// On load this fetches, in parallel:
//   • /api/access            → who's here + which rooms they're granted
//   • {cellar,cocina,recuerdas}.casam.me/api/today → the live room feeds
//
// Then it fills each room tile with one of two states:
//   • a LIVE FEED card  — a count + the latest happening — when the
//     visitor has access to that room, and
//   • a welcoming EMPTY card — a warm "you're not in here yet" — when
//     they don't.
//
// It also populates (or leaves hidden) the "Tonight" slab from the real
// cocina `tonight` + cellar `openTonight` payloads. Nothing is fabricated:
// a missing feed degrades to a quiet resting state, never a broken tile.
//
// Plain DOM (no React) so it cooperates with the static markup in
// index.html and never fights the chrome that app.jsx mounts. All
// feed-supplied strings go in via textContent — never innerHTML — so a
// recipe title can't inject markup.

(function () {
  "use strict";

  // ─── policy ───────────────────────────────────────────────
  // A signed-in member sees live feeds for rooms they're granted and a
  // welcoming empty card for rooms they're not. For an anonymous visitor
  // who simply lands on casam.me, show the public feeds (the house's
  // front door) — the counts + activity are already public on each
  // bridge. Flip this to false to greet anonymous visitors with empty
  // welcoming cards on every room instead.
  const ANON_SEES_FEEDS = true;

  // ─── language (mirrors app.jsx's getLang) ─────────────────
  function getLang() {
    try {
      const v = localStorage.getItem("casam.lang");
      if (v === "en" || v === "es" || v === "en-es") return v;
    } catch (_) {}
    return "en-es";
  }
  // pick(es, en) → primary string for the current language
  function pick(es, en) {
    return getLang() === "en" ? en : es;
  }

  // ─── room registry ────────────────────────────────────────
  // `app` matches the app_grants.app key; `data-room` on the tile in
  // index.html matches `key`. `feed` reads the bridge payload into a
  // normalized { count, unit, line, when } shape (or null bits).
  const ROOMS = {
    cellar: {
      app: "cellar",
      url: "https://cellar.casam.me/api/today",
      empty: {
        es: "Aún no tienes un lugar en la cava.",
        en: "You don't have a place in the cellar yet.",
      },
      feed(d) {
        const count = numOrNull(d && d.counts && d.counts.bottles);
        const a = firstWithWhat(d && d.activity);
        return {
          count, unit: pick("botellas", "bottles"),
          line: a ? cap(`${a.verb} · ${a.what}`) : null,
          when: a ? a.at : (d && d.lastPour && d.lastPour.at) || null,
        };
      },
    },
    cocina: {
      app: "cocina",
      url: "https://cocina.casam.me/api/today",
      empty: {
        es: "Todavía no cocinas en esta cocina.",
        en: "You're not cooking in this kitchen yet.",
      },
      feed(d) {
        const count = numOrNull(d && d.counts && d.counts.recipes);
        const a = firstWithWhat(d && d.activity);
        return {
          count, unit: pick("recetas", "recipes"),
          line: a ? cap(`${a.verb} · ${a.what}`) : null,
          when: a ? a.at : null,
        };
      },
    },
    recuerdas: {
      app: "recuerdas",
      url: "https://recuerdas.casam.me/api/today",
      empty: {
        es: "El mayordomo aún no te conoce.",
        en: "The mayordomo doesn't know you yet.",
      },
      feed(d) {
        const count = numOrNull(d && d.counts && d.counts.pendingToday);
        const p = d && Array.isArray(d.pending) ? d.pending[0] : null;
        const title = p ? (getLang() === "es" && p.titleEs ? p.titleEs : p.title) : null;
        return {
          count, unit: pick("pendientes", "pending"),
          line: p ? `${title}${p.dueLabel ? ` · ${p.dueLabel}` : ""}` : null,
          when: null, // recuerdas items are forward-looking (due), not "ago"
        };
      },
    },
  };

  // ─── room copy (localized) ────────────────────────────────
  // The room NAMES (Cava, Cocina, Recuerdas, Tienda) are Spanish brand
  // nouns and stay fixed; their tagline + sub localize. In bilingual
  // (en-es) mode the sub leads in Spanish with a faint English glance,
  // mirroring the hero greeting. Keyed by tile: the three feed rooms by
  // data-room, Tienda by its toggle id.
  const ROOM_COPY = {
    cellar: {
      tagline: { es: "La bodega · vinos y catas", en: "The cellar · wines & tastings" },
      sub:     { es: "Botellas, añadas, catas y la ventana de descorche.",
                 en: "Bottles, vintages, tastings, the drink window." },
    },
    cocina: {
      tagline: { es: "La cocina · lo que está al fuego", en: "The kitchen · what's on the stove" },
      sub:     { es: "Recetas — lo que cocinamos en casa.",
                 en: "Recipes — what we cook at home." },
    },
    recuerdas: {
      tagline: { es: "¿Recuerdas? · el mayordomo", en: "Recuerdas · the steward" },
      sub:     { es: "Rituales — ofrendas, recetas, llamadas a casa.",
                 en: "Rituals — offerings, recipes, calls home." },
    },
    tienda: {
      tagline: { es: "La tienda · especias y mezclas", en: "The shop · spices & blends" },
      sub:     { es: "Casa M Spice Co. — compra aquí, pago directo.",
                 en: "Casa M Spice Co. — shop here, checkout direct." },
    },
  };

  function localizeRooms() {
    const lang = getLang();
    const lead = lang === "en" ? "en" : "es";
    const bilingual = lang === "en-es";
    Object.keys(ROOM_COPY).forEach((slug) => {
      const tile = slug === "tienda"
        ? document.getElementById("tienda-toggle")
        : document.querySelector(`.room[data-room="${slug}"]`);
      if (!tile) return;
      const c = ROOM_COPY[slug];
      const tagEl = tile.querySelector(".room-tagline");
      const subEl = tile.querySelector(".room-sub");
      if (tagEl) tagEl.textContent = c.tagline[lead];
      if (subEl) {
        if (bilingual) {
          subEl.textContent = c.sub.es;
          const glance = document.createElement("span");
          glance.style.cssText = "display:block;opacity:0.5;font-style:italic;";
          glance.textContent = c.sub.en;
          subEl.appendChild(glance);
        } else {
          subEl.textContent = c.sub[lead];
        }
      }
    });
  }

  // ─── helpers ──────────────────────────────────────────────
  function numOrNull(n) {
    return typeof n === "number" && isFinite(n) ? n : null;
  }
  function fmtCount(n) {
    return n == null ? null : n.toLocaleString(getLang() === "es" ? "es" : "en-US");
  }
  function cap(s) {
    return s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
  }
  // First activity entry that actually names something (skips the empty
  // "tasted ''" rows the cellar bridge can emit).
  function firstWithWhat(arr) {
    if (!Array.isArray(arr)) return null;
    return arr.find((a) => a && a.what && String(a.what).trim()) || null;
  }
  function ago(iso) {
    if (!iso) return null;
    const then = new Date(iso).getTime();
    if (isNaN(then)) return null;
    const s = Math.max(0, (Date.now() - then) / 1000);
    const m = s / 60, h = m / 60, d = h / 24;
    const es = getLang() === "es";
    if (d >= 1) return `${Math.round(d)}${es ? "d" : "d"}`;
    if (h >= 1) return `${Math.round(h)}h`;
    if (m >= 1) return `${Math.round(m)}m`;
    return es ? "ahora" : "now";
  }
  function el(tag, cls, text) {
    const n = document.createElement(tag);
    if (cls) n.className = cls;
    if (text != null) n.textContent = text;
    return n;
  }

  // ─── fetchers ─────────────────────────────────────────────
  function getJSON(url, sameOrigin) {
    return fetch(url, {
      credentials: "include",
      headers: { Accept: "application/json" },
      // bridges are cross-origin; /api/access is same-origin
      mode: sameOrigin ? "same-origin" : "cors",
    })
      .then((r) => (r.ok ? r.json() : null))
      .catch(() => null);
  }

  // ─── request access (empty-card CTA) ──────────────────────
  function requestAccess(app) {
    return fetch("/api/access/request", {
      credentials: "include",
      method: "POST",
      headers: { "Content-Type": "application/json", Accept: "application/json" },
      body: JSON.stringify({ app: app }),
    }).then((r) => (r.ok ? r.json() : Promise.reject(new Error("HTTP " + r.status))));
  }

  // ─── render: one room tile ────────────────────────────────
  function renderRoom(tile, room, feedData, hasAccess, signedIn) {
    // Clear any prior injected block (idempotent across reloads/SW updates)
    tile.querySelectorAll(".room-stat,.room-feed,.room-empty").forEach((n) => n.remove());

    const sub = tile.querySelector(".room-sub");
    const insertBefore = (node) =>
      sub ? tile.insertBefore(node, sub) : tile.appendChild(node);

    if (!hasAccess) {
      const box = el("div", "room-empty");
      box.appendChild(el("div", "room-empty-key", pick("Esta sala", "This room")));
      box.appendChild(
        el("div", "room-empty-line", room.empty[getLang() === "en" ? "en" : "es"])
      );
      // Signed-in members can knock — the CTA posts a request and the
      // household's admins get the note. Anonymous visitors (only seen
      // here if ANON_SEES_FEEDS is off) just follow the tile into the
      // room's own front door.
      const cta = el(
        "div", "room-empty-cta",
        signedIn ? pick("Tocar para pedir acceso →", "Tap to ask for access →")
                 : pick("Entrar →", "Step inside →")
      );
      if (signedIn) {
        cta.style.cursor = "pointer";
        cta.addEventListener("click", function (e) {
          e.preventDefault(); e.stopPropagation();
          if (cta.getAttribute("data-sent")) return;
          cta.textContent = pick("Enviando…", "Sending…");
          requestAccess(room.app).then(
            function (res) {
              cta.setAttribute("data-sent", "1");
              cta.textContent = (res && res.already)
                ? pick("Ya tienes acceso ✓", "You already have access ✓")
                : pick("Pedido enviado ✓", "Request sent ✓");
            },
            function () { cta.textContent = pick("Inténtalo otra vez", "Try again"); }
          );
        });
      }
      box.appendChild(cta);
      insertBefore(box);
      tile.setAttribute("data-state", "empty");
      return;
    }

    const norm = room.feed(feedData || {});

    // stat row (count + unit) — only when the bridge gave us a number
    if (norm.count != null) {
      const stat = el("div", "room-stat");
      stat.appendChild(el("span", "num", fmtCount(norm.count)));
      stat.appendChild(el("span", "unit", norm.unit));
      const when = ago(norm.when);
      if (when) {
        const delta = el("span", "delta", when);
        stat.appendChild(delta);
      }
      insertBefore(stat);
    }

    // latest happening
    const feed = el("div", "room-feed");
    const row = el("div", "row");
    row.appendChild(el("span", "k", pick("Lo último", "Latest")));
    const v = el("span", "v");
    if (norm.line) {
      const live = el("span", "live");
      v.appendChild(live);
      v.appendChild(document.createTextNode(norm.line));
    } else {
      v.appendChild(
        document.createTextNode(pick("en reposo · nada nuevo", "resting · nothing new"))
      );
      v.classList.add("dim");
    }
    row.appendChild(v);
    feed.appendChild(row);
    insertBefore(feed);
    tile.setAttribute("data-state", feedData ? "live" : "resting");
  }

  // ─── render: Tonight slab ─────────────────────────────────
  function renderTonight(cocina, cellar, show) {
    const slab = document.getElementById("tonight");
    if (!slab) return;

    const tonight = cocina && cocina.tonight;          // { dish, time, note, suggestedWine }
    const open = cellar && cellar.openTonight;          // { wine, bin, note }
    if (!show || (!tonight && !open)) {
      slab.hidden = true;
      slab.innerHTML = "";
      return;
    }

    slab.innerHTML = "";

    // when
    const when = el("div", "when");
    when.appendChild(el("div", "label", pick("Esta noche", "Tonight")));
    when.appendChild(el("div", "h", (tonight && tonight.time) || "·"));
    slab.appendChild(when);

    // center: dish + pairing
    const center = el("div");
    center.appendChild(
      el("div", "dish", (tonight && tonight.dish) || (open && open.wine) || pick("La mesa está puesta", "The table is set"))
    );
    const pairBits = [];
    if (tonight && tonight.suggestedWine) pairBits.push(tonight.suggestedWine);
    else if (open && open.wine) pairBits.push(open.wine);
    if (open && open.bin) pairBits.push(open.bin);
    const note = (tonight && tonight.note) || (open && open.note);
    if (pairBits.length || note) {
      const pair = el("div", "pair");
      if (pairBits.length) {
        pair.appendChild(document.createTextNode(pairBits[0]));
        if (pairBits[1]) {
          const bin = el("span", "bin", ` · ${pairBits[1]}`);
          pair.appendChild(bin);
        }
      }
      if (note) {
        pair.appendChild(el("div", null, note));
      }
      center.appendChild(pair);
    }
    slab.appendChild(center);

    // cta
    const ctas = el("div", "cta-stack");
    const a1 = document.createElement("a");
    a1.className = "cta primary";
    a1.href = "https://cocina.casam.me";
    a1.textContent = pick("Ver en la cocina", "Open in Cocina");
    ctas.appendChild(a1);
    if (open) {
      const a2 = document.createElement("a");
      a2.className = "cta ghost";
      a2.href = "https://cellar.casam.me";
      a2.textContent = pick("La cava", "The cellar");
      ctas.appendChild(a2);
    }
    slab.appendChild(ctas);

    slab.hidden = false;
  }

  // ─── boot ─────────────────────────────────────────────────
  function boot() {
    const tiles = {};
    document.querySelectorAll(".room[data-room]").forEach((t) => {
      tiles[t.getAttribute("data-room")] = t;
    });

    // Localize the room taglines + subs immediately (no need to wait on
    // the network — this is static copy that follows the language picker).
    localizeRooms();

    // Paint a quiet "loading" hint so the tiles aren't bare during fetch.
    Object.values(tiles).forEach((t) => t.setAttribute("data-state", "loading"));

    const access = getJSON("/api/access", true);
    const feeds = {};
    Object.keys(ROOMS).forEach((k) => {
      feeds[k] = getJSON(ROOMS[k].url, false);
    });

    Promise.all([access, feeds.cellar, feeds.cocina, feeds.recuerdas]).then(
      ([acc, cellar, cocina, recuerdas]) => {
        const a = acc || { user: null, grants: [] };
        const signedIn = !!a.user;
        const granted = new Set((a.grants || []).map((g) => g.app));
        const hasAccess = (app) =>
          signedIn ? granted.has(app) : ANON_SEES_FEEDS;

        const data = { cellar, cocina, recuerdas };
        Object.keys(ROOMS).forEach((k) => {
          const tile = tiles[k];
          if (!tile) return;
          renderRoom(tile, ROOMS[k], data[k], hasAccess(ROOMS[k].app), signedIn);
        });

        // Tonight is the household's shared evening — show it to anyone
        // who can see either the kitchen or the cellar.
        renderTonight(
          cocina, cellar,
          hasAccess("cocina") || hasAccess("cellar")
        );
      }
    );

    // Re-render on language change so the injected copy follows the picker.
    // Bind exactly once (boot runs again on each switch).
    const picker = document.getElementById("lang-picker");
    if (picker && !picker.__todayBound) {
      picker.__todayBound = true;
      picker.addEventListener("click", function (e) {
        const b = e.target.closest("button[data-lang]");
        if (b) setTimeout(boot, 0);
      });
    }
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", boot);
  } else {
    boot();
  }
})();
