/* ============================================================
   Guided Workshop v2 — item-type renderers + poll presenter
   ============================================================ */

const { useState, useEffect, useRef, useCallback, useMemo } = React;

/* ---------- icons (subset, sized for v2) ---------- */
const v2Icons = {
  arrowL: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6"/></svg>,
  arrowR: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6"/></svg>,
  check:  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>,
  x:      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>,
  play:   <svg viewBox="0 0 24 24" fill="currentColor"><polygon points="6 4 20 12 6 20 6 4"/></svg>,
  refresh:<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4-4.64 4.36A9 9 0 0 1 3.51 15"/></svg>,
  expand: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>,
  upload: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>,
  file:   <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>,
  copy:   <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>,
  users:  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>,
  zoomIn: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>,
  lock:   <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>,
};

window.v2Icons = v2Icons;

/* ============================================================
   ContentView — refined reading layout
   ============================================================ */
function ContentView({ item }) {
  return (
    <article className="v2-prose">
      {item.blocks.map((b, i) => <Block key={i} block={b} />)}
    </article>
  );
}

function Block({ block }) {
  switch (block.kind) {
    case "heading":
      return <h3 className="v2-h3">{block.text}</h3>;
    case "para":
      return <p className="v2-p">{block.text}</p>;
    case "image":
      return (
        <figure className="v2-figure">
          <img src={block.src} alt={block.caption || ""} loading="lazy" />
          {block.caption && <figcaption>{block.caption}</figcaption>}
        </figure>
      );
    case "video":
      return (
        <div className="v2-video">
          {block.poster && <img src={block.poster} alt="" />}
          <span className="v2-video-play">{v2Icons.play}</span>
          <span className="v2-video-len">4:12</span>
        </div>
      );
    case "bullets":
      return <ul className="v2-bullets">{block.items.map((it, i) => <li key={i}>{it}</li>)}</ul>;
    case "callout":
      return (
        <aside className="v2-callout">
          <strong>{block.label}</strong>
          <span>{block.text}</span>
        </aside>
      );
    case "gallery":
      return <Gallery images={block.images} />;
    default:
      return null;
  }
}

/* ============================================================
   Gallery — cleaner, grid-only by default
   ============================================================ */
function Gallery({ images }) {
  const open = (i) => window.dispatchEvent(new CustomEvent("v2-lightbox", { detail: { images, index: i } }));
  if (images.length === 1) {
    return (
      <figure className="v2-figure" onClick={() => open(0)} style={{ cursor: "zoom-in" }}>
        <img src={images[0].src} alt={images[0].caption || ""} loading="lazy" />
        {images[0].caption && <figcaption>{images[0].caption}</figcaption>}
      </figure>
    );
  }
  return (
    <div className="v2-gallery" data-count={images.length}>
      {images.map((im, i) => (
        <button key={i} className="v2-gallery-tile" onClick={() => open(i)} aria-label={im.caption || `Image ${i + 1}`}>
          <img src={im.src} alt={im.caption || ""} loading="lazy" />
          {im.caption && <span className="v2-gallery-cap">{im.caption}</span>}
        </button>
      ))}
    </div>
  );
}

/* ============================================================
   MediaView — full-bleed image or video; gallery for multi-image
   ============================================================ */
function MediaView({ item }) {
  const isVideo = item.mediaKind === "video";
  const isMulti = Array.isArray(item.images) && item.images.length > 1;
  const openLb = () => window.dispatchEvent(new CustomEvent("v2-lightbox", { detail: { images: [{ src: item.src, caption: item.title }], index: 0 } }));

  return (
    <div className="v2-media-stage">
      {item.showTitle && item.description && <p className="v2-media-desc">{item.description}</p>}
      {isMulti ? (
        <Gallery images={item.images} />
      ) : isVideo ? (
        <div className="v2-video v2-video-large">
          {item.poster && <img src={item.poster} alt="" />}
          <span className="v2-video-play">{v2Icons.play}</span>
          <span className="v2-video-len">4:12</span>
        </div>
      ) : (
        <figure className="v2-media-figure" onClick={openLb}>
          <img src={item.src} alt={item.title || ""} loading="lazy" />
        </figure>
      )}
    </div>
  );
}

