/* global React, StudyData */

// =========================================================
// Raw Results view — real data from study.json
// Left rail: Sections (Survey insights stubs + Raw results subsections)
// Center: question cards OR product carousel depending on section
// Right: filter panel (real cross-tabs on per-respondent data)
// =========================================================

// ---- Sneaker silhouette family color mapping ----
const FAMILY_COLORS = {
  Hawk:        { bg: "#E8D9C4", fg: "#5A3F2B", abbrev: "HK" },
  Sprinter:    { bg: "#D6E2D4", fg: "#3D5A3A", abbrev: "SP" },
  Delta:       { bg: "#E8DCDC", fg: "#7A3F3F", abbrev: "DE" },
  Elan:        { bg: "#DDD8E6", fg: "#4A3F6E", abbrev: "EL" },
  Amera:       { bg: "#E6E0CF", fg: "#6E5A2E", abbrev: "AM" },
  Viper:       { bg: "#CFD8DE", fg: "#2F4A5C", abbrev: "VI" },
  Trakstar:    { bg: "#E5D6CF", fg: "#7A4A35", abbrev: "TK" },
  Championship:{ bg: "#D8DBE0", fg: "#3A4456", abbrev: "CH" },
  Celestra:    { bg: "#E0D6E0", fg: "#5A3F6E", abbrev: "CE" },
  Clora:       { bg: "#E6D7DA", fg: "#7A3F4C", abbrev: "CL" },
  Badminton:   { bg: "#D8E0D2", fg: "#3F5A35", abbrev: "BD" },
  default:     { bg: "#E0E0E0", fg: "#444", abbrev: "??" },
};

function productFamily(title) {
  const first = (title || "").split(" ")[0];
  return FAMILY_COLORS[first] || FAMILY_COLORS.default;
}

// ---- Section definitions (left rail) ----
const SURVEY_INSIGHTS_STUBS = [
  { id: "sentiment",  label: "Consumer sentiment", ti: "heart", icon: "♡", stub: "AI-summarized sentiment across the panel — what consumers feel, in their own words." },
  { id: "efficiency", label: "Line efficiency",    ti: "chart-line", icon: "↗", stub: "Which products in the line earn their slot vs cannibalize each other — coming soon." },
  { id: "head",       label: "Head to head",       ti: "circles-relation", icon: "⇄", stub: "Compare any two products side-by-side across every question — coming soon." },
  { id: "buckets",    label: "Buckets",            ti: "stack-2", icon: "☰", stub: "Group products into go / hold / kill buckets based on signal — coming soon." },
];

// ---- Active study config (filter facets + demo question split). ----
// Defaults reproduce the Gola study exactly; the app overrides via
// window.ACTIVE_STUDY_CFG for other studies.
function activeCfg() {
  return (typeof window !== "undefined" && window.ACTIVE_STUDY_CFG) || {
    demoQuestionIds: ["q19", "q20"],
    demoFacets: [
      { field: "age", label: "Age" },
      { field: "gender", label: "Gender" },
      { field: "country", label: "Country", limit: 6 },
    ],
    answerFacets: [],
  };
}

