/* global React, window */
// =========================================================
// v4 · "Ask MakerLab" finding context.
// When a finding is pinned into the chat, MakerLab knows which
// finding it's looking at and offers ~3 grounded prompts. Every
// answer is generated from the real study numbers carried in the
// findings (REAL_FINDINGS) + the open-text synthesis (VERBATIM),
// not a canned string — so the same engine answers any pinned
// finding with its own data.
//
// Three answer shapes, matching the three things people ask here:
//   · compare   — one style read across the four accounts / cuts
//   · spread    — dig into a franchise's make-ups (what to cut)
//   · synthetic — model a make-up the line hasn't fielded yet
// =========================================================
(function () {
  const PI = window.PRODUCT_IMAGES;
  const img = (id) => (PI ? PI.url(id) : null);

  // ---- Accounts / cuts (avg buy-consideration, from O4 findings) ----
  const ACCOUNTS = [
    { key: "gola", label: "Gola consumers", avg: 61, n: 159, note: "enthusiast ceiling" },
    { key: "anthro", label: "Anthropologie", avg: 58, n: 206, note: "warm read" },
    { key: "fp", label: "Free People", avg: 57, n: 270, note: "tracks Anthro" },
    { key: "dept", label: "Dept. stores", avg: 56, n: 373, note: "sell-in baseline" },
  ];

  // ---- Per-style scores by account (from the O4 account findings) ----
  // overall = all-respondent score (from the O3 design findings).
  const STYLES = {
    "Hawk Twill":      { fr: "hawk", img: "69f113d473c424d01687b8da", overall: 72, by: { gola: 82, anthro: 77, fp: 76, dept: 73 } },
    "Sprinter Reflect":{ fr: "sprinter", img: "69f113d473c424d01687b8f0", overall: 67, by: { anthro: 70, fp: 71, dept: 68 } },
    "Championship":    { fr: "championship", img: "69f113d473c424d01687b902", overall: null, by: { anthro: 72, fp: 71, dept: 68 } },
    "Delta Tonal":     { fr: "delta", img: "69f113d473c424d01687b8ee", overall: null, by: { gola: 73, fp: 70 } },
    "Clora Mule":      { fr: "clora", img: "69f113d473c424d01687b8f8", overall: 36, by: { gola: 39, anthro: 30, fp: 33, dept: 34 } },
  };

  // ---- Franchise make-up tables (scores from the O3 design findings) ----
  const FRANCHISES = {
    hawk: {
      label: "Hawk", leader: "Hawk Twill", range: [53, 72],
      lesson: "The print, not the silhouette, is what people buy — twill swings the same shoe +19.",
      makeups: [
        { name: "Hawk Twill", score: 72, treat: "twill print", lean: "strong", img: "69f113d473c424d01687b8da" },
        { name: "Hawk", score: 53, treat: "earth multi", lean: "weak", img: "69f113d473c424d01687b8dc" },
      ],
    },
    sprinter: {
      label: "Sprinter", leader: "Sprinter Reflect", range: [48, 67],
      lesson: "Widest spread in the line — the reflective treatment earns its place; the outdoor make-up is the edit candidate.",
      makeups: [
        { name: "Sprinter Reflect", score: 67, treat: "reflective", lean: "strong", img: "69f113d473c424d01687b8f0" },
        { name: "Sprinter Tonal", score: 63, treat: "tonal white", lean: "mixed", img: "69f113d473c424d01687b8f4" },
        { name: "Sprinter Satin", score: 61, treat: "gold satin", lean: "mixed", img: "69f113d473c424d01687b8f6" },
        { name: "Sprinter Quilt", score: 59, treat: "yellow quilt", lean: "mixed", img: "69f113d473c424d01687b90c" },
        { name: "Sprinter Reflect (alt)", score: 56, treat: "yellow reflect", lean: "mixed", img: "69f113d473c424d01687b8f2" },
        { name: "Sprinter Outdoor", score: 48, treat: "orange trail", lean: "weak", img: "69f113d473c424d01687b918" },
      ],
    },
    amera: {
      label: "Amera", leader: "Amera Satin", range: [49, 63],
      lesson: "Splits cleanly by material — satin and quilt carry it; both mesh executions are the floor.",
      makeups: [
        { name: "Amera Satin", score: 63, treat: "metallic satin", lean: "strong", img: "69f113d473c424d01687b900" },
        { name: "Amera", score: 61, treat: "clean low", lean: "mixed", img: "69f113d473c424d01687b8fe" },
        { name: "Amera Quilt", score: 61, treat: "quilt", lean: "mixed", img: "69f113d473c424d01687b90e" },
        { name: "Amera Mesh", score: 51, treat: "brown mesh", lean: "weak", img: "69f113d473c424d01687b91a" },
        { name: "Amera Mesh (alt)", score: 49, treat: "yellow mesh", lean: "weak", img: "69f113d473c424d01687b91c" },
      ],
    },
    celestra: {
      label: "Celestra", leader: "Celestra Quilt", range: [43, 48],
      lesson: "The problem is the silhouette, not the color — all three quilt make-ups sit at the floor. No treatment rescues a flat ballet build.",
      makeups: [
        { name: "Celestra Quilt", score: 48, treat: "quilt ballet", lean: "weak", img: "69f113d473c424d01687b8fa" },
        { name: "Celestra Quilt (alt)", score: 46, treat: "quilt ballet", lean: "weak", img: "69f113d473c424d01687b910" },
        { name: "Celestra Quilt (alt 2)", score: 43, treat: "quilt ballet", lean: "weak", img: "69f113d473c424d01687b912" },
      ],
    },
    trakstar: {
      label: "Trakstar", leader: "Trakstar", range: [43, 54],
      lesson: "Over-built make-ups sink — the simpler base reads 11 points above the strappy Flex.",
      makeups: [
        { name: "Trakstar", score: 54, treat: "base red/blue", lean: "mixed", img: "69f113d473c424d01687b8fc" },
        { name: "Trakstar Flex", score: 43, treat: "strappy / open", lean: "weak", img: "69f113d473c424d01687b906" },
      ],
    },
  };

  // ---- Synthetic proposals: a make-up the line hasn't fielded, grounded
  // in the franchise's tested range + the treatment priors it has learned. ----
  const SYNTH = {
    hawk: {
      name: "Hawk Suede", treat: "tonal suede upper",
      effect: +4, band: 6,
      basis: "2 fielded Hawk make-ups + surface-treatment priors (twill +19, busy multi −19)",
      attrs: [
        { k: "Upper", v: "up", t: "Suede reads premium and lands between the twill hero and the busy base — the texture does what twill does without the print risk." },
        { k: "Color", v: "up", t: "A single tonal colorway dodges the “too many colors” gripe that drags the standard Hawk." },
        { k: "Risk", v: "flat", t: "Suede durability questions in an everyday sneaker — pair with a cleanable finish in the brief." },
      ],
      quote: "Looks more expensive than the others — I’d wear the tonal one.",
    },
    sprinter: {
      name: "Sprinter Knit", treat: "engineered knit upper",
      effect: +2, band: 7,
      basis: "6 fielded Sprinter make-ups + treatment priors (reflective +, outdoor −)",
      attrs: [
        { k: "Upper", v: "up", t: "Knit reads light and modern, in the clean-base lane that already wins for Sprinter." },
        { k: "Color", v: "flat", t: "Keep it tonal — the franchise punishes novelty brights (orange Outdoor is the floor)." },
        { k: "Risk", v: "down", t: "Knit can read too athletic for the fashion positioning; hold the sole clean." },
      ],
      quote: "Comfy-looking and simple — but don’t make it loud.",
    },
    amera: {
      name: "Amera Cord", treat: "corduroy upper",
      effect: +5, band: 6,
      basis: "5 fielded Amera make-ups + material priors (satin +, mesh −12)",
      attrs: [
        { k: "Material", v: "up", t: "Corduroy sits with satin on the premium side of Amera's material split — clearly above mesh." },
        { k: "Color", v: "up", t: "Pastel / metallic palettes are what people said they'd wear here; cord carries them well." },
        { k: "Sole", v: "flat", t: "Add a touch of height — the clean low draws “add a chunkier sole.”" },
      ],
      quote: "The texture's nice — feels like the metallic one I liked.",
    },
    celestra: {
      name: "Celestra Low", treat: "low sneaker silhouette (drop the ballet flat)",
      effect: +12, band: 8,
      basis: "3 fielded Celestra quilts (all capped) + the franchise's silhouette lesson",
      attrs: [
        { k: "Silhouette", v: "up", t: "This is the lever: a real low sneaker escapes the “looks like ballerina shoes” ceiling that caps every quilt make-up." },
        { k: "Color", v: "flat", t: "Color was never the problem here — carry the existing palette." },
        { k: "Risk", v: "down", t: "Biggest unknown in the line — confidence is wide because no Celestra sneaker has been fielded." },
      ],
      quote: "If it were an actual sneaker and not a flat, I'd consider it.",
    },
    trakstar: {
      name: "Trakstar Clean", treat: "closed, simplified construction",
      effect: +6, band: 6,
      basis: "2 fielded Trakstar make-ups + the line-wide “simpler reads win” prior",
      attrs: [
        { k: "Construction", v: "up", t: "Closing the open straps moves it toward the steadier base, away from the polarizing Flex." },
        { k: "Color", v: "flat", t: "Rework the red/blue toward a calmer combo; color was a secondary gripe." },
        { k: "Risk", v: "flat", t: "Trakstar is unremarkable even at its best — a clean make-up lifts the floor, not the ceiling." },
      ],
      quote: "Better without all the straps — looks wearable now.",
    },
  };

  // ---- Retailer-cut effect sizes (segmentation strength), from the
  // seg/gap findings. Higher ES = stronger, more divergent segmentation. ----
  const OVERALL_ES = 0.0574;
  const RETAILER_CUTS = [
    { label: "Small boutiques", es: 0.090, n: 97 },
    { label: "Anthropologie", es: 0.082, n: 103 },
    { label: "Free People", es: 0.076, n: 133 },
    { label: "Brand sites / stores", es: 0.074, n: 197 },
    { label: "Dept. stores", es: 0.072, n: 192 },
    { label: "Specialty retail", es: 0.065, n: 192 },
    { label: "Amazon / online", es: 0.065, n: 195 },
    { label: "Madewell", es: 0.057, n: 73 },
  ];

  const ACC_BY_KEY = {};
  ACCOUNTS.forEach((a) => { ACC_BY_KEY[a.key] = a; });
  const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));

  // ---- Resolve a pinned finding → its subject (franchise / account / segment) ----
  function meta(f) {
    if (!f || !f.id) return { kind: "other" };
    const head = String(f.id).split("::")[0];
    const seg = head.split("|").pop();
    if (f.lens === "design") return { kind: "design", franchise: head.split("|")[1] };
    if (f.lens === "account") return { kind: "account", account: seg === "accounts" ? null : seg };
    return { kind: "seg", segment: seg };
  }

  // =====================================================================
  // Prompt sets — ~3 per finding, framed to its subject.
  // =====================================================================
  function presetsFor(f) {
    const m = meta(f);
    if (m.kind === "design" && FRANCHISES[m.franchise]) {
      const F = FRANCHISES[m.franchise];
      const list = [
        { kind: "spread", q: `Which ${F.label} make-ups should we cut?` },
        { kind: "synthetic", q: `Spin up synthetic research on a ${F.label} make-up we haven't tested` },
      ];
      if (STYLES[F.leader]) list.unshift({ kind: "compare", q: `How does ${F.leader} read across our four accounts?` });
      return list;
    }
    if (m.kind === "account") {
      return [
        { kind: "compare", q: `How does Hawk Twill read across our four accounts?` },
        { kind: "acctHeroes", q: m.account ? `What are ${ACC_LABEL(m.account)}'s heroes and floors?` : `Which styles hold across every account?` },
        { kind: "synthetic", q: `Spin up synthetic research on a Hawk make-up we haven't tested` },
      ];
    }
    // segmentation / channel / hierarchy findings
    return [
      { kind: "segHold", q: `Does this hold across the retailer cuts?` },
      { kind: "compare", q: `How does Hawk Twill read across our four accounts?` },
      { kind: "synthetic", q: `Spin up synthetic research on a Hawk make-up we haven't tested` },
    ];
  }

  function ACC_LABEL(key) {
    const hit = ACCOUNTS.find((a) => a.key === key || a.label.toLowerCase().indexOf(String(key).toLowerCase()) === 0);
    return hit ? hit.label : key;
  }
  function accKeyFromName(name) {
    const n = String(name).toLowerCase();
    if (n.indexOf("gola") === 0) return "gola";
    if (n.indexOf("anthro") === 0) return "anthro";
    if (n.indexOf("free") === 0) return "fp";
    if (n.indexOf("dep") === 0) return "dept";
    return null;
  }

  // =====================================================================
  // Renderers (live inside the AI chat bubble)
  // =====================================================================
  function ScoreBar({ score, max, tone }) {
    return (
      <div className="gl-ml-bar">
        <div className={"gl-ml-bar__fill gl-ml-bar__fill--" + (tone || "mid")} style={{ width: clamp((score / (max || 100)) * 100, 4, 100) + "%" }}></div>
      </div>
    );
  }

  function CompareCard({ style }) {
    const S = STYLES[style];
    if (!S) return null;
    const rows = ACCOUNTS.filter((a) => S.by[a.key] != null);
    const vals = rows.map((a) => S.by[a.key]);
    const hi = Math.max.apply(null, vals), lo = Math.min.apply(null, vals);
    return (
      <div className="gl-ml-card">
        <div className="gl-ml-card__head">
          {img(S.img) && <img className="gl-ml-thumb" src={img(S.img)} alt={style} />}
          <div>
            <div className="gl-ml-card__title">{style}</div>
            <div className="gl-ml-card__sub">Buy-consideration by account{S.overall != null ? ` · ${S.overall} overall` : ""}</div>
          </div>
        </div>
        <div className="gl-ml-rows">
          {rows.map((a) => {
            const v = S.by[a.key];
            const tone = v === hi ? "hi" : v === lo ? "lo" : "mid";
            return (
              <div className="gl-ml-row" key={a.key}>
                <span className="gl-ml-row__lab">{a.label}</span>
                <ScoreBar score={v} max={100} tone={tone} />
                <span className="gl-ml-row__val">{v}</span>
              </div>
            );
          })}
        </div>
        <div className="gl-ml-foot">
          Spread of {hi - lo} pts across accounts — {hi - lo <= 6 ? "merchandise it everywhere; the read barely moves." : "weight it to the accounts where it over-indexes."}
        </div>
      </div>
    );
  }

  function SpreadCard({ franchise }) {
    const F = FRANCHISES[franchise];
    if (!F) return null;
    const sorted = F.makeups.slice().sort((a, b) => b.score - a.score);
    const hi = sorted[0].score, lo = sorted[sorted.length - 1].score;
    const cut = sorted.filter((m) => m.lean === "weak");
    const fv = window.VERBATIM ? window.VERBATIM.BY_FRANCHISE[franchise] : null;
    return (
      <div className="gl-ml-card">
        <div className="gl-ml-card__head">
          <div>
            <div className="gl-ml-card__title">{F.label} · {sorted.length} make-ups</div>
            <div className="gl-ml-card__sub">{hi - lo}-pt spread · {lo}–{hi}</div>
          </div>
        </div>
        <div className="gl-ml-rows">
          {sorted.map((mk) => {
            const tone = mk.lean === "strong" ? "hi" : mk.lean === "weak" ? "lo" : "mid";
            return (
              <div className="gl-ml-row gl-ml-row--mk" key={mk.name}>
                {img(mk.img) && <img className="gl-ml-mkthumb" src={img(mk.img)} alt={mk.name} />}
                <span className="gl-ml-row__lab">{mk.name}<span className="gl-ml-row__treat">{mk.treat}</span></span>
                <ScoreBar score={mk.score} max={100} tone={tone} />
                <span className="gl-ml-row__val">{mk.score}</span>
              </div>
            );
          })}
        </div>
        <div className="gl-ml-rec">
          <span className="gl-ml-rec__tag">{cut.length ? "Cut candidates" : "Hold the line"}</span>
          <span>{cut.length
            ? cut.map((m) => m.name).join(", ") + " — " + F.lesson
            : F.lesson}</span>
        </div>
        {fv && <div className="gl-ml-quote">“{fv.quotes[fv.quotes.length - 1]}”</div>}
      </div>
    );
  }

  function RetailerCutsCard() {
    const max = 0.11;
    return (
      <div className="gl-ml-card gl-ml-es">
        <div className="gl-ml-card__head">
          <div>
            <div className="gl-ml-card__title">Buy-consideration by retailer shopped</div>
            <div className="gl-ml-card__sub">Effect size · higher = stronger segmentation</div>
          </div>
        </div>
        <div className="gl-ml-rows">
          {RETAILER_CUTS.map((c) => {
            const tone = c.es >= 0.08 ? "hi" : c.es <= OVERALL_ES + 0.001 ? "lo" : "mid";
            return (
              <div className="gl-ml-row" key={c.label}>
                <span className="gl-ml-row__lab">{c.label}<span className="gl-ml-row__treat">n = {c.n}</span></span>
                <ScoreBar score={c.es} max={max} tone={tone} />
                <span className="gl-ml-row__val">{c.es.toFixed(3)}</span>
              </div>
            );
          })}
          <div className="gl-ml-row gl-ml-row--base">
            <span className="gl-ml-row__lab">Overall baseline</span>
            <ScoreBar score={OVERALL_ES} max={max} tone="base" />
            <span className="gl-ml-row__val">{OVERALL_ES.toFixed(3)}</span>
          </div>
        </div>
        <div className="gl-ml-foot">Every retailer cut sits at or above the overall baseline ({OVERALL_ES.toFixed(3)}) — small boutiques and Anthropologie segment hardest. The pattern is consistent, not a one-segment artifact.</div>
      </div>
    );
  }

  function SyntheticCard({ franchise }) {
    const F = FRANCHISES[franchise];
    const P = SYNTH[franchise];
    if (!F || !P) return null;
    const mid = Math.round((F.range[0] + F.range[1]) / 2);
    const score = clamp(mid + P.effect, 30, 85);
    const v = (x) => x === "up" ? "▲" : x === "down" ? "▼" : "—";
    return (
      <div className="gl-ml-card gl-ml-synth">
        <div className="gl-ml-synth__flag">
          <span className="gl-ml-synth__dot"></span> Synthetic · model estimate, not fielded
        </div>
        <div className="gl-ml-card__head">
          <div className="gl-ml-synth__ph" aria-hidden="true"><span>untested<br/>make-up</span></div>
          <div>
            <div className="gl-ml-card__title">{P.name}</div>
            <div className="gl-ml-card__sub">{P.treat}</div>
          </div>
        </div>
        <div className="gl-ml-synth__scorebar">
          <div className="gl-ml-synth__score">{score}<span>est.</span></div>
          <div className="gl-ml-synth__band">
            <ScoreBar score={score} max={100} tone="syn" />
            <div className="gl-ml-synth__range">likely {clamp(score - P.band, 30, 85)}–{clamp(score + P.band, 30, 85)} · vs {F.label} field {F.range[0]}–{F.range[1]}</div>
          </div>
        </div>
        <div className="gl-ml-attrs">
          {P.attrs.map((a) => (
            <div className="gl-ml-attr" key={a.k}>
              <span className={"gl-ml-attr__v gl-ml-attr__v--" + a.v}>{v(a.v)}</span>
              <span className="gl-ml-attr__k">{a.k}</span>
              <span className="gl-ml-attr__t">{a.t}</span>
            </div>
          ))}
        </div>
        <div className="gl-ml-quote gl-ml-quote--syn">“{P.quote}”<span className="gl-ml-quote__src">synthetic respondent</span></div>
        <div className="gl-ml-synth__basis">Basis · {P.basis}</div>
        <button className="gl-ml-synth__cta" onClick={(e) => e.preventDefault()}>Field this make-up →</button>
      </div>
    );
  }

  // =====================================================================
  // answerFor — pick the shape, return { node, confidence, sources }
  // =====================================================================
  function answerFor(f, preset) {
    const m = meta(f);
    const fr = m.franchise && FRANCHISES[m.franchise] ? m.franchise
      : (m.kind === "design" ? "hawk" : "hawk");
    const k = preset.kind;

    if (k === "compare") {
      const style = (m.kind === "design" && FRANCHISES[m.franchise] && STYLES[FRANCHISES[m.franchise].leader])
        ? FRANCHISES[m.franchise].leader : "Hawk Twill";
      return {
        text: `Reading ${style} across the four accounts you sell into:`,
        node: <CompareCard style={style} />,
        confidence: "High", sources: ["Buy-consideration × account (O4)", "Product ratings"],
      };
    }
    if (k === "spread") {
      return {
        text: `Here's the full ${FRANCHISES[fr].label} make-up ladder, ranked:`,
        node: <SpreadCard franchise={fr} />,
        confidence: "High", sources: ["Within-franchise ratings (O3)", "Open-text synthesis"],
      };
    }
    if (k === "synthetic") {
      return {
        text: `Modeling a ${FRANCHISES[fr].label} make-up we haven't fielded — estimated from the tested range plus what the line has taught us about treatments:`,
        node: <SyntheticCard franchise={fr} />,
        confidence: "Synthetic", sources: ["Treatment priors", "Franchise score distribution"],
      };
    }
    if (k === "acctHeroes") {
      const accKey = m.account ? accKeyFromName(m.account) : null;
      if (accKey === "anthro") return { text: "Anthropologie reads the line warmly (avg 58). Heroes: Hawk Twill (77), Championship (72), Sprinter Reflect (70), with Sprinter Satin over-indexing (69). Floor: Clora Mule (30), rejected as firmly as everywhere else.", confidence: "High", sources: ["Anthropologie shoppers (O4)"] };
      if (accKey === "fp") return { text: "Free People tracks Anthropologie closely (avg 57). Heroes: Hawk Twill (76), Sprinter Reflect (71), Championship (71), Delta Tonal (70). Floor: Clora Mule (33) and the Celestra quilts (40).", confidence: "High", sources: ["Free People shoppers (O4)"] };
      if (accKey === "dept") return { text: "Department-store shoppers are the toughest crowd (avg 56) — your conservative sell-in read. Same heroes hold (Hawk Twill 73, Sprinter Reflect 68, Championship 68) but the floor is harsher: Trakstar Flex (38), Clora Mule (34).", confidence: "High", sources: ["Department-store shoppers (O4)"] };
      if (accKey === "gola") return { text: "Gola consumers are the enthusiast ceiling (avg 61) — treat as a high read, not a forecast. Hawk Twill hits 82 here (highest in the study); loyalty lifts Delta (73) and Elan (72). Even this warm crowd puts Clora Mule last (39).", confidence: "High", sources: ["Gola affinity (O4)"] };
      return {
        text: "Two verdicts hold across every account: Hawk Twill is the universal hero (#1 for all four) and the Clora Mule is the universal floor (last in all four). Generosity ranks Gola (61) > Anthropologie (58) > Free People (57) > Dept. stores (56).",
        node: <CompareCard style="Hawk Twill" />,
        confidence: "High", sources: ["Cross-account agreement (O4)"],
      };
    }
    if (k === "segHold") {
      return {
        text: "Yes — the segmentation holds across the retailer cuts. Every account-relevant cut sits at or above the overall baseline:",
        node: <RetailerCutsCard />,
        confidence: "Moderate", sources: ["Effect size × retailer shopped"],
      };
    }
    // free-text / fallback — ground it in the pinned finding
    return {
      text: `On "${f.statement}" — ${trimProse(f.prose)} Want me to read it across accounts, ladder the make-ups, or model an untested one?`,
      confidence: f.sig === "high" ? "High" : "Moderate",
      sources: [f.lensLabel || "This finding"],
    };
  }

  function trimProse(p) {
    if (!p) return "";
    const first = String(p).split(/(?<=\.)\s/)[0];
    return first.length > 220 ? first.slice(0, 217) + "…" : first;
  }

  function greetingFor(f) {
    const m = meta(f);
    if (m.kind === "design" && FRANCHISES[m.franchise]) {
      return `Pinned the ${FRANCHISES[m.franchise].label} read. Ask me to compare its hero across accounts, ladder the make-ups, or spin up synthetic research on one you haven't fielded.`;
    }
    if (m.kind === "account") {
      return `Pinned this account read. I can compare a style across all four accounts, pull this account's heroes and floors, or model an untested make-up.`;
    }
    return `Pinned "${f.statement}". Ask me to compare a style across accounts, dig into a franchise, or model an untested make-up.`;
  }

  window.MakerLabCtx = { presetsFor, answerFor, greetingFor, meta };
})();