/* ============================================================
   EvidenceView — large drop zone, list of files, notes
   ============================================================ */
function EvidenceView({ item }) {
  const [files, setFiles] = useState([]);
  const [notes, setNotes] = useState("");
  const ref = useRef(null);
  const fmt = (b) => b < 1024 ? `${b} B` : b < 1024*1024 ? `${(b/1024).toFixed(0)} KB` : `${(b/1024/1024).toFixed(1)} MB`;
  const onPick = (e) => {
    const list = [...(e.target.files || [])].map(f => ({ name: f.name, size: f.size }));
    setFiles(p => [...p, ...list]);
    if (ref.current) ref.current.value = "";
  };
  return (
    <div className="v2-evidence">
      {item.description && <p className="v2-evidence-desc">{item.description}</p>}
      <label className="v2-dropzone">
        <input ref={ref} type="file" multiple onChange={onPick} hidden />
        <span className="v2-dropzone-icon">{v2Icons.upload}</span>
        <span className="v2-dropzone-cta"><b>Click to upload</b> or drag and drop</span>
        <span className="v2-dropzone-hint">{(item.accepts || ["PDF"]).join(", ")} · up to {item.maxSize || "25 MB"}</span>
      </label>
      {files.length > 0 && (
        <ul className="v2-files">
          {files.map((f, i) => (
            <li key={i}>
              <span className="v2-file-icon">{v2Icons.file}</span>
              <span className="v2-file-name">{f.name}</span>
              <span className="v2-file-size">{fmt(f.size)}</span>
              <button className="v2-file-rm" onClick={() => setFiles(p => p.filter((_, x) => x !== i))} aria-label="Remove">{v2Icons.x}</button>
            </li>
          ))}
        </ul>
      )}
      <label className="v2-field">
        <span className="v2-field-lbl">Notes</span>
        <textarea
          className="v2-textarea" rows="3"
          value={notes} onChange={(e) => setNotes(e.target.value)}
          placeholder={item.notesPlaceholder || "Add context for reviewers…"}
        />
      </label>
    </div>
  );
}

/* ============================================================
   QuestionView — interactive inputs; poll-mode shows preview
   ============================================================ */
function QuestionView({ item, answer, onAnswer, pollLive, complete, onReopenPoll, onPresentResults }) {
  const value   = answer?.value ?? null;
  const comment = answer?.comment ?? "";
  const notes   = answer?.notes ?? "";
  const setVal   = (v) => onAnswer({ value: v, comment, notes });
  const setCom   = (c) => onAnswer({ value, comment: c, notes });
  const setNotes = (n) => onAnswer({ value, comment, notes: n });
  const subtype = item.questionType;
  const isPoll  = item.mode === "poll";
  const pollState = !isPoll ? null : pollLive ? "live" : complete ? "closed" : "never";

  /* Closed-poll results take over the body */
  if (pollState === "closed") {
    return (
      <PollResults
        item={item}
        notes={notes}
        onNotesChange={setNotes}
        onReopen={onReopenPoll}
        onPresent={onPresentResults}
      />
    );
  }

  const renderInput = (disabled) => (
    <fieldset className="v2-fieldset" disabled={disabled}>
      {subtype === "radio"    && <RadioGroup    item={item} value={disabled ? null : value} onChange={setVal} />}
      {subtype === "rating"   && <RatingScale   item={item} value={disabled ? 0    : value} onChange={setVal} />}
      {subtype === "boolean"  && <BooleanInput  item={item} value={disabled ? null : value} onChange={setVal} />}
      {subtype === "text"     && <TextInput     item={item} value={disabled ? ""   : value} onChange={setVal} placeholderOverride={disabled ? "Participants type here…" : null} />}
      {subtype === "textarea" && <LongText      item={item} value={disabled ? ""   : value} onChange={setVal} placeholderOverride={disabled ? "Participants type here…" : null} />}
    </fieldset>
  );

  return (
    <div className="v2-question">
      {item.description && <p className="v2-question-desc">{item.description}</p>}
      {renderInput(isPoll)}
      {!isPoll && item.commentBox && (
        <label className="v2-field">
          <span className="v2-field-lbl">Add a comment <span className="v2-field-optional">— optional</span></span>
          <textarea className="v2-textarea" rows="3" value={comment} onChange={(e) => setCom(e.target.value)} placeholder="Anything to add to your answer above?" />
        </label>
      )}
    </div>
  );
}