// ---- Main component ----
function RawResultsView() {
  const [loaded, setLoaded] = React.useState(false);
  const [data, setData] = React.useState(null);
  const [activeSection, setActiveSection] = React.useState({ kind: "survey", id: "main" });
  const [filtersOpen, setFiltersOpen] = React.useState(true);
  const [filters, setFilters] = React.useState({ demo: {}, answers: {} });
  const [sortMode, setSortMode] = React.useState({});
  const [traceNote, setTraceNote] = React.useState(null);
  const [productTarget, setProductTarget] = React.useState(null);
  const store = React.useContext(window.PinContext);

  React.useEffect(() => {
    StudyData.load().then((d) => { setData(d); setLoaded(true); });
  }, []);

  // ---- Apply a deep link from a Findings card (question + filter) ----
  const intent = store && store.dataIntent;
  React.useEffect(() => {
    if (!loaded || !intent) return;
    if (intent.section === "sentiment") {
      setActiveSection({ kind: "stub", id: "sentiment" });
    } else if (intent.section === "product") {
      setActiveSection({ kind: "product", id: "product" });
      setProductTarget({ productId: intent.productId, pqTitle: intent.pqTitle, key: Date.now() });
    } else if (intent.section === "question") {
      const demoIds = (window.ACTIVE_STUDY_CFG && window.ACTIVE_STUDY_CFG.demoQuestionIds) || ["q19", "q20"];
      const isDemo = demoIds.indexOf(intent.qid) >= 0;
      setActiveSection({ kind: isDemo ? "demo" : "survey", id: isDemo ? "demo" : "main" });
    }
    if (intent.filter) {
      const fresh = { demo: {}, answers: {} };
      Object.entries(intent.filter.demo || {}).forEach(([k, v]) => { fresh.demo[k] = new Set(v); });
      Object.entries(intent.filter.answers || {}).forEach(([k, v]) => { fresh.answers[k] = new Set(v); });
      setFilters(fresh);
      setFiltersOpen(true);
    } else {
      setFilters({ demo: {}, answers: {} });
    }
    setTraceNote({
      statement: intent.statement,
      sourceLabel: intent.sourceLabel,
      cutLabel: intent.cutLabel,
      fromId: intent.fromId,
    });
    let n = 0;
    const tick = () => {
      const parent = document.querySelector("[data-rr-scroll]");
      if (!parent) return;
      if (intent.section === "question") {
        const el = document.getElementById("rr-q-" + intent.qid);
        if (el && el.getBoundingClientRect().height > 0) {
          const top = el.getBoundingClientRect().top - parent.getBoundingClientRect().top + parent.scrollTop - 14;
          parent.scrollTo({ top, behavior: n === 0 ? "auto" : "smooth" });
        }
      } else if (n === 0) {
        parent.scrollTo({ top: 0 });
      }
      n += 1;
      if (n < 9) setTimeout(tick, 140);
    };
    setTimeout(tick, 100);
    store.setDataIntent(null);
  }, [loaded, intent]);

  if (!loaded) {
    return <div className="rr-loading">Loading study data…</div>;
  }

  // ----- Compute filtered respondents -----
  const filtered = StudyData.filterRespondents(filters);
  const totalShown = filtered.length;
  const totalAll = data.respondents.length;
  const filterCount =
    Object.values(filters.demo).reduce((n, s) => n + s.size, 0) +
    Object.values(filters.answers).reduce((n, s) => n + s.size, 0);

  // ----- Section definitions (derived from real data) -----
  const cfg = activeCfg();
  const demoIds = cfg.demoQuestionIds || ["q19", "q20"];
  const mainQuestions = data.questions.filter((q) => demoIds.indexOf(q.id) < 0);
  const demoQuestions = data.questions.filter((q) => demoIds.indexOf(q.id) >= 0);
  const rawSections = [
    { id: "main",    label: "Survey questions", count: mainQuestions.length, kind: "questions", questions: mainQuestions },
    { id: "product", label: "Product Section",  count: (data.product_questions || []).length, kind: "product", pqs: data.product_questions || [] },
    { id: "demo",    label: "Demographics",     count: demoQuestions.length, kind: "questions", questions: demoQuestions },
  ];

  // ----- Filter toggles -----
  function toggleDemo(field, value) {
    setFilters((f) => {
      const next = { ...f.demo };
      const cur = new Set(next[field] || []);
      cur.has(value) ? cur.delete(value) : cur.add(value);
      if (cur.size === 0) delete next[field]; else next[field] = cur;
      return { ...f, demo: next };
    });
  }
  function toggleAnswer(qid, label) {
    setFilters((f) => {
      const next = { ...f.answers };
      const cur = new Set(next[qid] || []);
      cur.has(label) ? cur.delete(label) : cur.add(label);
      if (cur.size === 0) delete next[qid]; else next[qid] = cur;
      return { ...f, answers: next };
    });
  }
  function applyProfile(profile) {
    // Replace filters with profile's filter spec (cloning sets)
    const fresh = { demo: {}, answers: {} };
    Object.entries(profile.filter.demo || {}).forEach(([k, s]) => { fresh.demo[k] = new Set(s); });
    Object.entries(profile.filter.answers || {}).forEach(([k, s]) => { fresh.answers[k] = new Set(s); });
    setFilters(fresh);
  }
  function clearFilters() { setFilters({ demo: {}, answers: {} }); setTraceNote(null); }

  return (
    <div className="rr">
      <div className="rr__body">
        {/* Left rail: Sections */}
        <SectionsRail
          surveyInsights={SURVEY_INSIGHTS_STUBS}
          rawSections={rawSections}
          activeSection={activeSection}
          onSelect={(s) => { setTraceNote(null); setActiveSection(s); }}
        />

        {/* Center */}
        <div data-rr-scroll className="rr__center">
          {!filtersOpen && (
          <div className="rr__center-head">
            {filterCount > 0 && (
              <button className="rr__clear" onClick={clearFilters}>× Clear filters</button>
            )}
            <button
              className={"rr__filter-toggle" + (filtersOpen ? " is-active" : "")}
              onClick={() => setFiltersOpen((v) => !v)}
              title="Expand filters" aria-label="Expand filters"
            >
              <i className="ti ti-layout-sidebar-right-expand"></i>
              {filterCount > 0 && <span className="rr__filter-count">{filterCount}</span>}
            </button>
          </div>
          )}
          {traceNote && (
            <div className={"rr-trace" + (activeSection.id === "sentiment" ? " rr-trace--wide" : "")}>
              <button className="rr-trace__back" title="Back to the finding"
                onClick={() => { if (store) { store.setReturnToFinding && store.setReturnToFinding(traceNote.fromId || null); store.setTab && store.setTab("Insights"); } }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
              </button>
              <span className="rr-trace__txt">
                Traced from finding
                <strong> “{traceNote.statement}”</strong>
                <span className="rr-trace__sep">·</span>
                showing <b>{traceNote.sourceLabel}</b>{traceNote.cutLabel && traceNote.cutLabel !== "All respondents" ? <> filtered to <b>{traceNote.cutLabel}</b></> : <> · all respondents</>}
              </span>
              <button className="rr-trace__clear" onClick={() => { clearFilters(); setTraceNote(null); }}>Clear</button>
            </div>
          )}
          {activeSection.kind === "survey" && (
            <QuestionsList
              questions={rawSections[0].questions}
              respondents={filtered}
              filters={filters}
              onToggleAnswer={toggleAnswer}
              sortMode={sortMode}
              onSortChange={(qid, m) => setSortMode((s) => ({ ...s, [qid]: m }))}
            />
          )}
          {activeSection.kind === "product" && (
            <ProductSectionView
              data={data}
              respondents={filtered}
              filters={filters}
              target={productTarget}
            />
          )}
          {activeSection.kind === "demo" && (
            <QuestionsList
              questions={rawSections[2].questions}
              respondents={filtered}
              filters={filters}
              onToggleAnswer={toggleAnswer}
              sortMode={sortMode}
              onSortChange={(qid, m) => setSortMode((s) => ({ ...s, [qid]: m }))}
            />
          )}
          {activeSection.kind === "stub" && (
            activeSection.id === "sentiment"
              ? React.createElement(window.ConsumerSentimentView, { filtered, allRespondents: data.respondents })
              : <StubView stub={SURVEY_INSIGHTS_STUBS.find((s) => s.id === activeSection.id)} />
          )}
        </div>

        {/* Right: filter panel */}
        {filtersOpen && (
          <FilterPanel
            data={data}
            cfg={cfg}
            filters={filters}
            filterCount={filterCount}
            totalShown={totalShown}
            onToggleDemo={toggleDemo}
            onToggleAnswer={toggleAnswer}
            onApplyProfile={applyProfile}
            onClear={clearFilters}
            onClose={() => setFiltersOpen(false)}
          />
        )}
      </div>
    </div>
  );
}

// ---------- Left rail ----------
function SectionsRail({ surveyInsights, rawSections, activeSection, onSelect }) {
  const [expanded, setExpanded] = React.useState({ main: true, product: true, demo: true });
  const [collapsed, setCollapsed] = React.useState(true);
  function toggle(id) { setExpanded((e) => ({ ...e, [id]: !e[id] })); }
  return (
    <aside className={"rr__rail rr__rail--sections" + (collapsed ? " is-collapsed" : "")}>
      <button
        className="rr__rail-head rr__rail-toggle"
        onClick={() => setCollapsed((c) => !c)}
        title={collapsed ? "Expand sections" : "Collapse sections"}
        aria-expanded={!collapsed}
      >
        <i className="ti ti-layout-sidebar"></i>
        {!collapsed && <span>Sections</span>}
      </button>

      {!collapsed && (
      <React.Fragment>
      <div className="rr__rail-group-label">Survey insights</div>
      {surveyInsights.map((s) => (
        <button
          key={s.id}
          className={"rr__rail-leaf" + (activeSection.kind === "stub" && activeSection.id === s.id ? " is-active" : "")}
          onClick={() => onSelect({ kind: "stub", id: s.id })}
        >
          <span className="rr__rail-glyph"><i className={"ti ti-" + (s.ti || "circle")}></i></span>
          <span className="rr__rail-leaf-label">{s.label}</span>
        </button>
      ))}

      <div className="rr__rail-group-label" style={{ marginTop: 14 }}>Raw results</div>
      {rawSections.map((sec) => {
        const isActive = (sec.id === "main" && activeSection.kind === "survey") ||
                         (sec.id === "product" && activeSection.kind === "product") ||
                         (sec.id === "demo" && activeSection.kind === "demo");
        const isOpen = expanded[sec.id];
        return (
          <div key={sec.id} className="rr__rail-section-wrap">
            <button
              className={"rr__rail-section-btn" + (isActive ? " is-active" : "")}
              onClick={() => {
                onSelect({
                  kind: sec.id === "main" ? "survey" : sec.id === "product" ? "product" : "demo",
                  id: sec.id,
                });
                if (!isOpen) toggle(sec.id);
              }}
            >
              <span className={"rr__rail-caret" + (isOpen ? " is-open" : "")}><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
              <span className="rr__rail-section-label">{sec.label}</span>
              <span className="rr__rail-section-count">{sec.count}</span>
            </button>
            {isOpen && (
              <div className="rr__rail-children">
                {sec.kind === "questions" && sec.questions.map((q) => (
                  <button
                    key={q.id}
                    className="rr__rail-child"
                    onClick={() => {
                      onSelect({
                        kind: sec.id === "main" ? "survey" : "demo",
                        id: sec.id,
                      });
                      // Scroll to question
                      setTimeout(() => {
                        const el = document.getElementById("rr-q-" + q.id);
                        const parent = el && el.closest("[data-rr-scroll]");
                        if (el && parent) {
                          parent.scrollTo({ top: el.offsetTop - parent.offsetTop - 12, behavior: "smooth" });
                        }
                      }, 50);
                    }}
                  >
                    <span className="rr__rail-child-icon"><i className={"ti ti-" + (q.type === "text" ? "abc" : q.type === "ranking" ? "list-numbers" : q.type === "multi" ? "checkbox" : "circle-dot")}></i></span>
                    <span className="rr__rail-child-label">{q.title.slice(0, 38)}{q.title.length > 38 ? "…" : ""}</span>
                  </button>
                ))}
                {sec.kind === "product" && (
                  <React.Fragment>
                    {(sec.pqs || []).map((pq) => (
                      <button key={pq.id} className="rr__rail-child" onClick={() => onSelect({ kind: "product", id: "product" })}>
                        <span className="rr__rail-child-icon"><i className={"ti ti-" + (pq.type === "scale" ? "star" : pq.type === "multi" ? "checkbox" : "abc")}></i></span>
                        <span className="rr__rail-child-label">{pq.title.slice(0, 32)}{pq.title.length > 32 ? "\u2026" : ""}</span>
                      </button>
                    ))}
                  </React.Fragment>
                )}
              </div>
            )}
          </div>
        );
      })}
      </React.Fragment>
      )}
    </aside>
  );
}

// ---------- Question list view ----------
function QuestionsList({ questions, respondents, filters, onToggleAnswer, sortMode, onSortChange }) {
  return (
    <React.Fragment>
      {questions.map((q) => (
        <div key={q.id} id={"rr-q-" + q.id}>
          <QuestionCard
            q={q}
            respondents={respondents}
            filters={filters}
            onToggleAnswer={onToggleAnswer}
            sortMode={sortMode[q.id] || "desc"}
            onSortChange={(m) => onSortChange(q.id, m)}
          />
        </div>
      ))}
    </React.Fragment>
  );
}

// ---------- Question card ----------
// Respondent count chip. With a twin/human split configured it becomes the
// hover target for the composition popover instead of a second pill.
function RRNChip({ n }) {
  const s = window.__TWIN_SPLIT;
  const plain = <span className="rr-card__chip">n = {(n || 0).toLocaleString()}</span>;
  if (!s || n == null || !window.ApSamplePop) return plain;
  const t = Math.round(n * (s.share || 0.667)), h = n - t;
  return (
    <span className="ap-nwrap" tabIndex={0}>
      <span className="rr-card__chip rr-card__chip--pop">n = {n.toLocaleString()}<i className="ti ti-chevron-down ap-nbadge__cv"></i></span>
      <window.ApSamplePop n={n} sp={{ h, t }} />
    </span>
  );
}
function QuestionCard({ q, respondents, filters, onToggleAnswer, sortMode, onSortChange }) {
  const agg = React.useMemo(
    () => StudyData.aggregateQuestion(q.id, respondents),
    [q.id, respondents]
  );
  const selfSet = filters.answers[q.id];
  const hasSelf = selfSet && selfSet.size > 0;

  const items = React.useMemo(() => {
    if (!agg) return [];
    if (agg.type === "text" || agg.type === "ranking") return agg.options || [];
    const arr = agg.options.map((opt) => ({
      ...opt,
      _selected: hasSelf && selfSet.has(opt.label),
    }));
    if (sortMode === "desc") arr.sort((a, b) => b.pct - a.pct);
    return arr;
  }, [agg, sortMode, hasSelf, selfSet]);

  const [sortOpen, setSortOpen] = React.useState(false);

  return (
    <article className="rr-card">
      <div className="rr-card__head">
        <div className="rr-card__title">
          {q.title}
        </div>
        <div className="rr-card__meta">
          <span className="rr-card__chip">
            {q.type === "single" ? "Single select"
              : q.type === "multi" ? "Multi-select"
              : q.type === "ranking" ? "Ranking"
              : "Long text"}
          </span>
          <RRNChip n={agg ? agg.total : 0} />
          {(agg && agg.type !== "text") && (
            <div style={{ position: "relative" }}>
              <button className="rr-card__sort" onClick={() => setSortOpen((v) => !v)} title="Sort">
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"><line x1="3" y1="6" x2="15" y2="6"/><line x1="3" y1="12" x2="11" y2="12"/><line x1="3" y1="18" x2="7" y2="18"/></svg>
              </button>
              {sortOpen && (
                <React.Fragment>
                  <div onClick={() => setSortOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 28 }}></div>
                  <div className="rr-card__sort-menu">
                    <div className="rr-card__sort-label">Sort by</div>
                    <button onClick={() => { onSortChange("desc"); setSortOpen(false); }} className={sortMode === "desc" ? "is-active" : ""}>
                      <span className="rr-card__sort-check">{sortMode === "desc" ? "✓" : ""}</span>
                      <span>
                        <span className="rr-card__sort-title">% descending</span>
                        <span className="rr-card__sort-sub">Most popular first</span>
                      </span>
                    </button>
                    <button onClick={() => { onSortChange("original"); setSortOpen(false); }} className={sortMode === "original" ? "is-active" : ""}>
                      <span className="rr-card__sort-check">{sortMode === "original" ? "✓" : ""}</span>
                      <span>
                        <span className="rr-card__sort-title">Original order</span>
                        <span className="rr-card__sort-sub">As asked in the survey</span>
                      </span>
                    </button>
                  </div>
                </React.Fragment>
              )}
            </div>
          )}
        </div>
      </div>
      <div className="rr-card__body">
        {agg && (agg.type === "single" || agg.type === "multi" || agg.type === "scale") && items.map((opt) => (
          <BarRow key={opt.label} opt={opt} onClick={() => onToggleAnswer(q.id, opt.label)} />
        ))}
        {agg && agg.type === "ranking" && items.map((opt) => (
          <RankRow key={opt.label} opt={opt} />
        ))}
        {agg && agg.type === "text" && <TextResponses cloud={agg.cloud} sample={agg.responses.slice(0, 6)} />}
      </div>
      <div className="rr-card__foot">
        <div className="rr-card__chart-toggles">
          <button className="rr-card__chart-tab is-active" title="Bar chart">
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><line x1="3" y1="6" x2="15" y2="6"/><line x1="3" y1="12" x2="19" y2="12"/><line x1="3" y1="18" x2="10" y2="18"/></svg>
          </button>
          <button className="rr-card__chart-tab" title="Column chart" disabled>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
          </button>
          <button className="rr-card__chart-tab" title="Donut chart" disabled>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M21.21 15.89A10 10 0 1 1 8 2.83"/><path d="M22 12A10 10 0 0 0 12 2v10z"/></svg>
          </button>
        </div>
        <div style={{ marginLeft: "auto", display: "inline-flex", gap: 4 }}>
          <button className="rr-card__foot-btn">Options</button>
          <button className="rr-card__foot-btn" title="Export">⤓</button>
          <button className="rr-card__foot-btn" title="Expand">⤢</button>
        </div>
      </div>
    </article>
  );
}

