/* Shared wizard logic — hooks and primitive components used by all 5 variations.
   Exposes everything to window so other Babel scripts can use them. */

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

// ─── Hooks ───────────────────────────────────────────────────────────────
function useRoute() {
  const [route, setRoute] = useState(() => window.parseRoute());
  const setLang = useCallback((lang) => setRoute(r => ({ ...r, lang })), []);
  const setRole = useCallback((role) => setRoute(r => ({ ...r, role })), []);
  return { ...route, setLang, setRole };
}

function useT(lang, role) {
  return window.getT ? window.getT(lang, role) : (window.I18N[lang] || window.I18N.en);
}

function useClient(id) {
  return window.CLIENTS[id] || { name: id || 'friend', contact: '' };
}

// Persist wizard answers to localStorage keyed by client ID.
function useWizard(clientId, totalSteps, instanceKey = 'v1') {
  const storageKey = `cf-${instanceKey}-${clientId}`;
  const [state, setState] = useState(() => {
    try {
      const raw = localStorage.getItem(storageKey);
      if (raw) return JSON.parse(raw);
    } catch (e) {}
    return { step: 0, answers: {}, started: false, done: false };
  });
  useEffect(() => {
    try { localStorage.setItem(storageKey, JSON.stringify(state)); } catch (e) {}
  }, [state, storageKey]);

  const next = useCallback(() => setState(s => ({ ...s, step: Math.min(s.step + 1, totalSteps) })), [totalSteps]);
  const back = useCallback(() => setState(s => ({ ...s, step: Math.max(s.step - 1, 0) })), []);
  const setAnswer = useCallback((k, v) => setState(s => ({ ...s, answers: { ...s.answers, [k]: v } })), []);
  const start = useCallback(() => setState(s => ({ ...s, started: true })), []);
  const finish = useCallback(() => setState(s => ({ ...s, done: true })), []);
  const reset = useCallback(() => setState({ step: 0, answers: {}, started: false, done: false }), []);

  return { state, setState, next, back, setAnswer, start, finish, reset };
}

// ─── Confetti generator ────────────────────────────────────────────────
function Confetti({ count = 60 }) {
  const pieces = useMemo(() => Array.from({ length: count }, (_, i) => {
    const colors = [
      'oklch(0.78 0.13 65)', 'oklch(0.78 0.06 150)', 'oklch(0.85 0.12 90)',
      'oklch(0.7 0.16 30)', 'oklch(0.94 0.012 80)',
    ];
    return {
      left: Math.random() * 100,
      delay: Math.random() * 1.2,
      duration: 2.4 + Math.random() * 2,
      color: colors[i % colors.length],
      rot: Math.random() * 360,
      shape: i % 3,
    };
  }), [count]);
  return (
    <div className="cf-confetti">
      {pieces.map((p, i) => (
        <i key={i} style={{
          left: p.left + '%',
          background: p.color,
          animationDelay: p.delay + 's',
          animationDuration: p.duration + 's',
          transform: `rotate(${p.rot}deg)`,
          borderRadius: p.shape === 0 ? '0' : p.shape === 1 ? '50%' : '2px',
        }} />
      ))}
    </div>
  );
}

// ─── Lang switcher ─────────────────────────────────────────────────────
function LangSwitcher({ lang, onChange }) {
  return (
    <div className="cf-lang" role="group" aria-label="Language">
      {['en', 'ru', 'uk'].map(l => (
        <button key={l} aria-pressed={lang === l} onClick={() => onChange(l)}>
          {l}
        </button>
      ))}
    </div>
  );
}

