// Shared constants

const QUESTION_TYPES = [
  { id: 'short', label: 'Short answer', glyph: '—' },
  { id: 'long', label: 'Paragraph', glyph: '¶' },
  { id: 'single', label: 'Single choice', glyph: '◉' },
  { id: 'multi', label: 'Multi choice', glyph: '▣' },
  { id: 'dropdown', label: 'Dropdown', glyph: '▾' },
  { id: 'dropdown-search', label: 'Dropdown with search', glyph: '⌕' },
  { id: 'scale', label: 'Linear scale', glyph: '┄' },
  { id: 'number', label: 'Number', glyph: '#' },
  { id: 'vibe', label: 'Tap to vibe-check', glyph: '◐' },
];

// 3-state vibe-check question type. Tap cycles untapped → 0 → 1 → 2 → untapped.
// Colors always green / yellow / red (in that order). Labels are customisable per question.
const VIBE_COLORS = ['#9ec27e', '#e6c14a', '#dc8866'];
const VIBE_DEFAULTS = ['love', 'meh', 'nope'];

// Parses a bulk-paste blob into a vibeGroups array.
// Lines with a comma are items: "CODE, Label". Lines without a comma start a new group.
// Blank lines are ignored.
function parseVibeBulk(text) {
  const groups = [];
  let current = null;
  let stamp = Date.now();
  for (const raw of String(text || '').split('\n')) {
    const line = raw.trim();
    if (!line) continue;
    const ci = line.indexOf(',');
    if (ci === -1) {
      current = { id: 'g' + (stamp++), name: line, items: [] };
      groups.push(current);
    } else {
      if (!current) {
        current = { id: 'g' + (stamp++), name: '', items: [] };
        groups.push(current);
      }
      const code = line.slice(0, ci).trim();
      const label = line.slice(ci + 1).trim();
      if (code) current.items.push({ id: 'i' + (stamp++), code, label: label || code });
    }
  }
  return groups.length ? groups : [{ id: 'g' + Date.now(), name: '', items: [] }];
}

// Rough time to complete, by question type. Calibrated (Oct 2026) against the
// median durations of live surveys: good-lovers 112s (estimate 124s),
// wm-der-liebhaber 127s (116s), speak-to-the-media 241s (222s).
function estimateSurveySeconds(survey) {
  const qs = (survey && survey.questions) || [];
  let sec = 10 + (survey && survey.prizeDraw && survey.prizeDraw.enabled ? 5 : 0); // intro, submit, email
  for (const q of qs) {
    const opts = (q.options || []).length + (q.allowOther ? 1 : 0);
    switch (q.type) {
      case 'single': sec += 4 + 1.2 * opts; break;
      case 'multi': sec += 6 + 1.5 * opts; break;
      case 'dropdown': sec += 7; break;
      case 'dropdown-search': sec += 9; break;
      case 'scale': sec += 5; break;
      case 'number': sec += 7; break;
      case 'short': sec += 15; break;
      case 'long': sec += q.required ? 60 : 30; break; // optional ones are often skipped
      case 'vibe': sec += 3 + (q.vibeGroups || []).reduce((n, g) => n + (g.items || []).length, 0); break;
      default: sec += 10;
    }
  }
  return sec;
}
function estimateSurveyMinutes(survey) {
  return Math.max(1, Math.round(estimateSurveySeconds(survey) / 60));
}
function surveyDurationLabel(survey) {
  const m = estimateSurveyMinutes(survey);
  return m === 1 ? tr(survey.lang, 'aboutMinute') : tr(survey.lang, 'aboutMinutes', { n: m });
}