function BarRow({ opt, onClick }) {
  return (
    <div className={"rr-bar" + (opt._selected ? " is-selected" : "")} onClick={onClick}>
      <div className="rr-bar__row">
        <div className="rr-bar__label">
          {opt._selected && <span className="rr-bar__check">✓</span>}
          {opt.label}
        </div>
        <div className="rr-bar__pct">
          <span className="rr-bar__count">{opt.count.toLocaleString()}</span>
          <span className="rr-bar__pct-val">{opt.pct}%</span>
        </div>
      </div>
      <div className="rr-bar__track">
        <div className="rr-bar__fill" style={{ width: `${Math.max(0.5, opt.pct)}%` }}></div>
      </div>
    </div>
  );
}

function RankRow({ opt }) {
  return (
    <div className="rr-bar">
      <div className="rr-bar__row">
        <div className="rr-bar__label">{opt.label}</div>
        <div className="rr-bar__pct">
          <span className="rr-bar__count">avg #{opt.mean}</span>
          <span className="rr-bar__pct-val">{opt.top1pct}% picked #1</span>
        </div>
      </div>
      <div className="rr-bar__track">
        <div className="rr-bar__fill" style={{ width: `${Math.max(0.5, opt.pct)}%` }}></div>
      </div>
    </div>
  );
}