// ─── NPS scale ─────────────────────────────────────────────────────────
function NpsScale({ value, onChange, onAutoAdvance, t }) {
  const cat = (n) => {
    if (n == null) return '';
    if (n <= 6) return t.q.nps.cat_detractor || (t.locale === 'ru' ? 'Критик' : t.locale === 'uk' ? 'Критик' : 'Detractor');
    if (n <= 8) return t.q.nps.cat_passive || (t.locale === 'ru' ? 'Нейтрал' : t.locale === 'uk' ? 'Нейтрал' : 'Passive');
    return t.q.nps.cat_promoter || (t.locale === 'ru' ? 'Промоутер' : t.locale === 'uk' ? 'Промоутер' : 'Promoter');
  };
  const handle = (n) => {
    onChange(n);
    if (onAutoAdvance) setTimeout(() => onAutoAdvance(), 480);
  };
  return (
    <div>
      <div className="cf-nps">
        {Array.from({ length: 11 }, (_, n) => (
          <button key={n} aria-pressed={value === n} onClick={() => handle(n)}>{n}</button>
        ))}
      </div>
      <div className="cf-nps-ends">
        <span>0 — {t.q.nps.scale_low}</span>
        <span>{t.q.nps.scale_high} — 10</span>
      </div>
      <div className="cf-nps-live" key={value} style={{ opacity: value == null ? 0 : 1 }}>
        {value != null ? `→ ${cat(value)}` : ''}
      </div>
    </div>
  );
}

// ─── Mood ──────────────────────────────────────────────────────────────
const MOOD_FACES = ['😞', '😕', '😐', '🙂', '😍'];
function MoodPicker({ value, onChange, onAutoAdvance, t }) {
  const handle = (i) => {
    onChange(i);
    if (onAutoAdvance) setTimeout(() => onAutoAdvance(), 600);
  };
  return (
    <div className="cf-moods">
      {t.q.mood.moods.map((label, i) => (
        <button key={i} className="cf-mood" aria-pressed={value === i} onClick={() => handle(i)}>
          <span className="cf-mood-face">{MOOD_FACES[i]}</span>
          <span className="cf-mood-label">{label}</span>
        </button>
      ))}
    </div>
  );
}

// ─── Checks ────────────────────────────────────────────────────────────
function CheckGrid({ options, value = [], onChange }) {
  const toggle = (opt) => {
    const has = value.includes(opt);
    onChange(has ? value.filter(v => v !== opt) : [...value, opt]);
  };
  return (
    <div className="cf-checks">
      {options.map(opt => (
        <button key={opt} className="cf-check" aria-pressed={value.includes(opt)} onClick={() => toggle(opt)}>
          <span className="cf-check-box" />
          <span>{opt}</span>
        </button>
      ))}
    </div>
  );
}