function RadioGroup({ item, value, onChange }) {
  return (
    <div className="v2-radio-group">
      {item.options.map((opt, i) => {
        const selected = value === opt;
        return (
          <label key={i} className={`v2-radio-card ${selected ? "is-selected" : ""}`}>
            <input type="radio" name={`r-${item.id}`} checked={selected} onChange={() => onChange(opt)} />
            <span className="v2-radio-dot"><span className="v2-radio-dot-inner" /></span>
            <span className="v2-radio-card-lbl">{opt}</span>
          </label>
        );
      })}
    </div>
  );
}

function RatingScale({ item, value, onChange }) {
  const { min = 1, max = 5 } = item.scale || {};
  const labels = item.labels || {};
  const v = Number.isFinite(value) ? value : 0;
  const items = [];
  for (let i = min; i <= max; i++) items.push(i);
  return (
    <div className="v2-rating">
      <div className="v2-rating-row">
        {items.map((n) => {
          const active = n <= v;
          return (
            <button key={n} type="button" className={`v2-rating-cell ${active ? "is-active" : ""}`} onClick={() => onChange(n)} aria-label={`Rate ${n}`}>
              <svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" strokeWidth="1" strokeLinejoin="round">
                <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
              </svg>
            </button>
          );
        })}
      </div>
      {(labels.min || labels.max) && (
        <div className="v2-rating-labels">
          <span>{labels.min}</span>
          <span>{labels.max}</span>
        </div>
      )}
    </div>
  );
}

function BooleanInput({ item, value, onChange }) {
  const t = item.trueLabel || "Yes";
  const f = item.falseLabel || "No";
  return (
    <div className="v2-bool">
      <button type="button" className={`v2-bool-btn ${value === true ? "is-yes" : ""}`} onClick={() => onChange(true)}>
        <span className="v2-bool-mark">{v2Icons.check}</span><span>{t}</span>
      </button>
      <button type="button" className={`v2-bool-btn ${value === false ? "is-no" : ""}`} onClick={() => onChange(false)}>
        <span className="v2-bool-mark">{v2Icons.x}</span><span>{f}</span>
      </button>
    </div>
  );
}

function TextInput({ item, value, onChange, placeholderOverride }) {
  return (
    <input
      type="text" className="v2-input"
      value={value || ""} onChange={(e) => onChange(e.target.value)}
      placeholder={placeholderOverride || item.placeholder || "Type your answer…"}
    />
  );
}

function LongText({ item, value, onChange, placeholderOverride }) {
  return (
    <textarea
      className="v2-textarea v2-textarea-large"
      rows={item.rows || 5}
      value={value || ""} onChange={(e) => onChange(e.target.value)}
      placeholder={placeholderOverride || item.placeholder || "Type your answer…"}
    />
  );
}

/* ============================================================
   PollPresenter — full-screen takeover for collecting responses.
   Designed to be projected: giant QR + giant session code,
   live response counter, minimal chrome.
   ============================================================ */
function QRPattern({ seed = 0 }) {
  const N = 25;
  const cells = [];
  let s = seed * 9301 + 49297;
  const rng = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
  for (let y = 0; y < N; y++) {
    for (let x = 0; x < N; x++) {
      const inFinder = (x < 7 && y < 7) || (x >= N - 7 && y < 7) || (x < 7 && y >= N - 7);
      if (inFinder) continue;
      if (rng() > 0.5) cells.push({ x, y });
    }
  }
  const finder = (cx, cy) => (
    <>
      <rect x={cx} y={cy} width="7" height="7" fill="currentColor" />
      <rect x={cx + 1} y={cy + 1} width="5" height="5" fill="white" />
      <rect x={cx + 2} y={cy + 2} width="3" height="3" fill="currentColor" />
    </>
  );
  return (
    <svg viewBox={`0 0 ${N} ${N}`} className="v2-qr-svg" shapeRendering="crispEdges">
      {cells.map((c, i) => <rect key={i} x={c.x} y={c.y} width="1" height="1" fill="currentColor"/>)}
      {finder(0, 0)}
      {finder(N - 7, 0)}
      {finder(0, N - 7)}
    </svg>
  );
}