function TextResponses({ cloud, sample }) {
  const max = Math.max(...cloud.map((r) => r.count), 1);
  const total = cloud.reduce((n, r) => n + r.count, 0);
  return (
    <div>
      <div className="rr-text__meta">{cloud.length} top tokens · {total.toLocaleString()} mentions</div>
      <div className="rr-text__cloud">
        {cloud.map((r) => (
          <span
            key={r.text}
            className="rr-text__word"
            style={{ fontSize: 12 + (r.count / max) * 18 }}
          >
            {r.text} <span className="rr-text__n">{r.count}</span>
          </span>
        ))}
      </div>
      {sample && sample.length > 0 && (
        <div className="rr-text__sample">
          <div className="rr-text__sample-label">Sample verbatims</div>
          {sample.map((s, i) => <div key={i} className="rr-text__verbatim">"{s}"</div>)}
        </div>
      )}
    </div>
  );
}

// ---------- Stub view ----------
function StubView({ stub }) {
  if (!stub) return null;
  return (
    <div className="rr-stub">
      <div className="rr-stub__panel">
        <Eyebrow>{stub.label}</Eyebrow>
        <div className="rr-stub__title">{stub.label}</div>
        <div className="rr-stub__sub">{stub.stub}</div>
        <div style={{ marginTop: 14 }}>
          <span className="rr-card__chip">Coming soon · v2.1</span>
        </div>
      </div>
    </div>
  );
}

