/* global React, window */
// =========================================================
// Research depth as a LEVEL-OF-DETAIL control, not a purchase question.
// Set in the composer (like an effort dial) before the brief is even sent, then
// living as a tab row that governs how much resolution the intake reveals.
// Each tier is its own independently-editable research design; editing one
// moves that tier's sample, so the three tabs are a live comparison of real
// designs rather than three adjectives.
// =========================================================
const { useState: useStateT, useEffect: useEffectT, useRef: useRefT } = React;

const TIER_SPECS = {
  directional: {
    id: "directional", label: "Quick read", short: "Quick read",
    use: "I'll steer my own work with it",
    jtbd: "Quick validation you can act on today",
    eg: "Which of three colorways leads · does this print read premium",
    profiles: 1, filters: 3, markets: 1, demos: 3,
    n: 200, base: 25, support: "Lean",
    delivery: "~30 min", floorCell: 60
  },
  decision: {
    id: "decision", label: "Decision-grade", short: "Decision-grade",
    use: "My team has to line up behind it",
    jtbd: "For decisions your team will build on",
    eg: "Which styles make the line · where the price tier lands",
    profiles: 3, filters: 6, markets: 2, demos: 5,
    n: 500, base: 50, support: "Custom",
    delivery: "~48 hours", floorCell: 60
  },
  defensible: {
    id: "defensible", label: "Fully defensible", short: "Fully defensible",
    use: "A decision with downstream impact",
    jtbd: "For calls you'll defend outside your team",
    eg: "A retail partner's buy · a category bet · a board case",
    profiles: 5, filters: 9, markets: 3, demos: 8,
    n: 1200, base: 200, support: "Premium",
    delivery: "5 days", floorCell: 60
  }
};
const TIER_ORDER = ["directional", "decision", "defensible"];
// A filled-dot meter — 1, 2 or 3 of three. Reads as a spectrum at a glance and
// survives being small far better than thin strokes do.
const TierMeter = ({ level }) => (
  <span className="ix-meter" aria-hidden="true">
    {[0, 1, 2].map(i => <i key={i} className={i < level ? "is-on" : ""} />)}
  </span>
);
const TIER_LEVEL = { directional: 1, decision: 2, defensible: 3 };
const specOf = (id) => TIER_SPECS[id] || TIER_SPECS.decision;
// The cheapest tier that affords the Nth item of a kind — drives the ghost label.
function unlockTier(kind, index) {
  for (const id of TIER_ORDER) if (index < TIER_SPECS[id][kind]) return id;
  return null;
}

// Sample is the OUTPUT of the design, never the input. Adding a profile or a
// market at any tier scales that tier's sample.
function tierMetrics(tierId, design, opts) {
  const s = specOf(tierId);
  const d = design || {};
  const o = opts || {};
  const profiles = d.profiles != null ? d.profiles : s.profiles;
  const markets = d.markets != null ? d.markets : s.markets;
  const filters = d.filters != null ? d.filters : s.filters;
  const demos = d.demos != null ? d.demos : s.demos;
  const scale = (profiles / s.profiles) * (markets / s.markets) * (1 + 0.05 * (filters - s.filters)) * (1 + 0.04 * (demos - s.demos));
  const n = Math.max(50, Math.round(s.n * Math.max(0.35, scale) / 25) * 25);
  // Coverage is the ONLY source for the mix. With no pool yet (skeleton states,
  // the composer menu before a brief) panelMix returns the depth's ceiling,
  // which is the honest ceiling rather than a stale constant.
  const mix = window.FW.panelMix(o.pool || [], tierId, { confidential: o.confidential, limit: profiles });
  const twin = mix.twin;
  const twinN = Math.round(n * twin / 100);
  const humanN = n - twinN;
  const cells = Math.max(1, profiles * markets);
  const cellN = Math.floor(n / cells);
  return { ...s, profiles, markets, filters, demos, n, twin, twinN, humanN, cells, cellN, mix,
    readable: cellN >= s.floorCell, confidential: !!o.confidential,
    mode: twin >= 85 ? "Digital Twin panel" : twin >= 50 ? "Twin-led hybrid panel" : twin >= 15 ? "Human-led hybrid panel" : "Human respondent panel" };
}
const mixNote = (m) => m.humanN.toLocaleString() + " recruited shoppers  +  " + m.twinN.toLocaleString() + " Digital Twins  =  " + m.n.toLocaleString() + " respondents";