// ─── Open question (text + fake voice + fake attachments) ─────────────
function OpenQuestion({ value = {}, onChange, t }) {
  const [recording, setRecording] = useState(false);
  const [recTime, setRecTime] = useState(0);
  const recTimer = useRef();
  const fileRef = useRef();

  const text = value.text || '';
  const voice = value.voice || null; // { duration: 7 }
  const files = value.files || [];

  useEffect(() => {
    if (recording) {
      setRecTime(0);
      recTimer.current = setInterval(() => setRecTime(t => t + 1), 1000);
    } else {
      clearInterval(recTimer.current);
    }
    return () => clearInterval(recTimer.current);
  }, [recording]);

  const toggleRec = () => {
    if (recording) {
      setRecording(false);
      onChange({ ...value, voice: { duration: recTime || 1 } });
    } else {
      setRecording(true);
    }
  };

  const onFiles = (e) => {
    const list = Array.from(e.target.files || []).map(f => ({ name: f.name, size: f.size }));
    onChange({ ...value, files: [...files, ...list] });
    e.target.value = '';
  };

  const fmtTime = (n) => `${Math.floor(n/60)}:${String(n%60).padStart(2, '0')}`;
  const fmtSize = (b) => b < 1024 ? `${b}B` : b < 1048576 ? `${Math.round(b/1024)}KB` : `${(b/1048576).toFixed(1)}MB`;

  return (
    <div>
      <textarea
        className="cf-open-text"
        placeholder={t.q.open.placeholder}
        value={text}
        rows={5}
        onChange={e => onChange({ ...value, text: e.target.value })}
      />
      <div className="cf-open-meta">
        <span className={text.length > 30 ? 'warm' : ''}>
          {text.length === 0 ? (t.locale === 'ru' ? 'Чем подробнее — тем полезнее' : t.locale === 'uk' ? 'Чим детальніше — тим корисніше' : 'The more detail, the better')
            : text.length < 30 ? (t.locale === 'ru' ? 'Продолжай…' : t.locale === 'uk' ? 'Продовжуй…' : 'Keep going…')
            : (t.locale === 'ru' ? 'Спасибо, это уже золото' : t.locale === 'uk' ? 'Дякую, це вже золото' : 'Thanks, this is gold')}
        </span>
        <span>{text.length} / 2000</span>
      </div>
      <div className="cf-open-actions">
        <button className="cf-open-action" data-recording={recording} onClick={toggleRec}>
          {recording ? <><span className="cf-rec-dot" />{t.q.open.recordingLabel} · {fmtTime(recTime)}</> : <>🎙 {t.q.open.recordLabel}</>}
        </button>
        <button className="cf-open-action" onClick={() => fileRef.current.click()}>
          📎 {t.q.open.attachLabel}
        </button>
        <input ref={fileRef} type="file" multiple style={{ display: 'none' }} onChange={onFiles} />
      </div>
      {(voice || files.length > 0) && (
        <div className="cf-attachments">
          {voice && (
            <div className="cf-attachment">
              <span className="cf-rec-dot" /> {t.q.open.recordedLabel} · {fmtTime(voice.duration)}
              <span className="cf-attachment-x" onClick={() => onChange({ ...value, voice: null })}>×</span>
            </div>
          )}
          {files.map((f, i) => (
            <div key={i} className="cf-attachment">
              <span>📎</span> {f.name} <span style={{ opacity: 0.5 }}>· {fmtSize(f.size)}</span>
              <span className="cf-attachment-x" onClick={() => onChange({ ...value, files: files.filter((_, j) => j !== i) })}>×</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ─── Done screen content (shared) ─────────────────────────────────────
function DoneCheckmark() {
  return (
    <div className="cf-checkmark">
      <svg viewBox="0 0 44 44">
        <path d="M10 22 L19 31 L34 14" />
      </svg>
    </div>
  );
}

// Inline ladder for {v, label} levels — same pattern as variationCTO.
function Ladder({ levels, value, onChange }) {
  return (
    <div className="cto-ladder">
      {levels.map(lv => (
        <button
          key={lv.v}
          className="cto-ladder-step"
          data-level={lv.v}
          aria-pressed={value === lv.v}
          onClick={() => onChange(value === lv.v ? undefined : lv.v)}
        >
          <span className="cto-ladder-num cf-mono">{String(lv.v).padStart(2, '0')}</span>
          <span className="cto-ladder-label">{lv.label}</span>
          <span className="cto-ladder-mark" />
        </button>
      ))}
    </div>
  );
}

// Build a question registry: a list of {key, render(answers, set, t)} for the wizard.
// Each variation renders the title/lead/kicker; we provide just the input.
function makeQuestions(t) {
  const q = t.q;
  return [
    { key: 'nps', kicker: q.nps.kicker, title: q.nps.title, lead: q.nps.lead,
      render: (a, set, onAuto) => <NpsScale value={a.nps} onChange={v => set('nps', v)} onAutoAdvance={onAuto} t={t} />,
      isAnswered: a => typeof a.nps === 'number',
    },
    { key: 'mood', kicker: q.mood.kicker, title: q.mood.title, lead: q.mood.lead,
      render: (a, set, onAuto) => <MoodPicker value={a.mood} onChange={v => set('mood', v)} onAutoAdvance={onAuto} t={t} />,
      isAnswered: a => typeof a.mood === 'number',
    },
    { key: 'onboard', kicker: q.onboard.kicker, title: q.onboard.title, lead: q.onboard.lead,
      render: (a, set) => <CheckGrid options={q.onboard.options} value={a.onboard} onChange={v => set('onboard', v)} />,
      isAnswered: a => Array.isArray(a.onboard) && a.onboard.length > 0,
    },
    { key: 'comm', kicker: q.comm.kicker, title: q.comm.title, lead: q.comm.lead,
      render: (a, set) => <CheckGrid options={q.comm.options} value={a.comm} onChange={v => set('comm', v)} />,
      isAnswered: a => Array.isArray(a.comm) && a.comm.length > 0,
    },
    { key: 'timeline', kicker: q.timeline.kicker, title: q.timeline.title, lead: q.timeline.lead,
      render: (a, set) => <CheckGrid options={q.timeline.options} value={a.timeline} onChange={v => set('timeline', v)} />,
      isAnswered: a => Array.isArray(a.timeline) && a.timeline.length > 0,
    },
    { key: 'change', kicker: q.change.kicker, title: q.change.title, lead: q.change.lead,
      render: (a, set) => <Ladder levels={q.change.levels} value={a.change} onChange={v => set('change', v)} />,
      isAnswered: a => typeof a.change === 'number',
    },
    { key: 'proactive', kicker: q.proactive.kicker, title: q.proactive.title, lead: q.proactive.lead,
      render: (a, set, onAuto) => <NpsScale value={a.proactive} onChange={v => set('proactive', v)} onAutoAdvance={onAuto} t={{ ...t, q: { ...t.q, nps: { ...q.nps, scale_low: q.proactive.scale_low, scale_high: q.proactive.scale_high } } }} />,
      isAnswered: a => typeof a.proactive === 'number',
    },
    { key: 'quality', kicker: q.quality.kicker, title: q.quality.title, lead: q.quality.lead,
      render: (a, set) => <CheckGrid options={q.quality.options} value={a.quality} onChange={v => set('quality', v)} />,
      isAnswered: a => Array.isArray(a.quality) && a.quality.length > 0,
    },
    { key: 'impact', kicker: q.impact.kicker, title: q.impact.title, lead: q.impact.lead,
      render: (a, set) => <Ladder levels={q.impact.levels} value={a.impact} onChange={v => set('impact', v)} />,
      isAnswered: a => typeof a.impact === 'number',
    },
    { key: 'money', kicker: q.money.kicker, title: q.money.title, lead: q.money.lead,
      render: (a, set, onAuto) => <NpsScale value={a.money} onChange={v => set('money', v)} onAutoAdvance={onAuto} t={{ ...t, q: { ...t.q, nps: { ...q.nps, scale_low: q.money.scale_low, scale_high: q.money.scale_high } } }} />,
      isAnswered: a => typeof a.money === 'number',
    },
    { key: 'trust', kicker: q.trust.kicker, title: q.trust.title, lead: q.trust.lead,
      render: (a, set) => <TrustMeter items={q.trust.list.map(it => ({ ...it, levels: q.trust.levels }))} value={a.trust || {}} onChange={v => set('trust', v)} />,
      isAnswered: a => a.trust && Object.keys(a.trust).length > 0,
    },
    { key: 'pairs', kicker: q.pairs.kicker, title: q.pairs.title, lead: q.pairs.lead,
      render: (a, set) => <WordPair pairs={q.pairs.list} value={a.pairs || {}} onChange={v => set('pairs', v)} />,
      isAnswered: a => a.pairs && Object.keys(a.pairs).length > 0,
    },
    { key: 'steal', kicker: q.steal.kicker, title: q.steal.title, lead: q.steal.lead,
      render: (a, set) => <StealPicker tags={q.steal.tags} value={a.steal || []} onChange={v => set('steal', v)} max={3} />,
      isAnswered: a => Array.isArray(a.steal) && a.steal.length > 0,
    },
    { key: 'sort', kicker: q.sort.kicker, title: q.sort.title, lead: q.sort.lead,
      render: (a, set) => <SortablePriorities items={q.sort.items} value={a.sort} onChange={v => set('sort', v)} />,
      isAnswered: () => true,
    },
    { key: 'risk', kicker: q.risk.kicker, title: q.risk.title, lead: q.risk.lead,
      render: (a, set) => <RiskFlag value={a.risk || {}} onChange={v => set('risk', v)} placeholder={q.risk.placeholder} severityLow={q.risk.sevLow} severityHigh={q.risk.sevHigh} />,
      isAnswered: () => true,
    },
    { key: 'again', kicker: q.again.kicker, title: q.again.title, lead: q.again.lead,
      render: (a, set) => <YesNoWithReason value={a.again || {}} onChange={v => set('again', v)} yesLabel={q.again.yes} noLabel={q.again.no} reasonPlaceholder={q.again.reasonPlaceholder} />,
      isAnswered: a => a.again && a.again.choice != null,
    },
    { key: 'open', kicker: q.open.kicker, title: q.open.title, lead: q.open.lead,
      render: (a, set) => <OpenQuestion value={a.open} onChange={v => set('open', v)} t={t} />,
      isAnswered: () => true,
    },
  ];
}

Object.assign(window, {
  useRoute, useT, useClient, useWizard,
  Confetti, LangSwitcher, NpsScale, MoodPicker, CheckGrid, OpenQuestion, DoneCheckmark,
  makeQuestions, MOOD_FACES,
});