function PollPresenter({ item, complete, onClose, onMarkComplete }) {
  const [copied, setCopied] = useState(null);
  if (!item || !item.session) return null;
  const s = item.session;
  const seed = parseInt((s.code || "0").replace(/\D/g, ""), 10) || 0;
  const copy = (key, text) => {
    try { navigator.clipboard?.writeText(text); } catch (_) {}
    setCopied(key);
    setTimeout(() => setCopied(null), 1400);
  };

  /* Closed poll → results-presenter layout (no QR, just the chart big) */
  if (complete) {
    const dist = computeDistribution(item);
    const t = item.questionType;
    return (
      <div className="v2-presenter v2-presenter-results" role="dialog" aria-label="Poll results — presenter mode">
        <header className="v2-presenter-head">
          <div className="v2-presenter-eyebrow v2-presenter-eyebrow-results">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><polyline points="20 6 9 17 4 12"/></svg>
            <span>Poll closed · {s.responded} responded</span>
          </div>
          <button className="v2-presenter-close" onClick={onClose} aria-label="Exit presenter mode">{v2Icons.x}</button>
        </header>

        <main className="v2-presenter-body v2-presenter-results-body">
          <section className="v2-presenter-left">
            <div className="v2-presenter-num">{item.num}</div>
            <h1 className="v2-presenter-title">{item.title}</h1>
            {item.description && <p className="v2-presenter-desc">{item.description}</p>}
          </section>
          <section className="v2-presenter-results-chart">
            {dist && t === "radio"    && <V2RadioChart    item={item} dist={dist} />}
            {dist && t === "rating"   && <V2RatingChart   item={item} dist={dist} />}
            {dist && t === "boolean"  && <V2BooleanChart  item={item} dist={dist} />}
            {dist && t === "text"     && <V2TextResponses item={item} dist={dist} />}
            {dist && t === "textarea" && <V2TextareaResponses item={item} dist={dist} />}
          </section>
        </main>

        <footer className="v2-presenter-foot">
          <div className="v2-presenter-stats">
            <span className="v2-presenter-stat">
              <span className="v2-stat-num">{s.responded}</span>
              <span className="v2-stat-lbl">responded</span>
            </span>
            <span className="v2-presenter-sep" />
            <span className="v2-presenter-stat">
              <span className="v2-stat-num">{s.participants}</span>
              <span className="v2-stat-lbl">participants</span>
            </span>
          </div>
          <div className="v2-presenter-actions">
            <button className="v2-btn v2-btn-on-dark" onClick={onClose}>Exit presenter</button>
          </div>
        </footer>
      </div>
    );
  }

  return (
    <div className="v2-presenter" role="dialog" aria-label="Workshop poll — presenter mode">
      <header className="v2-presenter-head">
        <div className="v2-presenter-eyebrow">
          <span className="v2-live-dot" />
          <span>Live poll · {s.responded} responded · {s.participants} participants</span>
        </div>
        <button className="v2-presenter-close" onClick={onClose} aria-label="Exit presenter mode">
          {v2Icons.x}
        </button>
      </header>

      <main className="v2-presenter-body">
        <section className="v2-presenter-left">
          <div className="v2-presenter-num">{item.num}</div>
          <h1 className="v2-presenter-title">{item.title}</h1>
          {item.description && <p className="v2-presenter-desc">{item.description}</p>}
          <div className="v2-presenter-preview">
            <PreviewInput item={item} />
          </div>
        </section>

        <section className="v2-presenter-right">
          <div className="v2-presenter-codecard">
            <div className="v2-presenter-codelabel">Join with code</div>
            <div className="v2-presenter-code">{s.code}</div>
            <div className="v2-presenter-or">or scan the QR</div>
            <div className="v2-presenter-qr"><QRPattern seed={seed} /></div>
            <div className="v2-presenter-url">
              <span>{s.url}</span>
              <button className="v2-presenter-copy" onClick={() => copy("url", s.url)}>
                {copied === "url" ? v2Icons.check : v2Icons.copy}
              </button>
            </div>
          </div>
        </section>
      </main>

      <footer className="v2-presenter-foot">
        <div className="v2-presenter-stats">
          <span className="v2-presenter-stat">
            <span className="v2-stat-num">{s.responded}</span>
            <span className="v2-stat-lbl">responded</span>
          </span>
          <span className="v2-presenter-sep" />
          <span className="v2-presenter-stat">
            <span className="v2-stat-num">{s.participants}</span>
            <span className="v2-stat-lbl">participants</span>
          </span>
        </div>
        <div className="v2-presenter-actions">
          <button className="v2-btn v2-btn-secondary v2-btn-on-dark" onClick={onClose}>Pause</button>
          <button className="v2-btn v2-btn-primary" onClick={onMarkComplete}>
            {v2Icons.check}<span>Close poll &amp; mark complete</span>
          </button>
        </div>
      </footer>
    </div>
  );
}