// Fixed participant-facing text (buttons, labels, messages). Question text is
// whatever the author writes; this only covers the chrome around it.
const UI_LANGS = [['en', 'English'], ['de', 'Deutsch']];
const UI_STRINGS = {
  en: {
    eyebrowSurvey: 'Erobella · Survey', eyebrowAnon: 'Erobella · Anonymous survey',
    question: 'question', questions: 'questions',
    aboutMinute: 'about a minute', aboutMinutes: 'about {n} minutes',
    anonNote: 'Your answers are anonymous.', leaveAnyTime: 'You can leave at any time.',
    submit: 'Submit', submitAnon: 'Submit anonymously',
    confirm18: "By submitting you confirm you're 18+.", storesAnswers: 'Erobella stores answers, not identities.',
    qLabel: 'Q', required: 'required', requiredError: 'This question is required.',
    typeAnswer: 'Type your answer…', otherSpecify: 'Other (please specify)', chooseOne: 'Choose one…',
    otherDots: 'Other…', pleaseSpecify: 'Please specify', search: 'Search…', noMatches: 'No matches',
    useOther: 'Use "Other: {q}"', otherLabel: 'Other:', empty: '(empty)',
    clear: 'Clear', untapped: 'untapped', dontKnow: "don't know",
    gateEyebrow: 'Adults only', gateQ1: 'Are you ', gateEm: '18 or over', gateQ2: '?',
    gateBody: 'Erobella collects research from adults only. This survey is hosted by our team in Amsterdam and falls under EU data-protection law.',
    gateYes: "Yes, I'm 18 or over", gateNo: 'No, take me back',
    recorded: 'Response recorded', thanksTitle: 'Thank you.', inDraw: "You're in the prize draw. Good luck!",
    prizeEyebrow: 'Prize draw · optional', emailPlaceholder: 'Your email',
    emailAria: 'Email for the prize draw', emailBad: "That email doesn't look right.",
    stepHint: 'Use − / +, or tap the number to type', stepRange: 'Enter a number from {lo} to {hi}',
    stepMin: 'Enter {lo} or more', stepMax: '{hi} is the maximum', inc: 'Increase', dec: 'Decrease', numberAria: 'Number',
    alertRequired: 'Please answer all required questions.', alertEmail: 'Please check your email address.',
    alertFailed: 'Submit failed.', alertOffline: 'Could not submit right now.',
  },
  de: {
    eyebrowSurvey: 'Erobella · Umfrage', eyebrowAnon: 'Erobella · Anonyme Umfrage',
    question: 'Frage', questions: 'Fragen',
    aboutMinute: 'etwa eine Minute', aboutMinutes: 'etwa {n} Minuten',
    anonNote: 'Deine Antworten sind anonym.', leaveAnyTime: 'Du kannst jederzeit abbrechen.',
    submit: 'Absenden', submitAnon: 'Anonym absenden',
    confirm18: 'Mit dem Absenden bestätigst du, dass du mindestens 18 Jahre alt bist.', storesAnswers: 'Erobella speichert Antworten, keine Identitäten.',
    qLabel: 'F', required: 'Pflichtfrage', requiredError: 'Bitte beantworte diese Frage.',
    typeAnswer: 'Deine Antwort…', otherSpecify: 'Sonstiges (bitte angeben)', chooseOne: 'Bitte auswählen…',
    otherDots: 'Sonstiges…', pleaseSpecify: 'Bitte angeben', search: 'Suchen…', noMatches: 'Keine Treffer',
    useOther: '„Sonstiges: {q}“ verwenden', otherLabel: 'Sonstiges:', empty: '(leer)',
    clear: 'Löschen', untapped: 'nicht angetippt', dontKnow: 'weiß nicht',
    gateEyebrow: 'Nur für Erwachsene', gateQ1: 'Bist du ', gateEm: '18 oder älter', gateQ2: '?',
    gateBody: 'Erobella befragt ausschließlich Erwachsene. Diese Umfrage wird von unserem Team in Amsterdam durchgeführt und unterliegt dem EU-Datenschutzrecht.',
    gateYes: 'Ja, ich bin 18 oder älter', gateNo: 'Nein, zurück zu Erobella',
    recorded: 'Antwort gespeichert', thanksTitle: 'Danke.', inDraw: 'Du bist beim Gewinnspiel dabei. Viel Glück!',
    prizeEyebrow: 'Gewinnspiel · freiwillig', emailPlaceholder: 'Deine E-Mail-Adresse',
    emailAria: 'E-Mail-Adresse für das Gewinnspiel', emailBad: 'Diese E-Mail-Adresse sieht nicht richtig aus.',
    stepHint: 'Mit − / + oder tippe auf die Zahl, um sie einzugeben', stepRange: 'Gib eine Zahl von {lo} bis {hi} ein',
    stepMin: 'Gib {lo} oder mehr ein', stepMax: '{hi} ist das Maximum', inc: 'Mehr', dec: 'Weniger', numberAria: 'Zahl',
    alertRequired: 'Bitte beantworte alle Pflichtfragen.', alertEmail: 'Bitte überprüfe deine E-Mail-Adresse.',
    alertFailed: 'Absenden fehlgeschlagen.', alertOffline: 'Absenden ist gerade nicht möglich. Bitte versuch es gleich noch mal.',
  },
};
function tr(lang, key, vars) {
  const table = UI_STRINGS[lang] || UI_STRINGS.en;
  let s = table[key] !== undefined ? table[key] : UI_STRINGS.en[key];
  if (vars) for (const k in vars) s = s.split('{' + k + '}').join(vars[k]);
  return s;
}
const LangContext = React.createContext('en');
function useT() {
  const lang = React.useContext(LangContext);
  return (key, vars) => tr(lang, key, vars);
}

Object.assign(window, { QUESTION_TYPES, VIBE_COLORS, VIBE_DEFAULTS, parseVibeBulk, estimateSurveySeconds, estimateSurveyMinutes, surveyDurationLabel, UI_LANGS, UI_STRINGS, tr, LangContext, useT });