// ---------- Filter panel ----------
function FilterPanel({ data, cfg, filters, filterCount, totalShown, onToggleDemo, onToggleAnswer, onApplyProfile, onClear, onClose }) {
  const profiles = StudyData.getProfiles();
  const demoFacets = (cfg && cfg.demoFacets) || [];
  const answerFacets = (cfg && cfg.answerFacets) || [];
  const [q, setQ] = React.useState("");
  const match = (s) => !q || String(s).toLowerCase().indexOf(q.toLowerCase()) !== -1;

  return (
    <aside className="rr__filter-panel">
      <div className="rr-fp__head">
        <button className="rr-fp__collapse" onClick={onClose} aria-label="Close filters"><i className="ti ti-layout-sidebar-right"></i></button>
        <span className="rr-fp__title">Filters</span>
        <span className="rr-fp__sp"></span>
        <button className="rr-fp__icon" title="Filter settings"><i className="ti ti-adjustments-horizontal"></i></button>
      </div>
      <div className="rr-fp__search">
        <i className="ti ti-search"></i>
        <input placeholder="Search" value={q} onChange={(e) => setQ(e.target.value)} />
      </div>

      {/* Applied filters */}
      <RRFilterGroup label="Applied filters" count={filterCount || null} startOpen={filterCount > 0}>
        {filterCount === 0 && <div className="rr-fp__empty">Nothing applied yet</div>}
        <React.Fragment>
          {Object.entries(filters.demo).map(([field, set]) => {
            const label = (demoFacets.find((f) => f.field === field) || {}).label || field;
            return (
              <div key={field} className="rr__active-ans">
                <div className="rr__active-ans-q">{label}</div>
                {[...set].map((l) => (
                  <span key={l} className="rr__active-ans-chip">
                    {l}
                    <button onClick={() => onToggleDemo(field, l)} aria-label="Remove">×</button>
                  </span>
                ))}
              </div>
            );
          })}
          {Object.entries(filters.answers).map(([qid, set]) => {
            const qq = data._qIndex[qid];
            return (
              <div key={qid} className="rr__active-ans">
                <div className="rr__active-ans-q">{qq ? qq.num : qid}</div>
                {[...set].map((l) => (
                  <span key={l} className="rr__active-ans-chip">
                    {l}
                    <button onClick={() => onToggleAnswer(qid, l)} aria-label="Remove">×</button>
                  </span>
                ))}
              </div>
            );
          })}
          {filterCount > 0 && <button className="rr-fp__clear" onClick={onClear}>Clear all filters</button>}
        </React.Fragment>
      </RRFilterGroup>

      {/* Saved profiles */}
      <RRFilterGroup label="Consumer profiles" action={<span className="rr-fp__act">+ New from filters</span>}>
        {profiles.filter((p) => match(p.name)).map((p) => {
          // Compute n on the fly for each profile
          const n = StudyData.filterRespondents(p.filter).length;
          return (
            <button key={p.id} className="rr-filter-row rr-filter-row--profile" onClick={() => onApplyProfile(p)}>
              <span className="rr-filter-row__dot" style={{ background: p.color }}></span>
              <span className="rr-filter-row__label">{p.name}</span>
              <span className="rr-filter-row__meta">{n.toLocaleString()}</span>
            </button>
          );
        })}
      </RRFilterGroup>

      {/* Demographic facets (config-driven) */}
      {demoFacets.map((facet) => {
        let dist = StudyData.demoDistribution(facet.field, data.respondents, facet.order);
        if (facet.limit) dist = dist.slice(0, facet.limit);
        dist = dist.filter((o) => match(o.label) || match(facet.label));
        if (!dist.length) return null;
        const sel = filters.demo[facet.field];
        const allOn = dist.every((o) => sel && sel.has(o.label));
        return (
          <RRFilterGroup key={facet.field} label={facet.label} compare>
            <RRFilterRow label="Select all" strong checked={allOn}
              onChange={() => dist.forEach((o) => { const on = !!(sel && sel.has(o.label)); if (allOn ? on : !on) onToggleDemo(facet.field, o.label); })} />
            {dist.map((o) => (
              <RRFilterRow key={o.label}
                label={o.label}
                meta={o.count.toLocaleString()}
                checked={(filters.demo[facet.field] && filters.demo[facet.field].has(o.label)) || false}
                onChange={() => onToggleDemo(facet.field, o.label)}
              />
            ))}
          </RRFilterGroup>
        );
      })}

      {/* Answer-based facets (config-driven) */}
      {answerFacets.map((facet) => {
        const agg = StudyData.aggregateQuestion(facet.qid, data.respondents);
        if (!agg || !agg.options) return null;
        const opts = agg.options.filter((o) => o.count > 0 && (match(o.label) || match(facet.label)));
        if (!opts.length) return null;
        const asel = filters.answers[facet.qid];
        const aAllOn = opts.every((o) => asel && asel.has(o.label));
        return (
          <RRFilterGroup key={facet.qid} label={facet.label} compare>
            <RRFilterRow label="Select all" strong checked={aAllOn}
              onChange={() => opts.forEach((o) => { const on = !!(asel && asel.has(o.label)); if (aAllOn ? on : !on) onToggleAnswer(facet.qid, o.label); })} />
            {opts.map((o) => (
              <RRFilterRow key={o.label}
                label={o.label}
                meta={o.count.toLocaleString()}
                checked={(filters.answers[facet.qid] && filters.answers[facet.qid].has(o.label)) || false}
                onChange={() => onToggleAnswer(facet.qid, o.label)}
              />
            ))}
          </RRFilterGroup>
        );
      })}
    </aside>
  );
}

