/* tagline-rotator.js — rotate ontoref definition-phrases by audience + focus.
 *
 * Source of truth: /r/taglines.json, projected by gen-taglines.nu from
 * .ontoref/positioning/taglines.ncl (drift-checked at export). This file never
 * carries phrases — only the rotation mechanism.
 *
 * Mount:
 *   <span data-tagline-rotator data-audience="all"
 *         data-src="/r/taglines.json" data-focus-target=".tagline-focus">
 *     Sure-footed, and light on your feet.  <!-- static fallback, shown if JS/fetch fail -->
 *   </span>
 *
 * Effect: drives typed.js (typewriter) when window.Typed is present; native fade
 * otherwise; static first-phrase under prefers-reduced-motion. Hybrid driver: the
 * home mount starts on data-audience (default "all"); any element carrying
 * [data-tagline-audience="<key>"] switches the (unlocked) rotators to that queue on
 * click — reach-vs-qualification: a routing gancho, the "all" queue is curated, not
 * the union. A mount with [data-lock-audience] ignores door clicks (door/about pages).
 * Language: data-lang fixed → <html lang> → localStorage 'ontoref-lang' → 'en';
 * follows .lang-btn / [data-lang-switch] clicks and cross-tab storage changes.
 */
(function () {
  "use strict";

  var REDUCED =
    window.matchMedia &&
    window.matchMedia("(prefers-reduced-motion: reduce)").matches;

  function detectLang(el) {
    var fixed = el.getAttribute("data-lang");
    if (fixed === "es" || fixed === "en") return fixed;
    var h = (document.documentElement.lang || "").slice(0, 2).toLowerCase();
    if (h === "es" || h === "en") return h;
    try {
      var s = localStorage.getItem("ontoref-lang");
      if (s === "es" || s === "en") return s;
    } catch (e) {}
    return "en";
  }

  function focusLabel(focus, labels, lang) {
    if (!focus) return "";
    var m = labels && labels[focus];
    if (m && m[lang]) return m[lang];
    return focus.replace(/^diff-/, "").replace(/-/g, " "); // slug fallback
  }

  function Rotator(el, data) {
    this.el = el;
    this.data = (data && data.by_audience) || {};
    this.byTier = (data && data.by_tier) || {};
    this.isTier = el.hasAttribute("data-tier-rotator");
    this.focusLabels = (data && data.focus_labels) || {};
    this.audience = el.getAttribute("data-audience") || "all";
    this.lang = detectLang(el);
    var sel = el.getAttribute("data-focus-target");
    this.focusEl = sel ? document.querySelector(sel) : null;
    this.typed = null;
    this.timer = null;
    this.idx = 0;
    this.queue = [];
    this.rebuild();
  }

  Rotator.prototype.phrases = function () {
    // Tier rotator (data-tier-rotator): a parallel axis — cycle the per-tier lines
    // (0 → 1 → 2) from by_tier, ignoring the audience queue. Door clicks never
    // switch it (mount carries data-lock-audience).
    if (this.isTier) {
      var t = this.byTier;
      return [].concat(t["0"] || [], t["1"] || [], t["2"] || []);
    }
    var q = this.data[this.audience];
    if (!q || !q.length) q = this.data.all || [];
    return q;
  };

  Rotator.prototype.text = function (i) {
    if (!this.queue.length) return "";
    var p = this.queue[i % this.queue.length];
    return p ? p[this.lang] || p.en || "" : "";
  };

  Rotator.prototype.renderFocus = function (i) {
    if (!this.focusEl || !this.queue.length) return;
    var p = this.queue[i % this.queue.length];
    this.focusEl.textContent = p ? focusLabel(p.focus, this.focusLabels, this.lang) : "";
  };

  Rotator.prototype.render = function (i) {
    this.el.textContent = this.text(i);
    this.renderFocus(i);
  };

  Rotator.prototype.rebuild = function () {
    this.stop();
    this.queue = this.phrases();
    this.idx = 0;
    if (!this.queue.length) {
      this.el.textContent = "";
      return;
    }
    if (REDUCED) {
      this.render(0); // honour reduced-motion: show one phrase, never animate
      return;
    }
    if (window.Typed) this.startTyped();
    else this.startFade();
  };

  Rotator.prototype.startTyped = function () {
    var self = this;
    var strings = this.queue.map(function (_, i) {
      // escape typed.js control chars: ^ (pause), ` (html), ~ (smart-backspace)
      return self.text(i).replace(/([\^`~])/g, "\\$1");
    });
    this.renderFocus(0);
    this.typed = new window.Typed(this.el, {
      strings: strings,
      typeSpeed: 38,
      backSpeed: 16,
      backDelay: 2400,
      startDelay: 250,
      smartBackspace: true,
      loop: true,
      cursorChar: "▌",
      preStringTyped: function (i) {
        self.renderFocus(i);
      },
    });
  };

  Rotator.prototype.startFade = function () {
    var self = this;
    this.render(0);
    this.el.classList.add("tagline-rot", "is-in");
    this.timer = setInterval(function () {
      self.el.classList.remove("is-in");
      setTimeout(function () {
        self.idx = (self.idx + 1) % self.queue.length;
        self.render(self.idx);
        self.el.classList.add("is-in");
      }, 350);
    }, 3800);
  };

  Rotator.prototype.stop = function () {
    if (this.typed) {
      this.typed.destroy();
      this.typed = null;
    }
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
  };

  Rotator.prototype.setAudience = function (key) {
    if (!key || key === this.audience) return;
    this.audience = key;
    this.rebuild();
  };

  Rotator.prototype.setLang = function (lang) {
    if ((lang !== "es" && lang !== "en") || lang === this.lang) return;
    this.lang = lang;
    this.rebuild();
  };

  function init() {
    var mounts = [].slice.call(
      document.querySelectorAll("[data-tagline-rotator]"),
    );
    if (!mounts.length) return;
    var src = mounts[0].getAttribute("data-src") || "/r/taglines.json";

    fetch(src, { credentials: "same-origin" })
      .then(function (r) {
        if (!r.ok) throw new Error("taglines " + r.status);
        return r.json();
      })
      .then(function (data) {
        var rotators = mounts.map(function (el) {
          return new Rotator(el, data);
        });
        window.__taglineRotators = rotators;

        // Hybrid driver — door affordances switch the unlocked rotators' audience.
        document.addEventListener("click", function (ev) {
          var t =
            ev.target.closest && ev.target.closest("[data-tagline-audience]");
          if (!t) return;
          var key = t.getAttribute("data-tagline-audience");
          var group = t.parentNode;
          if (group)
            [].forEach.call(
              group.querySelectorAll("[data-tagline-audience]"),
              function (b) {
                b.classList.toggle("is-active", b === t);
              },
            );
          // reveal the matching door panel; data-door="all" hides every panel
          var door = t.getAttribute("data-door");
          if (door !== null)
            [].forEach.call(
              document.querySelectorAll("[data-tagline-panel]"),
              function (p) {
                var match = p.getAttribute("data-tagline-panel") === door;
                p.classList.toggle("is-open", match); // class wins over any [hidden] override
                p.hidden = !match;
              },
            );
          rotators.forEach(function (rt) {
            if (!rt.el.hasAttribute("data-lock-audience")) rt.setAudience(key);
          });
        });

        // Language — follow the web lang toggle and cross-tab changes.
        document.addEventListener("click", function (ev) {
          var b =
            ev.target.closest &&
            ev.target.closest(".lang-btn, [data-lang-switch]");
          if (!b) return;
          var lang =
            b.getAttribute("data-lang") || b.getAttribute("data-lang-switch");
          rotators.forEach(function (rt) {
            rt.setLang(lang);
          });
        });
        window.addEventListener("storage", function (ev) {
          if (ev.key === "ontoref-lang" && ev.newValue)
            rotators.forEach(function (rt) {
              rt.setLang(ev.newValue);
            });
        });
      })
      .catch(function (e) {
        // leave the static fallback text in each mount untouched
        if (window.console) console.warn("[tagline-rotator]", e.message);
      });
  }

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