/* Smaller preview rendering inside presenter — shows the question shape
   so participants and presenter both know what the answer choices look like. */
function PreviewInput({ item }) {
  const t = item.questionType;
  if (t === "radio") {
    return (
      <ul className="v2-preview-radio">
        {item.options.map((o, i) => <li key={i}><span/>{o}</li>)}
      </ul>
    );
  }
  if (t === "rating") {
    const max = item.scale?.max || 5;
    return (
      <div className="v2-preview-rating">
        {Array.from({length: max}).map((_, i) => (
          <svg key={i} viewBox="0 0 24 24" fill="currentColor"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
        ))}
      </div>
    );
  }
  if (t === "boolean") {
    return (
      <div className="v2-preview-bool">
        <span>{item.trueLabel || "Yes"}</span><span>{item.falseLabel || "No"}</span>
      </div>
    );
  }
  if (t === "text" || t === "textarea") {
    return <div className="v2-preview-text">{item.placeholder || "Free-form response"}</div>;
  }
  return null;
}

/* ============================================================
   Lightbox — same as v1, scoped to v2 styles
   ============================================================ */
function Lightbox() {
  const [state, setState] = useState(null);
  useEffect(() => {
    const h = (e) => setState(e.detail);
    window.addEventListener("v2-lightbox", h);
    return () => window.removeEventListener("v2-lightbox", h);
  }, []);
  useEffect(() => {
    if (!state) return;
    const onKey = (e) => {
      if (e.key === "Escape") setState(null);
      if (e.key === "ArrowRight") setState(s => s && { ...s, index: (s.index + 1) % s.images.length });
      if (e.key === "ArrowLeft")  setState(s => s && { ...s, index: (s.index - 1 + s.images.length) % s.images.length });
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [state]);
  if (!state) return null;
  const img = state.images[state.index];
  return (
    <div className="v2-lightbox" onClick={() => setState(null)}>
      <button className="v2-lightbox-close" onClick={() => setState(null)} aria-label="Close">{v2Icons.x}</button>
      <figure className="v2-lightbox-figure" onClick={(e) => e.stopPropagation()}>
        <img src={img.src} alt={img.caption || ""}/>
        {img.caption && <figcaption>{img.caption}</figcaption>}
        <div className="v2-lightbox-counter">{state.index + 1} of {state.images.length}</div>
      </figure>
    </div>
  );
}

/* ============================================================
   PollResults — closed-poll visualizations for v2.
   Reuses the lifecycle from v1 but rebuilt for the v2 aesthetic:
   tighter spacing, royal-blue / indigo palette, presenter-ready chart.
   ============================================================ */
const SAMPLE_TEXT_RESPONSES_V2 = [
  "Heavy", "Fragmented", "Slow", "Agile", "Stuck", "Reactive", "Improving",
  "Disconnected", "Solid", "Patchy", "Working", "Stretched", "Streamlined",
  "Manual", "Confused", "Aligned",
];
const SAMPLE_TEXTAREA_RESPONSES_V2 = [
  "We've made progress in the operations review cadence but our data layer is still patchy. Hard to make real decisions without a single source of truth.",
  "Honestly the operating model feels great in some sites and disjointed in others. We need a clearer set of non-negotiables.",
  "There's a real tension between speed and consistency. Leadership says they want both — we feel forced to pick.",
  "Capability gaps are real. Onboarding works but mid-career upskilling is something we never invest in.",
  "Decision rights are theoretically clear, but in practice escalation happens for everything.",
  "We've been waiting on the tooling consolidation for ~18 months. Lots of duplicate effort still.",
];

function poissonish(seed, n) {
  let s = seed * 9301 + 49297;
  const rng = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
  const out = [];
  for (let i = 0; i < n; i++) out.push(Math.max(1, Math.round(rng() * 100)));
  return out;
}

function computeDistribution(item) {
  const total = item.session?.responded || 0;
  if (total === 0) return null;
  const seed = parseInt((item.session?.code || "0").replace(/\D/g, ""), 10) || 1;
  const t = item.questionType;
  if (t === "radio") {
    const N = item.options.length;
    const raw = poissonish(seed * 7, N);
    const sum = raw.reduce((a, b) => a + b, 0);
    const counts = raw.map((c) => Math.max(1, Math.round((c / sum) * total)));
    return { counts, labels: item.options, total };
  }
  if (t === "rating") {
    const max = item.scale?.max || 5;
    const min = item.scale?.min || 1;
    const N = max - min + 1;
    const raw = [];
    let s = seed;
    for (let i = 0; i < N; i++) {
      s = (s * 9301 + 49297) % 233280;
      const r = s / 233280;
      const weight = 0.3 + Math.abs(Math.sin((i / (N - 1)) * Math.PI)) * 1.2;
      raw.push(Math.max(1, Math.round(r * 100 * weight)));
    }
    const sum = raw.reduce((a, b) => a + b, 0);
    const counts = raw.map((c) => Math.max(0, Math.round((c / sum) * total)));
    return { counts, max, min, total };
  }
  if (t === "boolean") {
    const yesPct = 40 + (seed % 35);
    const yes = Math.round((yesPct / 100) * total);
    return { yes, no: total - yes, total };
  }
  if (t === "text") {
    const count = Math.min(SAMPLE_TEXT_RESPONSES_V2.length, total);
    return { responses: SAMPLE_TEXT_RESPONSES_V2.slice(0, count), total };
  }
  if (t === "textarea") {
    const count = Math.min(SAMPLE_TEXTAREA_RESPONSES_V2.length, Math.max(3, Math.min(total, 6)));
    return { responses: SAMPLE_TEXTAREA_RESPONSES_V2.slice(0, count), total };
  }
  return null;
}

function scoreToGrade(avg, max) {
  if (max <= 1) return "—";
  const norm = (avg - 1) / (max - 1);
  if (norm >= 0.85) return "A";
  if (norm >= 0.65) return "B";
  if (norm >= 0.45) return "C";
  if (norm >= 0.25) return "D";
  return "F";
}

/* Diverging palette — cohesive with v2's royal-blue accent */
const V2_PALETTE = ["#0e7490", "#06b6d4", "#94a3b8", "#818cf8", "#4f46e5"];
function v2Palette(i, n) {
  const idx = Math.round((i / Math.max(1, n - 1)) * (V2_PALETTE.length - 1));
  return V2_PALETTE[idx];
}

function PollResults({ item, notes, onNotesChange, onReopen, onPresent }) {
  const [grade, setGrade] = useState(false);
  const dist = computeDistribution(item);
  if (!dist) {
    return (
      <div className="v2-pr-empty">
        <p>No responses were collected during the session.</p>
        <button className="v2-btn v2-btn-tonal" onClick={onReopen}>
          {v2Icons.play}<span>Re-open poll</span>
        </button>
      </div>
    );
  }
  const t = item.questionType;
  return (
    <div className="v2-pr">
      {item.description && <p className="v2-question-desc">{item.description}</p>}

      <V2PollStats item={item} dist={dist} grade={grade} onToggleGrade={setGrade} />

      <div className="v2-pr-chart">
        {t === "radio"    && <V2RadioChart    item={item} dist={dist} />}
        {t === "rating"   && <V2RatingChart   item={item} dist={dist} />}
        {t === "boolean"  && <V2BooleanChart  item={item} dist={dist} />}
        {t === "text"     && <V2TextResponses item={item} dist={dist} />}
        {t === "textarea" && <V2TextareaResponses item={item} dist={dist} />}
      </div>

      {onPresent && (
        <button className="v2-pr-present" onClick={onPresent}>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>
          <span>Present results full-screen</span>
        </button>
      )}

      <div className="v2-pr-banner">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h0"/></svg>
        <span>Live results from this session. Use the notes area below to capture clarifications, actions, or follow-up items.</span>
      </div>

      <label className="v2-field">
        <span className="v2-field-lbl">Notes</span>
        <textarea
          className="v2-textarea" rows="3"
          value={notes || ""} onChange={(e) => onNotesChange(e.target.value)}
          placeholder="Add notes…"
        />
      </label>
    </div>
  );
}

function V2PollStats({ item, dist, grade, onToggleGrade }) {
  const t = item.questionType;
  let primary = null, secondary = null;
  if (t === "radio" || t === "rating") {
    const counts = dist.counts;
    const max = t === "rating" ? (dist.max - dist.min + 1) : counts.length;
    const sum = counts.reduce((acc, c, i) => acc + c * (i + 1), 0);
    const total = counts.reduce((a, b) => a + b, 0);
    const avg = sum / total;
    const healthy = counts.slice(Math.ceil(max / 2)).reduce((a, b) => a + b, 0);
    const healthPct = Math.round((healthy / total) * 100);
    primary = grade
      ? { tone: "purple", label: "Grade",         value: scoreToGrade(avg, max) }
      : { tone: "blue",   label: "Average score", value: `${avg.toFixed(2)} / ${max.toFixed(2)}` };
    secondary = { tone: "amber", label: "Health score", value: `${healthPct}%` };
  } else if (t === "boolean") {
    const yesPct = Math.round((dist.yes / dist.total) * 100);
    primary   = { tone: "green", label: item.trueLabel  || "Yes", value: `${dist.yes} · ${yesPct}%` };
    secondary = { tone: "red",   label: item.falseLabel || "No",  value: `${dist.no} · ${100 - yesPct}%` };
  } else if (t === "text" || t === "textarea") {
    primary   = { tone: "blue",  label: "Responses",      value: `${dist.total}` };
    secondary = { tone: "purple", label: "Unique answers", value: `${dist.responses.length}` };
  }
  return (
    <div className="v2-pr-stats">
      {primary && <V2StatCard {...primary} />}
      {secondary && <V2StatCard {...secondary} />}
      {(t === "radio" || t === "rating") && (
        <label className="v2-pr-grade-toggle">
          <span className="v2-pr-grade-track" data-on={grade}>
            <input type="checkbox" checked={grade} onChange={(e) => onToggleGrade(e.target.checked)} />
            <span className="v2-pr-grade-knob" />
          </span>
          <span>View as grade</span>
        </label>
      )}
    </div>
  );
}

function V2StatCard({ tone, label, value }) {
  return (
    <div className={`v2-stat-card v2-stat-${tone}`}>
      <div className="v2-stat-label">{label}</div>
      <div className="v2-stat-value">{value}</div>
    </div>
  );
}

function V2RadioChart({ item, dist }) {
  const total = dist.counts.reduce((a, b) => a + b, 0);
  const N = dist.counts.length;
  const segments = dist.counts.map((c, i) => ({
    label: dist.labels[i],
    count: c,
    pct: Math.round((c / total) * 100),
    color: v2Palette(i, N),
  }));
  const [hover, setHover] = useState(null);
  return (
    <div className="v2-chart-radio">
      <div className="v2-chart-bar">
        {segments.map((s, i) => (
          <div
            key={i}
            className="v2-chart-seg"
            style={{ flex: Math.max(s.pct, 1), background: s.color }}
            onMouseEnter={() => setHover(i)}
            onMouseLeave={() => setHover(null)}
          >
            {s.pct >= 7 && <span className="v2-chart-seg-pct">{s.pct}%</span>}
            {hover === i && <span className="v2-chart-tip">{s.label} · {s.count} responses</span>}
          </div>
        ))}
      </div>
      <div className="v2-chart-axis">
        <span>0%</span><span>25%</span><span>50%</span><span>75%</span><span>100%</span>
      </div>
      <ul className="v2-chart-legend">
        {segments.map((s, i) => (
          <li key={i}>
            <span className="v2-legend-dot" style={{ background: s.color }} />
            <span>{s.label}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}

function V2RatingChart({ item, dist }) {
  const total = dist.counts.reduce((a, b) => a + b, 0);
  const max = Math.max(...dist.counts);
  const sumWeighted = dist.counts.reduce((acc, c, i) => acc + c * (dist.min + i), 0);
  const avg = sumWeighted / total;
  return (
    <div className="v2-chart-rating">
      <div className="v2-chart-rating-bars">
        {dist.counts.map((c, i) => {
          const star = dist.min + i;
          const h = max > 0 ? (c / max) * 100 : 0;
          const pct = total > 0 ? Math.round((c / total) * 100) : 0;
          return (
            <div key={i} className="v2-chart-rating-col">
              <span className="v2-chart-rating-num">{c}</span>
              <span className="v2-chart-rating-bar" style={{ height: `${h}%` }} />
              <span className="v2-chart-rating-lbl">
                {Array.from({length: star}).map((_, k) => (
                  <svg key={k} viewBox="0 0 24 24" fill="currentColor"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
                ))}
              </span>
              <span className="v2-chart-rating-pct">{pct}%</span>
            </div>
          );
        })}
      </div>
      <div className="v2-chart-rating-avg-note">Average <b>{avg.toFixed(2)}</b> across {total} responses</div>
    </div>
  );
}

function V2BooleanChart({ item, dist }) {
  const yesPct = Math.round((dist.yes / dist.total) * 100);
  const noPct = 100 - yesPct;
  const dominantYes = yesPct >= noPct;
  return (
    <div className="v2-chart-bool">
      <div className="v2-chart-bool-hero">
        <div className={`v2-chart-bool-big ${dominantYes ? "is-yes" : "is-no"}`}>
          <span className="v2-chart-bool-big-num">{dominantYes ? yesPct : noPct}%</span>
          <span className="v2-chart-bool-big-lbl">said {dominantYes ? (item.trueLabel || "Yes") : (item.falseLabel || "No")}</span>
        </div>
      </div>
      <div className="v2-chart-bool-bar">
        <div className="v2-chart-bool-seg is-yes" style={{ flex: yesPct }}>
          <span>{item.trueLabel || "Yes"}</span><span>{yesPct}%</span>
        </div>
        <div className="v2-chart-bool-seg is-no" style={{ flex: noPct }}>
          <span>{item.falseLabel || "No"}</span><span>{noPct}%</span>
        </div>
      </div>
    </div>
  );
}

function V2TextResponses({ item, dist }) {
  return (
    <div className="v2-chart-text-chips">
      {dist.responses.map((r, i) => (
        <span key={i} className="v2-chart-chip" style={{ fontSize: `${15 + (i % 3) * 2}px` }}>{r}</span>
      ))}
    </div>
  );
}

function V2TextareaResponses({ item, dist }) {
  const [expanded, setExpanded] = useState(false);
  const visible = expanded ? dist.responses : dist.responses.slice(0, 3);
  return (
    <div className="v2-chart-textarea">
      <ul className="v2-chart-textarea-list">
        {visible.map((r, i) => (
          <li key={i}>
            <span className="v2-chart-quote">"</span>
            <p>{r}</p>
            <span className="v2-chart-resp-meta">Anonymous · response {i + 1}</span>
          </li>
        ))}
      </ul>
      {dist.responses.length > 3 && (
        <button className="v2-btn v2-btn-secondary v2-chart-expand" onClick={() => setExpanded(!expanded)}>
          {expanded ? "Collapse" : `Show all ${dist.responses.length} responses`}
        </button>
      )}
    </div>
  );
}

window.gwV2Views = {
  ContentView, MediaView, EvidenceView, QuestionView, PollPresenter, PollResults, computeDistribution, Lightbox, v2Icons,
};