function RRFilterGroup({ label, children, action, compare, count, startOpen = true }) {
  const [open, setOpen] = React.useState(startOpen);
  const [cmp, setCmp] = React.useState(false);
  return (
    <div className={"rr__filter-group" + (open ? " is-open" : "")}>
      <button className="rr__filter-group-head" onClick={() => setOpen((o) => !o)} aria-expanded={open}>
        <span className={"rr-fp__caret" + (open ? " is-open" : "")}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
        </span>
        <span className="rr__filter-group-label">{label}</span>
        {count ? <span className="rr-fp__count">{count}</span> : null}
      </button>
      {open && (
        <div className="rr__filter-group-body">
          {action && <div className="rr-fp__actrow">{action}</div>}
          {children}
          {compare && (
            <div className="rr-fp__cmp">
              <button className={"rr-fp__switch" + (cmp ? " is-on" : "")} onClick={() => setCmp((v) => !v)} aria-pressed={cmp}><span></span></button>
              <i className="ti ti-scale"></i>
              <span className="rr-fp__cmp-l">Compare</span>
              <span className="rr-fp__sp"></span>
              <button className="rr-fp__icon rr-fp__dots" title="More"><i className="ti ti-dots"></i></button>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

function RRFilterRow({ label, meta, swatch, checked, onChange, strong }) {
  return (
    <label className={"rr-filter-row" + (checked ? " is-checked" : "") + (strong ? " rr-filter-row--all" : "")}>
      <span className="rr-filter-row__box">
        {checked && <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3.2" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>}
      </span>
      <span className="rr-filter-row__label">{label}</span>
      {meta && <span className="rr-filter-row__meta">{meta}</span>}
      <input type="checkbox" checked={checked} onChange={onChange} style={{ position: "absolute", opacity: 0, pointerEvents: "none" }} />
    </label>
  );
}

Object.assign(window, { RawResultsView, productFamily, FAMILY_COLORS, RRFilterGroup, RRFilterRow });