// Read the brief and pick a starting tier. Deliberately conservative: the words
// that signal a real audience outside the room are what push it up.
function recommendTier(text) {
  const t = String(text || "").toLowerCase();
  if (/\b(board|retailer|retail partner|wholesale|sell-?in|account|buyer|investor|claim|launch|commit|forecast|market entry)\b/.test(t)) return "defensible";
  if (/\b(line|assortment|season|price tier|keep vs cut|roadmap|team|align|plan)\b/.test(t)) return "decision";
  return "directional";
}

// ---------- the control, in the composer ----------
function DepthPicker({ value, onChange, confidential, onConfidential, compact }) {
  const [open, setOpen] = useStateT(false);
  const wrap = useRefT(null);
  useEffectT(() => {
    if (!open) return;
    const away = (e) => { if (wrap.current && !wrap.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", away);
    return () => document.removeEventListener("mousedown", away);
  }, [open]);
  const s = specOf(value);
  return (
    <span className={"ix-dp" + (compact ? " ix-dp--row" : "")} ref={wrap}>
      <button type="button" className={"ix-dp__btn" + (open ? " is-open" : "")} onClick={() => setOpen(o => !o)} title="Research depth">
        <TierMeter level={TIER_LEVEL[value]} />
        {s.short}
        {!compact && <span className="ix-dp__btnwhen">{s.delivery}</span>}
        {confidential && <i className="ix-dp__lock" title="Confidential assets — Digital Twins only">
          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round"><rect x="4" y="11" width="16" height="10" rx="2" /><path d="M8 11V7a4 4 0 0 1 8 0v4" /></svg>
        </i>}
      </button>
      {open && (
        <span className={"ix-dp__menu" + (compact ? " ix-dp__menu--up" : "")}>
          <span className="ix-dp__h">What's the milestone you're looking at?</span>
          {TIER_ORDER.map(id => {
            const t = TIER_SPECS[id];
            // Confidential assets can't reach a human panel, and only the
            // fastest depth is all-Twin — the other two are unreachable.
            const off = confidential && id !== "directional";
            return (
              <button type="button" key={id} disabled={off}
                className={"ix-dp__opt" + (id === value ? " on" : "") + (off ? " is-off" : "")}
                onClick={() => { if (off) return; onChange(id); setOpen(false); }}>
                <span className="ix-dp__ico"><TierMeter level={TIER_LEVEL[id]} /></span>
                <span className="ix-dp__txt">
                  <span className="ix-dp__lab">{t.label}</span>
                  <span className="ix-dp__use">{t.use}</span>
                  <span className="ix-dp__meta">{off ? "Needs a human panel" : "~" + t.n.toLocaleString() + " respondents · " + t.support + " support"}</span>
                </span>
                <span className="ix-dp__when">{off ? "—" : t.delivery}</span>
              </button>
            );
          })}
          <span className="ix-dp__div" />
          <button type="button" className={"ix-dp__conf" + (confidential ? " on" : "")} onClick={() => { const next = !confidential; onConfidential(next); if (next && value !== "directional") onChange("directional"); }} role="switch" aria-checked={!!confidential}>
            <span className="ix-dp__track"><span className="ix-dp__thumb" /></span>
            <span>
              <b>Assets are confidential</b>
              <i>Unreleased or under NDA — can't be shown to a human panel.</i>
            </span>
          </button>
        </span>
      )}
    </span>
  );
}

// ---------- the control, as a tab row over the intake ----------
// Real tabs, not cards: the row is bottom-connected to everything below it, so
// the depth visibly governs the audience design rather than sitting beside it.
function TierTabs({ value, recommended, onChange, designs, confidential, pool, phase = "ready", step = 5 }) {
  const waiting = phase === "wait";
  const thinking = phase === "thinking";
  // While the objective is still being framed the depths are genuinely unknown,
  // so the row shows its shape and nothing more.
  const rowReady = (ix) => phase === "ready" || step > ix;
  return (
    <div className={"ix-ttabs" + (waiting ? " is-wait" : "") + (thinking ? " is-thinking" : "")}>
      <div className="ix-ttabs__row" role="tablist" aria-label="Research depth">
        {TIER_ORDER.map(id => {
          const t = TIER_SPECS[id];
          const m = tierMetrics(id, (designs || {})[id], { confidential, pool });
          const on = id === value;
          const d = (designs || {})[id];
          const edited = !!d && (d.profiles !== t.profiles || d.markets !== t.markets || d.filters !== t.filters || d.demos !== t.demos);
            const cell = (ix, label, val, extra, tip) => (
              <span className={"ix-ttab__row" + (extra || "")} tabIndex={(tip || extra) && rowReady(ix) ? 0 : undefined} data-tip={rowReady(ix) ? (tip || (extra ? mixNote(m) : undefined)) : undefined}>
                <span>{label}</span>
                {rowReady(ix) ? <b>{val}</b> : <b className="ix-skb" aria-hidden="true" />}
              </span>
            );
            return (
            <button key={id} role="tab" aria-selected={on} disabled={waiting} className={"ix-ttab" + (on ? " is-on" : "")} onClick={() => !waiting && onChange(id)}>
              {/* slot is always present so meters and names stay aligned across tabs */}
              <span className="ix-ttab__slot">{!waiting && id === recommended && <span className="ix-ttab__badge">Suggested</span>}</span>
              <span className="ix-ttab__top">
                <TierMeter level={TIER_LEVEL[id]} />
                <span className="ix-ttab__lab">{t.label}</span>
              </span>
              <span className="ix-ttab__rows">
                {cell(0, "Delivery", t.delivery)}
                {cell(1, "Sample", "~" + m.n.toLocaleString())}
                {cell(2, "Twin mix", m.twin + "%", " ix-ttab__row--tip", m.mix && m.mix.why ? m.mix.why : null)}
                {cell(3, "Support", t.support)}
              </span>
            </button>
          );
        })}
      </div>
      {(pool || []).length > 0 && (
        <div className="ix-ttabs__note">
          <b>Same accuracy where we have history. Real people where we don't.</b>
          <span>{window.FW.backtestLine()}</span>
        </div>
      )}
    </div>
  );
}

// A row of granularity this depth can't fund — shown, not hidden, so the
// comparison is legible without switching tabs.
function GhostRow({ label, unlock, tier, onRestore }) {
  if (!unlock) return null;
  // Affordable at the depth you're already on == you removed it. Offer it back
  // rather than telling someone to upgrade to recover what they have.
  const affordable = TIER_ORDER.indexOf(unlock) <= TIER_ORDER.indexOf(tier);
  if (affordable) {
    return (
      <div className="ix-ghost is-restorable">
        <span className="ix-ghost__l">{label}</span>
        {onRestore
          ? <button type="button" className="ix-ghost__r" onClick={onRestore}>Removed · restore</button>
          : <span className="ix-ghost__u">Removed</span>}
      </div>
    );
  }
  return (
    <div className="ix-ghost">
      <span className="ix-ghost__l">{label}</span>
      <span className="ix-ghost__u">Available at {specOf(unlock).label}</span>
    </div>
  );
}

Object.assign(window, { TIER_SPECS, TIER_ORDER, TIER_LEVEL, TierMeter, specOf, unlockTier, tierMetrics, mixNote, recommendTier, DepthPicker, TierTabs, GhostRow });
