/* ───────────────────────────────────────────────────────────────────────────
   Martes AI · Assessment POST formazione, il form di Farvima
   Si compila qualche settimana dopo le giornate del 22 e 23 settembre:
     /post/farvima/                        link unico, chiede nome e ruolo
     /post/farvima/?r=<recordId del pre>   link personale, rilegge il pre
   Anche /post/?c=farvima arriva qui, dal rinvio in functions/post/index.js.

   Nato il 09/10 come copia di /post/adsp/adsp.jsx, il form piu' aggiornato
   (efficienza dentro le cose costruite, «Possiamo citarti?» con nome e
   ruolo), senza il Company Brain: fuori le due domande della sezione, la
   voce dell'attesa fra i motivi di blocco e quella fra le cose che servono.
   Le parole sono quelle di un'azienda: reparto e azienda, non ufficio ed Ente.
   Da qui in poi i due file non si tengono allineati.

   Differenza dal form pre (typeform.jsx): il flusso non e' una lista fissa,
   si ricostruisce a ogni risposta. Serve perche' il blocco "una cosa che hai
   costruito" si ripete N volte e perche' meta' delle domande compaiono solo
   per chi ha costruito qualcosa. Le domande e il motivo di ognuna stanno in
   Resources/design-docs/2026-09-24-assessment-post-formazione.md del vault.
   ─────────────────────────────────────────────────────────────────────────── */

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

// ── opzioni ──────────────────────────────────────────────────────────────────

const FREQ = [
  'Ogni giorno',
  'Due o tre volte a settimana',
  'Una volta a settimana',
  'Una volta al mese',
  "L'ho costruita ma non la uso",
];

// Dal 06/10 se ne spuntano quante servono, e ognuna apre le sue domande: una
// cosa costruita puo' far risparmiare tempo, farne fare una nuova e far
// lavorare meglio, tutto insieme. "Tutte e due" con tre voci non reggeva piu'.
const TIPO = [
  'Mi fa risparmiare tempo',
  'È una cosa in più, prima non potevo farla',
  'Lavoro in modo più efficiente',
];
// chi aveva il form aperto prima del cambio ha in memoria una risposta sola
const tipiScelti = (v) => {
  if (Array.isArray(v)) return v;
  if (v === 'Tutte e due') return [TIPO[0], TIPO[1]];
  return v ? [v] : [];
};

// In cosa e' migliorata: come per le cose in piu', una voce che si conta
// accanto alla frase libera. Quante volte capita lo dice gia' "Ogni quanto la
// usi?".
const GENERE_EFFICIENZA = [
  'Meno errori e meno cose da rifare',
  'Meno passaggi fra persone e uffici',
  'Un risultato più completo e più curato',
  'La faccio sempre allo stesso modo, con un metodo',
  // con il suo campo libero (Riccardo, 06/10)
  'Altro',
];

// Il gruppo di lavoro e l'organizzazione hanno il nome che gli da' il
// cliente: qui reparto e azienda. Le voci stanno nella scheda, chiavi
// usa_gruppo, resto_gruppo e tutta_org.
const chiOpzioni = (testi) => [
  'Solo io',
  'L’ho passata a un collega',
  testi.usaGruppo,
  testi.tuttaOrg,
];

const BANDS = ['Meno di 1h', '1-2h', '3-5h', 'Più di 5h'];

const ORE_TORNATE = ['Nessuna', 'Meno di 1h', '1-3h', '3-5h', '5-10h', 'Più di 10h', 'Scrivilo tu'];

const BLOCCO = [
  'Non ho avuto tempo',
  'Mi sono bloccato su un problema tecnico che non ho risolto',
  'Mi manca un accesso o un permesso',
  'Non so da dove ripartire',
  'Quello che avevo provato non funzionava abbastanza bene',
];

// "Un punto fisso al mese dove porto i miei blocchi" non si capiva (Marco
// Pili, 30/09): "blocchi" nel form sono anche le cose costruite.
const serveOpzioni = (testi) => [
  'Un incontro fisso al mese per sbloccare i punti dove mi sono fermato',
  'Un corso in ordine da seguire da solo',
  // era "la cosa grossa al posto nostro": non diceva di cosa (Riccardo, 30/09)
  'Qualcuno che costruisca per noi gli strumenti più complessi',
  testi.restoGruppo,
  'Niente, vado',
];

const WORKSHOP = ['Sì, prima possibile', 'Sì, più avanti', 'No'];

// I programmi dove passa la giornata. Categorie e non marchi: nel pre di AdSP
// la stessa suite era scritta in sette modi ("word", "World", "office",
// "Pacchetto Office"...) e un conto su sette grafie non si fa. La lista vera
// sta nella scheda del cliente (chiave "software"), questa e' quella per chi
// non ce l'ha. "Altro" apre un campo per scrivere quale.
const PROGRAMMI_GENERICI = [
  'Posta e calendario',
  'Documenti e fogli di calcolo',
  'Gestionale',
  'CRM',
  'Presentazioni e grafica',
  'Altro',
];

const TEMPO_PROGRAMMA = ['Molto meno', 'Un po’ meno', 'Uguale', 'Di più'];
// le due risposte dopo cui le ore in meno diventano obbligatorie
const MENO = TEMPO_PROGRAMMA.slice(0, 2);

// Che tipo di cosa in piu': ogni voce diventa un numero che si conta, invece
// di trenta frasi libere su una slide
const GENERE = [
  'Un controllo o un’analisi che prima saltavo',
  'Lo stesso lavoro su molti più casi',
  'Un lavoro che prima chiedevo a un collega o a un esterno',
  'Una cosa che prima non sapevo fare (dati, codice, un’altra lingua)',
];

const STRAORDINARIO = 'Ore di straordinario';
const NESSUNA_SPESA = 'Nessuna';
// Chiesta da Maurizio Selis (04/10): chi non ha evitato una spesa ma lavora
// meglio non si riconosceva in "Nessuna". Dal 06/10 non dice piu' "Nessuna
// spesa, ma": si puo' spuntare insieme a una spesa vera, quindi non e' piu'
// una voce del no. Resta fuori dalle spese: non apre "Quale spesa hai evitato?".
const SPESA_EFFICIENZA = 'Lavoro in modo più efficiente';
// "Non tutti hanno la capacita' di quantificare un risparmio" (Luca Melis)
const SPESA_NON_SO = 'Non saprei quantificarla';
// le voci del no, che spengono le altre
const SPESA_NO = [NESSUNA_SPESA, SPESA_NON_SO];
// le voci che non sono una spesa da descrivere
const SENZA_SPESA = [NESSUNA_SPESA, SPESA_EFFICIENZA, SPESA_NON_SO];
const SPESE = [
  'Una consulenza esterna',
  'Un lavoro che prima si faceva fare fuori',
  'Un software che avremmo dovuto comprare',
  STRAORDINARIO,
  'Altro',
  SPESA_EFFICIENZA,
  SPESA_NON_SO,
  NESSUNA_SPESA,
];

const NUMERI = ['zero', 'una', 'due', 'tre', 'quattro', 'cinque'];

// I programmi scelti, con il nome da mostrare: "Altro" prende quello scritto
// a mano. L'id della schermata resta quello della categoria, cosi' correggere
// il nome scritto non fa perdere la risposta gia' data.
function programmiScelti(answers) {
  const scelti = Array.isArray(answers.programmi) ? answers.programmi : [];
  return scelti.map((nome) => ({
    id: `prog_${slugify(nome)}`,
    nome: nome === 'Altro' && (answers.programmi_altro || '').trim() ? answers.programmi_altro.trim() : nome,
  }));
}

// Farvima ha gia' dato l'ok a essere nominata (26/09): qui la persona decide
// solo se accanto al ruolo compare anche il suo nome
const citazioneOpzioni = (testi) => [
  testi.citazioneNome,
  'Sì, ma solo con il mio ruolo',
  'No, resta fra noi',
];

// Quali attivita' del pre la persona dice di aver coperto, nelle due forme
// della domanda (si'/no quando ne aveva una sola, lista quando erano di piu').
function coperteScelte(answers, attivita) {
  if (!attivita.length) return [];
  if (attivita.length === 1) return answers.coperte === 'Sì' ? [attivita[0].testo] : [];
  const scelte = Array.isArray(answers.coperte) ? answers.coperte : [];
  return scelte.filter((x) => x !== 'Su nessuna di queste');
}

// ── flusso ───────────────────────────────────────────────────────────────────
// Ricostruito a ogni render da risposte + dati del pre + numero di blocchi.

function buildFlow(answers, pre, blocks, testi) {
  const F = [];
  const has = (id) => answers[id] !== undefined && answers[id] !== null && answers[id] !== '';

  F.push({
    id: 'cover',
    kind: 'info',
    section: 'Bentornato',
    title: pre && pre.nome ? `Ciao ${pre.nome.split(' ')[0]}, che bello rivederti!` : 'Ciao, che bello rivederti!',
    body:
      `${testi.intro} La parte che ci interessa è questa: cosa ti sei costruito, cosa usi tutti i giorni, cosa è rimasto a metà.`,
    note: 'Ti rubo una decina di minuti :)',
    cta: 'Cominciamo',
  });

  F.push({ id: 'nome', kind: 'text', singleLine: true, section: 'Chi sei', title: 'Come ti chiami?', placeholder: 'Nome e cognome' });
  // Non a riga singola: nell'assessment pre molti hanno risposto con una frase
  // intera ("Mi occupo di pianificazione strategica, formazione e progetti
  // europei"), e riletta dentro una riga sola si vede a meta'
  F.push({ id: 'ruolo', kind: 'text', section: 'Chi sei', title: testi.ruolo, placeholder: testi.ruoloEsempio });

  F.push({
    id: 'gate',
    kind: 'single',
    section: 'Cosa hai costruito',
    title: 'Dopo le giornate hai costruito qualcosa?',
    hint: 'Una skill, una routine, un agente, un file che lavora per te. Anche piccola.',
    options: ['Sì', 'No, non ancora'],
  });

  const haCostruito = answers.gate === 'Sì';

  if (haCostruito) {
    for (let i = 0; i < blocks; i += 1) {
      const p = `b${i}`;
      F.push({
        id: `${p}_cosa`,
        kind: 'text',
        section: 'Cosa hai costruito',
        eyebrow: i === 0 ? 'La prima' : `La numero ${i + 1}`,
        title: 'Cosa fa, in una riga, quello che hai creato?',
        hint: 'Skill, artefatto, routine, altro',
        placeholder: 'Es. prende i dati dai tre gestionali e mi sputa il report…',
      });
      F.push({ id: `${p}_freq`, kind: 'single', section: 'Cosa hai costruito', title: 'Ogni quanto la usi?', options: FREQ });
      const abbandonata = answers[`${p}_freq`] === FREQ[4];
      if (abbandonata) {
        // Una cosa che non usa non ha un "prima" e un "adesso" da misurare, e
        // non la usa nessun collega: si chiede perche' e si passa oltre,
        // invece di farle rispondere quattro domande su un oggetto morto.
        F.push({ id: `${p}_perche`, kind: 'text', section: 'Cosa hai costruito', title: 'Come mai?', placeholder: 'Anche solo una riga, serve a noi per capire dove si rompe…' });
        F.push({
          id: `${p}_altra`,
          kind: 'single',
          section: 'Cosa hai costruito',
          title: 'Hai costruito altro?',
          options: ['Sì, ne ho un’altra', 'No, ho finito'],
        });
        if (answers[`${p}_altra`] !== 'Sì, ne ho un’altra') break;
        continue;
      }
      F.push({
        id: `${p}_tipo`,
        kind: 'multi',
        section: 'Cosa hai costruito',
        // la riga piccola sotto il titolo non si vedeva: sta nel titolo (Riccardo, 06/10)
        title: 'Cosa è cambiato da quando la usi? Puoi selezionarne più di una',
        aiutoNelTitolo: true,
        options: TIPO,
      });
      const tipo = tipiScelti(answers[`${p}_tipo`]);
      const risparmia = tipo.includes(TIPO[0]);
      const inpiu = tipo.includes(TIPO[1]);
      const efficiente = tipo.includes(TIPO[2]);
      if (risparmia) {
        F.push({ id: `${p}_prima`, kind: 'duration', section: 'Cosa hai costruito', title: 'Quanto ci mettevi prima, ogni volta che la facevi a mano?' });
        F.push({ id: `${p}_adesso`, kind: 'duration', section: 'Cosa hai costruito', title: 'Quanto ci metti adesso, dal lancio al risultato?' });
      }
      if (inpiu) {
        F.push({
          id: `${p}_inpiu`,
          kind: 'text',
          section: 'Cosa hai costruito',
          title: 'Cosa riesci a fare adesso che prima non facevi?',
          placeholder: 'Es. controllo tutti i contratti invece dei primi tre',
        });
        F.push({ id: `${p}_genere`, kind: 'single', section: 'Cosa hai costruito', title: 'Che tipo di cosa è?', options: GENERE });
        F.push({ id: `${p}_volte`, kind: 'number', section: 'Cosa hai costruito', title: 'Quante volte a settimana ti capita?', suffix: 'volte a settimana' });
      }
      if (efficiente) {
        F.push({
          id: `${p}_eff`,
          kind: 'text',
          section: 'Cosa hai costruito',
          title: 'Cosa fai in modo più efficiente?',
          placeholder: 'Prima la facevo in modo disorganizzato, ora in maniera strutturata e più efficiente…',
        });
        // Se ne sceglie una sola, ma passa dalla schermata delle scelte
        // multiple perche' e' quella che sa aprire il campo di "Altro": ogni
        // voce spegne le altre.
        F.push({
          id: `${p}_eff_genere`,
          kind: 'multi',
          section: 'Cosa hai costruito',
          title: 'Qual è il miglioramento più grande?',
          options: GENERE_EFFICIENZA,
          esclusiva: GENERE_EFFICIENZA,
          altroId: `${p}_eff_altro`,
          aiutoNelTitolo: true,
        });
      }
      F.push({ id: `${p}_chi`, kind: 'single', section: 'Cosa hai costruito', title: 'La usa qualcun altro oltre a te?', options: chiOpzioni(testi) });
      F.push({
        id: `${p}_altra`,
        kind: 'single',
        section: 'Cosa hai costruito',
        title: 'Hai costruito altro?',
        options: ['Sì, ne ho un’altra', 'No, ho finito'],
      });
      // il blocco successivo lo apre la risposta, non il ciclo
      if (answers[`${p}_altra`] !== 'Sì, ne ho un’altra') break;
    }
  }

  const attivita = (pre && pre.attivita) || [];

  // "Coperta" era una parola nostra: nessuno sa cosa vuol dire. Si chiede se
  // su quell'attivita' ha costruito qualcosa, che e' la stessa cosa detta come
  // si direbbe a voce. Con una sola attivita' e' una domanda si'/no, con due o
  // tre e' una lista da spuntare.
  if (haCostruito && attivita.length === 1) {
    F.push({
      id: 'coperte',
      kind: 'single',
      section: testi.sezionePre,
      quote: taglia(attivita[0].testo, 180),
      quoteNota: `Lo avevi scritto ${testi.quando}`,
      title: 'Hai costruito qualcosa per questa?',
      options: ['Sì', 'No'],
    });
  } else if (haCostruito && attivita.length > 1) {
    F.push({
      id: 'coperte',
      kind: 'multi',
      section: testi.sezionePre,
      title: 'Su quali di queste hai costruito qualcosa?',
      hint: `Sono le attività ripetitive che avevi scritto ${testi.quando}`,
      options: [...attivita.map((a) => a.testo), 'Su nessuna di queste'],
      etichette: Object.fromEntries(attivita.map((a) => [a.testo, taglia(a.testo, 110)])),
    });
  }

  const coperte = coperteScelte(answers, attivita);
  const scoperte = attivita.filter((a) => !coperte.includes(a.testo));

  if (!haCostruito || has('coperte') || !attivita.length) {
    scoperte.forEach((a, i) => {
      F.push({
        id: `sc${i}`,
        kind: 'band',
        section: testi.sezionePre,
        attivita: a,
        quote: taglia(a.testo, 180),
        quoteNota: a.tempo ? `${maiuscola(testi.quando)} ci passavi ${a.tempo} a settimana` : `Lo avevi scritto ${testi.quando}`,
        title: 'Oggi quanto ti prende?',
        options: BANDS,
      });
    });
    if (scoperte.length) {
      F.push({
        id: 'mancato',
        kind: 'text',
        section: testi.sezionePre,
        title: scoperte.length === 1 ? 'Cosa ti è mancato per automatizzarla, almeno in parte?' : 'Cosa ti è mancato per automatizzarle, almeno in parte?',
      });
    }
  }

  // I programmi: chiesti a tutti, anche a chi non ha costruito niente, perche'
  // il tempo in un programma scende anche solo usando la chat. Richiesto da
  // AdSP in call il 30/09: meno tempo sui software e licenze tolte sono il
  // numero che l'ente deve poter dire.
  F.push({
    id: 'programmi',
    kind: 'multi',
    section: 'I programmi che usi',
    title: 'In quali programmi passi più tempo durante la giornata?',
    options: testi.programmi,
    // erano tre: a un tecnico amministrativo non bastavano (Luca Melis), e
    // Maurizio Selis ne ha scritti tre dentro un solo "Altro"
    max: 5,
    altroId: 'programmi_altro',
  });
  // Il nome del programma sta dentro la domanda e non nell'etichetta piccola
  // sopra: con tre programmi di fila le schermate sembravano la stessa, e non
  // si capiva a quale si riferiva (Riccardo, 30/09).
  const scelti = programmiScelti(answers);
  scelti.forEach((pr, i) => {
    F.push({
      id: pr.id,
      kind: 'band',
      section: 'I programmi che usi',
      eyebrow: scelti.length > 1 ? `Programma ${i + 1} di ${scelti.length}` : null,
      title: `${testi.rispetto}, quanto tempo passi oggi su `,
      accento: pr.nome,
      coda: '?',
      options: TEMPO_PROGRAMMA,
      // il disegno resta aperto tutto il giorno mentre si fa altro (Luca Melis)
      hint: 'Conta il tempo in cui ci lavori, non quello in cui resta aperto.',
      numero: { label: 'ore in meno a settimana', solo: MENO },
    });
  });

  // Il secondo cervello si chiede solo a chi l'ha costruito in aula: dove la
  // giornata pratica era su altro, la domanda non ha un oggetto
  if (testi.cervello) F.push({
    id: 'cervello_uso',
    kind: 'single',
    section: 'Il secondo cervello',
    title: 'Quando l’hai aperto l’ultima volta?',
    options: ['Oggi o ieri', 'Questa settimana', 'Questo mese', 'Non lo apro da quando abbiamo finito'],
  });
  if (testi.cervello) F.push({
    id: 'cervello_cosa',
    kind: 'text',
    section: 'Il secondo cervello',
    title: `Cosa ci fai adesso che ${testi.quando} non riuscivi a fare?`,
    optional: true,
  });

  if (!haCostruito) {
    F.push({ id: 'bloccato_cosa', kind: 'single', section: 'Dove ti sei bloccato', title: 'Cosa ti ha fermato?', options: BLOCCO });
    F.push({ id: 'bloccato_preciso', kind: 'text', section: 'Dove ti sei bloccato', title: 'Cosa è successo di preciso?', placeholder: 'Il punto esatto in cui ti sei fermato…' });
    F.push({ id: 'bloccato_aiuto', kind: 'text', section: 'Dove ti sei bloccato', title: 'Come possiamo aiutarti?' });
  }

  F.push({
    id: 'ore',
    kind: 'single',
    section: 'Il conto',
    title: 'Mettendo insieme tutto, a occhio: quante ore a settimana ti sono tornate indietro?',
    options: ORE_TORNATE,
  });
  // Chiesta da AdSP il 06/10: non solo tempo e risparmio, devono poter dire
  // che un lavoro lo fanno meglio. Sta subito dopo le ore, perche' e' l'altra
  // meta' della stessa risposta, e la vedono tutti, anche chi non ha costruito.
  F.push({
    id: 'efficienza',
    kind: 'text',
    section: 'Il conto',
    title: 'Al di là del tempo, c’è un’attività che oggi svolgi in modo più efficiente?',
    placeholder: 'Prima la facevo in modo disorganizzato, ora in maniera strutturata e più efficiente…',
    optional: true,
  });
  F.push({
    id: 'numero_azienda',
    kind: 'text',
    section: 'Il conto',
    // "C'e' qualcosa che nel tuo lavoro si conta" non voleva dire niente
    // (Riccardo, 30/09): si chiede il numero, e gli esempi sono del cliente
    title: `${maiuscola(testi.da)} è cambiato qualche numero nel tuo lavoro?`,
    hint: testi.esempioNumeri,
    optional: true,
  });
  // Al posto di "Se hai una cifra in testa, scrivila", che non diceva cifra di
  // cosa: l'unica risposta arrivata era una percentuale di tempo. Qui la cifra
  // ha un oggetto. Lo straordinario (soldi veri, in un ente) ha il suo numero.
  F.push({
    id: 'spese',
    kind: 'multi',
    section: 'Il conto',
    title: `${maiuscola(testi.da)}, grazie all’AI hai evitato qualche spesa?`,
    options: SPESE,
    esclusiva: SPESA_NO,
  });
  const spese = Array.isArray(answers.spese) ? answers.spese : [];
  if (spese.includes(STRAORDINARIO)) {
    F.push({ id: 'straordinario', kind: 'number', section: 'Il conto', title: 'Quante ore di straordinario in meno al mese?', suffix: 'ore al mese' });
  }
  if (spese.some((x) => x !== STRAORDINARIO && !SENZA_SPESA.includes(x))) {
    F.push({ id: 'spesa', kind: 'spesa', section: 'Il conto', title: 'Quale spesa hai evitato?' });
  }

  F.push({
    id: 'stacco',
    kind: 'info',
    section: 'La formazione',
    title: 'Grazie mille! ☺️',
    body: 'Adesso volevamo chiederti un feedback schietto: dicci com’è andata la formazione, senza filtri.',
    cta: 'Ci sto',
  });

  F.push({ id: 'voto_plenaria', kind: 'rating', section: 'La formazione', title: `Che voto dai ${testi.plenaria}?` });
  F.push({ id: 'cambio_plenaria', kind: 'text', section: 'La formazione', title: 'Cosa cambieresti di quella giornata?', optional: true });
  F.push({ id: 'voto_pratica', kind: 'rating', section: 'La formazione', title: `Che voto dai ${testi.pratica}?` });
  F.push({ id: 'cambio_pratica', kind: 'text', section: 'La formazione', title: 'Cosa cambieresti di quella?', optional: true });
  F.push({ id: 'aggiunta', kind: 'text', section: 'La formazione', title: 'Cosa aggiungeresti che non c’era?', optional: true });

  F.push({ id: 'serve', kind: 'single', section: 'Cosa serve adesso', title: 'Cosa ti servirebbe per andare avanti?', options: serveOpzioni(testi) });
  F.push({ id: 'workshop', kind: 'single', section: 'Cosa serve adesso', title: 'Ti piacerebbe rifare un workshop come quelli che abbiamo fatto?', options: WORKSHOP });
  if (answers.workshop && answers.workshop !== 'No') {
    // "siamo agli inizi, e' difficile anche capire questo" (Luca Melis)
    F.push({ id: 'workshop_cosa', kind: 'text', section: 'Cosa serve adesso', title: 'Su cosa?', optional: true });
  }

  F.push({
    id: 'parole',
    kind: 'text',
    section: 'Le tue parole',
    title: `Se dovessi dire a un collega di ${testi.altraOrg} cos’è cambiato, come glielo diresti?`,
    placeholder: 'Come lo diresti a voce, senza rileggerlo…',
  });
  F.push({ id: 'citazione', kind: 'single', section: 'Le tue parole', title: 'Possiamo citarti?', options: citazioneOpzioni(testi) });

  F.push({
    id: 'thanks',
    kind: 'thanks',
    section: 'Fatto',
    title: 'Grazie davvero.',
    body: 'Quello che hai scritto qui decide cosa portiamo la prossima volta :)',
  });

  let n = 0;
  for (const s of F) {
    if (['single', 'multi', 'text', 'number', 'duration', 'rating', 'band', 'spesa'].includes(s.kind)) {
      n += 1;
      s.qNum = n;
    }
  }
  return F;
}

// ── tema ─────────────────────────────────────────────────────────────────────

const THEME = {
  bg: '#050505',
  card: '#0D0D0D',
  fg: '#F5F5F0',
  fgMuted: 'rgba(245,245,240,0.62)',
  fgDim: 'rgba(245,245,240,0.38)',
  border: 'rgba(245,245,240,0.12)',
  borderStrong: 'rgba(245,245,240,0.22)',
  accent: '#4ADE80',
  accentDim: 'rgba(74,222,128,0.14)',
  accentInk: '#050505',
  font: "'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
};

// ── componente ───────────────────────────────────────────────────────────────

// Le attivita' scritte a settembre arrivano come le ha scritte la persona: ce
// n'e' una da 425 caratteri. Per intero dentro un'opzione fanno un muro alto
// undici righe sul telefono, quindi a schermo si tagliano. Il valore salvato
// resta quello vero, tagliato mai.
function taglia(testo, max) {
  // C'e' chi ha incollato la risposta fra virgolette: dentro le nostre
  // caporali diventerebbero due virgolette una dentro l'altra.
  const s = String(testo || '').replace(/\s+/g, ' ').trim().replace(/^["'«»]+|["'«»]+$/g, '').trim();
  if (s.length <= max) return s;
  const pezzo = s.slice(0, max);
  const spazio = pezzo.lastIndexOf(' ');
  return (spazio > max * 0.6 ? pezzo.slice(0, spazio) : pezzo) + '…';
}

// "a settembre" -> "A settembre"
function maiuscola(s) {
  return s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
}

// "ADSP Mare di Sardegna" -> "adsp-mare-di-sardegna"
function slugify(s) {
  return (s || '')
    .toLowerCase()
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
}

function MartesPost() {
  const params = useMemo(() => new URLSearchParams(window.location.search), []);

  // Il link e' uno solo per tutti: chi apre si riconosce nella schermata "chi
  // sei" e da li' esce la sua riga di settembre. Il link personale con &r= in
  // coda resta valido e salta la schermata.
  const recordId = params.get('r') || '';

  const [conf, setConf] = useState(null);
  const [pre, setPre] = useState(null);
  const [stop, setStop] = useState(null);
  const [loaded, setLoaded] = useState(false);
  const [answers, setAnswers] = useState({});
  const [blocks, setBlocks] = useState(1);
  const [curId, setCurId] = useState('cover');
  const [dir, setDir] = useState(1);
  const [submitState, setSubmitState] = useState('idle');

  const client = (conf && conf.table) || params.get('client') || 'Sconosciuto';

  // I testi che cambiano da cliente a cliente, dalla scheda. I valori di
  // ripiego sono quelli di Farvima: pre compilato fra luglio e settembre,
  // quindi "prima delle giornate" e mai "a settembre", secondo cervello
  // costruito in aula.
  const testi = useMemo(() => {
    const s = (conf && conf.scheda) || {};
    return {
      // la preposizione sta dentro l'etichetta, perche' un cliente vuole "al
      // Modulo A" e un altro "alla plenaria del 12"
      plenaria: (conf && conf.g1) || 'alla prima giornata',
      pratica: (conf && conf.g2) || 'alla seconda giornata',
      intro: s.intro || 'Sono passate alcune settimane dalle giornate insieme.',
      quando: s.quando || 'prima delle giornate',
      da: s.da || 'dalle giornate',
      sezionePre: s.sezione_pre || 'Quelle che avevi scritto',
      cervello: s.cervello !== false,
      rispetto: s.rispetto || 'Rispetto a prima delle giornate',
      usaGruppo: s.usa_gruppo || 'La usa il mio reparto',
      restoGruppo: s.resto_gruppo || 'Che la usi anche il resto del reparto',
      tuttaOrg: s.tutta_org || 'È diventata una cosa dell’azienda',
      citazioneNome: s.citazione_nome || 'Sì, con il mio nome e il mio ruolo',
      altraOrg: s.altra_org || 'un’altra azienda',
      ruolo: s.ruolo || 'Qual è il tuo ruolo in azienda?',
      ruoloEsempio: s.ruolo_esempio || 'Es. Responsabile acquisti, Logistica…',
      esempioNumeri: s.esempio_numeri || 'Per esempio quanti ordini chiudi in una settimana, quanto ci mettete a rispondere a una richiesta, quanti errori tornano indietro.',
      programmi: Array.isArray(s.software) && s.software.length ? s.software : PROGRAMMI_GENERICI,
    };
  }, [conf]);

  // Prima la scheda del cliente (nome della tabella e nomi delle due giornate),
  // poi il record del pre. La scheda esiste per tenere corto il link: senza,
  // i nomi delle giornate viaggerebbero nell'indirizzo, 130 caratteri di coda
  // uguale per tutti. Il link resta valido anche senza scheda, con ?client= e
  // le etichette generiche.
  useEffect(() => {
    let alive = true;
    async function load() {
      // la scheda e' una sola e sta accanto a questo file
      let scheda = null;
      try {
        const r = await fetch('/post/farvima/scheda.json', { cache: 'no-cache' });
        if (r.ok) scheda = await r.json();
      } catch (e) {
        console.warn('[post] scheda di Farvima non trovata');
      }
      const tabella = (scheda && scheda.table) || params.get('client') || 'Sconosciuto';
      if (!alive) return;
      setConf({
        table: tabella,
        g1: params.get('g1') || (scheda && scheda.g1) || null,
        g2: params.get('g2') || (scheda && scheda.g2) || null,
        scheda,
      });

      // Un link che non si sa dove scrivere si ferma qui e non dopo trenta
      // domande: le risposte di chi le ha gia' scritte non si recuperano.
      if (tabella === 'Sconosciuto') { setStop('link'); setLoaded(true); return; }

      try {
        const q = `/api/pre?client=${encodeURIComponent(tabella)}` +
          (recordId ? `&r=${encodeURIComponent(recordId)}` : '');
        const res = await fetch(q);
        const data = await res.json().catch(() => null);
        if (!alive) return;
        // si ferma solo se la tabella di destinazione non c'e': una riga del
        // pre mancante fa perdere la rilettura di settembre, non la serata
        if (!data || data.pronto === false) {
          setStop('link');
          setLoaded(true);
          return;
        }
        if (res.ok && recordId) {
          setPre(data);
          // Il nome si riempie da solo: non cambia, e chiederlo di nuovo e'
          // una domanda finta. Il ruolo no: e' una risposta data a settembre,
          // e riscriverla nel campo vuol dire che la persona deve cancellarla
          // per correggerla, oppure tira dritto e ci ridiamo indietro quello
          // che avevamo gia'.
          setAnswers((a) => ({ ...a, nome: a.nome || data.nome || '' }));
        }
        // riga non trovata (link vecchio, record cancellato): il form resta
        // utilizzabile, perde solo la rilettura di settembre
      } catch (e) {
        console.warn('[post] pre non caricato:', e);
      }
      if (alive) setLoaded(true);
    }
    load();
    return () => { alive = false; };
  }, [params, recordId]);


  const FLOW = useMemo(() => buildFlow(answers, pre, blocks, testi), [answers, pre, blocks, testi]);
  const idx = Math.max(0, FLOW.findIndex((s) => s.id === curId));
  const screen = FLOW[idx] || FLOW[0];
  const totalQ = FLOW.filter((s) => s.qNum).length;

  const setAnswer = (id, val) => setAnswers((a) => ({ ...a, [id]: val }));

  const isAnswered = (s) => {
    if (!s) return true;
    if (s.kind === 'info' || s.kind === 'thanks') return true;
    if (s.optional) return true;
    const v = answers[s.id];
    if (s.kind === 'multi') {
      if (!Array.isArray(v) || !v.length) return false;
      if (s.altroId && v.includes('Altro')) return String(answers[s.altroId] || '').trim().length > 0;
      return true;
    }
    if (s.kind === 'spesa') return !!v && String(v.testo || '').trim().length > 0 && (v.euro === undefined || v.euro === '' || Number(v.euro) >= 0);
    if (s.kind === 'text') return typeof v === 'string' && v.trim().length > 0;
    if (s.kind === 'duration') return v && v.n !== '' && v.n !== undefined && Number(v.n) >= 0;
    if (s.kind === 'number') return v !== undefined && v !== '' && !Number.isNaN(Number(v));
    if (s.kind === 'band') {
      if (!v || !v.band) return false;
      // "molto meno" senza le ore e' un aggettivo, non un numero
      if (s.numero && s.numero.solo && s.numero.solo.includes(v.band)) return v.ore !== undefined && v.ore !== '' && Number(v.ore) > 0;
      return true;
    }
    return v !== undefined && v !== null && v !== '';
  };
  const canAdvance = isAnswered(screen);

  const goNext = useCallback(() => {
    setDir(1);
    const i = FLOW.findIndex((s) => s.id === curId);
    const next = FLOW[Math.min(i + 1, FLOW.length - 1)];
    if (next) setCurId(next.id);
  }, [FLOW, curId]);

  const goPrev = useCallback(() => {
    setDir(-1);
    const i = FLOW.findIndex((s) => s.id === curId);
    const prev = FLOW[Math.max(i - 1, 0)];
    if (prev) setCurId(prev.id);
  }, [FLOW, curId]);

  // "ne ho un'altra" apre il blocco successivo
  const handleSingle = (s, opt) => {
    setAnswer(s.id, opt);
    const m = /^b(\d+)_altra$/.exec(s.id);
    if (m && opt === 'Sì, ne ho un’altra') {
      const n = parseInt(m[1], 10);
      setBlocks((b) => Math.max(b, n + 2));
    }
  };

  const toggleMulti = (s, opt) => {
    setAnswers((a) => {
      const cur = Array.isArray(a[s.id]) ? a[s.id] : [];
      // "Su nessuna di queste", "Nessuna": la voce del no esclude le altre
      // qui le voci del no possono essere piu' d'una (le spese ne hanno tre)
      const escl = [].concat(s.esclusiva || 'Su nessuna di queste');
      if (escl.includes(opt)) return { ...a, [s.id]: cur.includes(opt) ? [] : [opt] };
      const senzaNessuna = cur.filter((x) => !escl.includes(x));
      if (senzaNessuna.includes(opt)) return { ...a, [s.id]: senzaNessuna.filter((x) => x !== opt) };
      // col tetto pieno la voce nuova non entra: il bottone e' gia' spento
      if (s.max && senzaNessuna.length >= s.max) return a;
      return { ...a, [s.id]: [...senzaNessuna, opt] };
    });
  };

  // ── invio ──
  const submit = async () => {
    if (submitState === 'sending' || submitState === 'sent') return;
    setSubmitState('sending');
    try {
      const costruzioni = [];
      for (let i = 0; i < blocks; i += 1) {
        const p = `b${i}`;
        if (!answers[`${p}_cosa`]) continue;
        costruzioni.push({
          cosa: answers[`${p}_cosa`] || '',
          frequenza: answers[`${p}_freq`] || '',
          perche_non_usata: answers[`${p}_perche`] || '',
          tipo: tipiScelti(answers[`${p}_tipo`]).join(' + '),
          prima: answers[`${p}_prima`] || null,
          adesso: answers[`${p}_adesso`] || null,
          in_piu: answers[`${p}_inpiu`] || '',
          genere: answers[`${p}_genere`] || '',
          volte_settimana: answers[`${p}_volte`] || '',
          efficienza: answers[`${p}_eff`] || '',
          genere_efficienza: [].concat(answers[`${p}_eff_genere`] || [])[0] || '',
          efficienza_altro: answers[`${p}_eff_altro`] || '',
          chi_la_usa: answers[`${p}_chi`] || '',
        });
      }
      const attivitaPre = (pre && pre.attivita) || [];
      const coperte = coperteScelte(answers, attivitaPre);
      const scoperte = [];
      // solo le attivita' di settembre: le schermate dei programmi usano lo
      // stesso componente ma non hanno un'attivita' dietro
      FLOW.filter((s) => s.kind === 'band' && s.attivita).forEach((s) => {
        const v = answers[s.id];
        if (v && v.band) scoperte.push({ attivita: s.attivita.testo, tempo_pre: s.attivita.tempo || '', oggi: v.band, ore_esatte: v.ore || '' });
      });

      const programmi = programmiScelti(answers).map((pr) => {
        const v = answers[pr.id] || {};
        return { nome: pr.nome, tempo: v.band || '', ore_in_meno: MENO.includes(v.band) ? (v.ore || '') : '' };
      });

      const res = await fetch('/api/post-submit', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          client,
          recordId,
          timestamp: new Date().toISOString(),
          answers,
          coperte,
          costruzioni,
          scoperte,
          programmi,
        }),
      });
      if (!res.ok) throw new Error(await res.text());
      // La riga della persona si scrive per prima, le cose costruite dopo: se
      // le seconde non passano il server risponde lo stesso ok, e senza
      // guardare qui uno vedrebbe "inviate" con meta' delle risposte a terra.
      const esito = await res.json().catch(() => null);
      const attese = costruzioni.length;
      const scritte = esito && typeof esito.costruzioni === 'number' ? esito.costruzioni : attese;
      setSubmitState(scritte < attese ? 'parziale' : 'sent');
    } catch (err) {
      console.error('[post] submit error:', err);
      setSubmitState('error');
    }
  };

  // ── tastiera ──
  useEffect(() => {
    const onKey = (e) => {
      const tag = (e.target.tagName || '').toLowerCase();
      const inField = tag === 'input' || tag === 'textarea';
      if (e.key === 'Enter') {
        if (inField && tag === 'textarea' && e.shiftKey) return;
        if (canAdvance && screen.kind !== 'thanks') { e.preventDefault(); goNext(); }
        return;
      }
      if (inField) return;
      if (e.key === 'ArrowDown' || e.key === 'ArrowRight') { if (canAdvance) goNext(); }
      else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') goPrev();
      else if (screen.kind === 'single' && /^[1-9]$/.test(e.key)) {
        const n = parseInt(e.key, 10) - 1;
        if (screen.options[n]) handleSingle(screen, screen.options[n]);
      } else if (screen.kind === 'rating' && /^[1-5]$/.test(e.key)) {
        setAnswer(screen.id, parseInt(e.key, 10));
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [screen, canAdvance, goNext, goPrev]);

  // ── tastiera del telefono ──
  // Su iPhone la tastiera non rimpicciolisce la pagina: copre e basta, e la
  // barra Avanti ci finisce sotto. Sui campi numerici e' un vicolo cieco,
  // perche' il tastierino numerico di iOS non ha il tasto invio. Qui si misura
  // quanto spazio si prende e la barra sale di altrettanto.
  useEffect(() => {
    const vv = window.visualViewport;
    if (!vv) return undefined;
    const aggiorna = () => {
      const coperto = Math.max(0, window.innerHeight - vv.height - vv.offsetTop);
      document.documentElement.style.setProperty('--mt-kb', `${coperto > 60 ? coperto : 0}px`);
    };
    vv.addEventListener('resize', aggiorna);
    vv.addEventListener('scroll', aggiorna);
    aggiorna();
    return () => {
      vv.removeEventListener('resize', aggiorna);
      vv.removeEventListener('scroll', aggiorna);
      document.documentElement.style.removeProperty('--mt-kb');
    };
  }, []);

  const progressPct = FLOW.length <= 1 ? 0 : (idx / (FLOW.length - 1)) * 100;

  if (!loaded) {
    return (
      <div className="mt-root mtp-loading" style={themeVars()}>
        <div className="mtp-loading-dot" />
      </div>
    );
  }

  if (stop) {
    return (
      <div className="mt-root" style={themeVars()}>
        <div className="mt-stage">
          <div className="mt-slide mt-slide-fade mt-slide-enter">
            <div className="mt-screen mt-screen-info">
              <h1 className="mt-title">Questo link non funziona.</h1>
              <p className="mt-body">
                Non e' colpa tua: l'indirizzo e' incompleto oppure non e' ancora collegato.
                Rispondi alla mail con cui ti e' arrivato e te ne mandiamo uno nuovo.
              </p>
              <p className="mtp-footnote">Non scrivere niente qui sotto: non verrebbe salvato.</p>
            </div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="mt-root" style={themeVars()}>
      <div className="mt-progress-wrap">
        <div className="mt-progress-track">
          <div className="mt-progress-fill" style={{ width: `${progressPct}%` }} />
        </div>
        <div className="mt-progress-meta">
          <span>{screen.section || ''}</span>
        </div>
      </div>

      <div className="mt-stage">
        <div className={`mt-slide mt-slide-fade mt-slide-enter mt-slide-dir-${dir > 0 ? 'fwd' : 'back'}`} key={screen.id}>
          <ScreenRenderer
            screen={screen}
            answer={answers[screen.id]}
            answers={answers}
            totalQ={totalQ}
            onSelect={(opt) => handleSingle(screen, opt)}
            onToggle={(opt) => toggleMulti(screen, opt)}
            onSet={(v) => setAnswer(screen.id, v)}
            onSetKey={setAnswer}
            onSubmit={submit}
            submitState={submitState}
          />
        </div>
      </div>

      {screen.kind !== 'thanks' && (
        <div className="mt-inline-cta-row">
          {idx > 0 && (
            <button className="mt-inline-back" onClick={goPrev} type="button" aria-label="Indietro">
              <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
                <path d="M4 10l4-4 4 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </button>
          )}
          <button className="mt-inline-cta" onClick={goNext} disabled={!canAdvance} type="button">
            <span>{screen.cta || 'Avanti'}</span>
          </button>
        </div>
      )}
    </div>
  );
}

function themeVars() {
  return {
    '--bg': THEME.bg,
    '--card': THEME.card,
    '--fg': THEME.fg,
    '--fg-muted': THEME.fgMuted,
    '--fg-dim': THEME.fgDim,
    '--border': THEME.border,
    '--border-strong': THEME.borderStrong,
    '--accent': THEME.accent,
    '--accent-dim': THEME.accentDim,
    '--accent-ink': THEME.accentInk,
    '--font': THEME.font,
    '--font-q': THEME.font,
    '--transition': 'fade',
  };
}

// ── schermate ────────────────────────────────────────────────────────────────

function ScreenRenderer(p) {
  const { screen } = p;
  if (screen.kind === 'info') return <InfoScreen screen={screen} />;
  if (screen.kind === 'thanks') return <ThanksScreen {...p} />;
  if (screen.kind === 'single') return <SingleScreen screen={screen} answer={p.answer} onSelect={p.onSelect} onSet={p.onSet} totalQ={p.totalQ} />;
  if (screen.kind === 'multi') return <MultiScreen screen={screen} answer={p.answer} answers={p.answers} onToggle={p.onToggle} onSetKey={p.onSetKey} totalQ={p.totalQ} />;
  if (screen.kind === 'spesa') return <SpesaScreen screen={screen} answer={p.answer} onSet={p.onSet} totalQ={p.totalQ} />;
  if (screen.kind === 'text') return <TextScreen screen={screen} answer={p.answer} onSet={p.onSet} totalQ={p.totalQ} />;
  if (screen.kind === 'number') return <NumberScreen screen={screen} answer={p.answer} onSet={p.onSet} totalQ={p.totalQ} />;
  if (screen.kind === 'duration') return <DurationScreen screen={screen} answer={p.answer} onSet={p.onSet} totalQ={p.totalQ} />;
  if (screen.kind === 'rating') return <RatingScreen screen={screen} answer={p.answer} onSet={p.onSet} totalQ={p.totalQ} />;
  if (screen.kind === 'band') return <BandScreen screen={screen} answer={p.answer} onSet={p.onSet} totalQ={p.totalQ} />;
  return null;
}

function QHead({ screen, totalQ }) {
  return (
    <div className="mt-q-head">
      {screen.eyebrow && <div className="mtp-eyebrow">{screen.eyebrow}</div>}
      <div className="mt-q-num">
        <span className="mt-q-num-n">{screen.qNum}</span>
        <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
          <path d="M2 5h6M5 2l3 3-3 3" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </div>
      {screen.quote && (
        <blockquote className="mtp-quote">
          <span className="mtp-quote-testo">{screen.quote}</span>
          {screen.quoteNota && <span className="mtp-quote-nota">{screen.quoteNota}</span>}
        </blockquote>
      )}
      <h2 className="mt-q-title">
        {screen.title}
        {screen.accento && <span className="mtp-accento">{screen.accento}</span>}
        {screen.coda}
        {screen.optional && <span className="mt-q-optional"> · opzionale</span>}
      </h2>
      {screen.hint && <div className="mt-q-hint">{screen.hint}</div>}
    </div>
  );
}

// ── LA PALLA DELLA COPERTINA ──
// Presa uguale da typeform.jsx, il form pre: e' la stessa cosa che si vede
// sulla copertina di quando hanno compilato a settembre, e rivederla dice
// "e' lo stesso posto" senza scriverlo.
function AsciiSphere() {
  const canvasRef = useRef(null);
  const frameRef = useRef(0);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    const chars = '░▒▓█▀▄▌▐│─┤├┴┬╭╮╰╯';
    let time = 0;

    const resize = () => {
      const dpr = window.devicePixelRatio || 1;
      const rect = canvas.getBoundingClientRect();
      canvas.width = rect.width * dpr;
      canvas.height = rect.height * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    resize();
    window.addEventListener('resize', resize);

    const render = () => {
      const rect = canvas.getBoundingClientRect();
      ctx.clearRect(0, 0, rect.width, rect.height);

      const centerX = rect.width / 2;
      const centerY = rect.height / 2;
      const radius = Math.min(rect.width, rect.height) * 0.46;

      ctx.font = '13px monospace';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';

      const points = [];
      for (let phi = 0; phi < Math.PI * 2; phi += 0.13) {
        for (let theta = 0; theta < Math.PI; theta += 0.13) {
          const x = Math.sin(theta) * Math.cos(phi + time * 0.5);
          const y = Math.sin(theta) * Math.sin(phi + time * 0.5);
          const z = Math.cos(theta);

          const rotY = time * 0.3;
          const newX = x * Math.cos(rotY) - z * Math.sin(rotY);
          const newZ = x * Math.sin(rotY) + z * Math.cos(rotY);

          const rotX = time * 0.2;
          const newY = y * Math.cos(rotX) - newZ * Math.sin(rotX);
          const finalZ = y * Math.sin(rotX) + newZ * Math.cos(rotX);

          const depth = (finalZ + 1) / 2;
          const charIndex = Math.floor(depth * (chars.length - 1));

          points.push({
            x: centerX + newX * radius,
            y: centerY + newY * radius,
            z: finalZ,
            char: chars[charIndex],
          });
        }
      }

      points.sort((a, b) => a.z - b.z);

      points.forEach((point) => {
        const depth = (point.z + 1) / 2;
        const alpha = 0.15 + depth * 0.7;
        const r = Math.round(243 - (243 - 74) * depth);
        const g = Math.round(243 - (243 - 222) * depth);
        const b = Math.round(243 - (243 - 128) * depth);
        ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${alpha})`;
        ctx.fillText(point.char, point.x, point.y);
      });

      time += reduce ? 0 : 0.02;
      frameRef.current = requestAnimationFrame(render);
    };
    render();

    return () => {
      window.removeEventListener('resize', resize);
      cancelAnimationFrame(frameRef.current);
    };
  }, []);

  return <canvas ref={canvasRef} className="mt-cover-sphere" />;
}

function InfoScreen({ screen }) {
  const isCover = screen.id === 'cover';
  return (
    <div className={`mt-screen mt-screen-info${isCover ? ' mt-screen-cover' : ''}`}>
      {isCover && (
        <div className="mt-cover-bg" aria-hidden="true">
          <AsciiSphere />
          <div className="mt-cover-scrim" />
        </div>
      )}
      {isCover && <img className="mt-cover-logo" src="/martes-logo.png" alt="Martes AI" />}
      <h1 className="mt-title">{screen.title}</h1>
      {screen.body && <p className="mt-body">{screen.body}</p>}
      {screen.note && <p className="mtp-note">{screen.note}</p>}
      {screen.footnote && <p className="mtp-footnote">{screen.footnote}</p>}
    </div>
  );
}

function SingleScreen({ screen, answer, onSelect, totalQ }) {
  const isAltro = (o) => o === 'Scrivilo tu';
  const selectedAltro = typeof answer === 'string' && answer.startsWith('Scrivilo tu');
  const [libero, setLibero] = useState('');
  return (
    <div className="mt-screen mt-screen-q">
      <QHead screen={screen} totalQ={totalQ} />
      <div className="mt-options">
        {screen.options.map((opt, i) => {
          const selected = isAltro(opt) ? selectedAltro : answer === opt;
          return (
            <React.Fragment key={opt}>
              <button
                className={`mt-option ${selected ? 'is-selected' : ''}`}
                onClick={() => onSelect(isAltro(opt) ? (libero ? `Scrivilo tu: ${libero}` : 'Scrivilo tu') : opt)}
                type="button"
              >
                <span className="mt-option-key">{i + 1}</span>
                <span className="mt-option-label">{opt}</span>
                <span className="mt-option-check">
                  <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
                    <path d="M3 7.5l3 3 5-6" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                  </svg>
                </span>
              </button>
              {isAltro(opt) && selected && (
                <input
                  className="mt-altro-input"
                  type="text"
                  autoFocus
                  placeholder="Quante, secondo te?"
                  value={libero}
                  onChange={(e) => { setLibero(e.target.value); onSelect(e.target.value ? `Scrivilo tu: ${e.target.value}` : 'Scrivilo tu'); }}
                />
              )}
            </React.Fragment>
          );
        })}
      </div>
    </div>
  );
}

function MultiScreen({ screen, answer, answers, onToggle, onSetKey, totalQ }) {
  const sel = Array.isArray(answer) ? answer : [];
  const pieno = screen.max && sel.length >= screen.max;
  const aiuto = screen.max
    ? `Scegline al massimo ${NUMERI[screen.max] || screen.max}`
    : 'Puoi selezionarne più di una';
  return (
    <div className="mt-screen mt-screen-q">
      <QHead screen={screen} totalQ={totalQ} />
      {screen.options.length > 2 && !screen.aiutoNelTitolo && <div className="mt-q-hint mtp-hint-multi">{aiuto}</div>}
      <div className={`mt-options${screen.options.length > 7 ? ' mtp-options-lunga' : ''}`}>
        {screen.options.map((opt, i) => {
          const on = sel.includes(opt);
          const spento = pieno && !on;
          return (
            <React.Fragment key={opt}>
              <button
                className={`mt-option ${on ? 'is-selected' : ''} ${spento ? 'mtp-option-off' : ''}`}
                onClick={() => onToggle(opt)}
                aria-disabled={spento}
                type="button"
              >
                <span className="mt-option-key">{String.fromCharCode(65 + i)}</span>
                <span className="mt-option-label">{(screen.etichette && screen.etichette[opt]) || opt}</span>
                <span className="mt-option-check">
                  <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
                    <path d="M3 7.5l3 3 5-6" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                  </svg>
                </span>
              </button>
              {screen.altroId && opt === 'Altro' && on && (
                <AltroInput
                  value={(answers && answers[screen.altroId]) || ''}
                  onChange={(v) => onSetKey(screen.altroId, v)}
                />
              )}
            </React.Fragment>
          );
        })}
      </div>
    </div>
  );
}

function TextScreen({ screen, answer, onSet, totalQ }) {
  const ref = useRef(null);
  useEffect(() => {
    const t = setTimeout(() => ref.current && ref.current.focus(), 320);
    return () => clearTimeout(t);
  }, [screen.id]);
  return (
    <div className="mt-screen mt-screen-q">
      <QHead screen={screen} totalQ={totalQ} />
      {screen.singleLine ? (
        <input
          ref={ref}
          className="mt-textarea mt-textarea-line"
          type="text"
          placeholder={screen.placeholder || 'Scrivi qui…'}
          value={answer || ''}
          onChange={(e) => onSet(e.target.value)}
        />
      ) : (
        <textarea
          ref={ref}
          className="mt-textarea"
          rows={3}
          placeholder={screen.placeholder || 'Scrivi qui…'}
          value={answer || ''}
          onChange={(e) => onSet(e.target.value)}
        />
      )}
    </div>
  );
}

function NumberScreen({ screen, answer, onSet, totalQ }) {
  const ref = useRef(null);
  useEffect(() => {
    const t = setTimeout(() => ref.current && ref.current.focus(), 320);
    return () => clearTimeout(t);
  }, [screen.id]);
  return (
    <div className="mt-screen mt-screen-q">
      <QHead screen={screen} totalQ={totalQ} />
      <div className="mtp-num-row">
        <input
          ref={ref}
          className="mtp-num"
          type="number"
          min="0"
          inputMode="numeric"
          placeholder="0"
          value={answer === undefined ? '' : answer}
          onChange={(e) => onSet(e.target.value)}
        />
        {screen.suffix && <span className="mtp-suffix">{screen.suffix}</span>}
      </div>
    </div>
  );
}

// Il campo di "Altro" sta in fondo a una lista di nove voci: sul telefono
// nasce sotto la barra Avanti, dove non si vede. Avanti resta spento senza
// che si capisca perche'. Appena compare la schermata scorre fino a lui.
function AltroInput({ value, onChange }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    el.focus({ preventScroll: true });
    el.scrollIntoView({ block: 'center', behavior: 'smooth' });
  }, []);
  return (
    <input
      ref={ref}
      className="mt-altro-input"
      type="text"
      placeholder="Quale?"
      value={value}
      onChange={(e) => onChange(e.target.value)}
    />
  );
}

// Cosa e quanto sulla stessa schermata: la cifra senza l'oggetto era la
// vecchia domanda 22, che non si sapeva a cosa riferire.
function SpesaScreen({ screen, answer, onSet, totalQ }) {
  const ref = useRef(null);
  const val = answer || { testo: '', euro: '' };
  useEffect(() => {
    const t = setTimeout(() => ref.current && ref.current.focus(), 320);
    return () => clearTimeout(t);
  }, [screen.id]);
  return (
    <div className="mt-screen mt-screen-q">
      <QHead screen={screen} totalQ={totalQ} />
      <textarea
        ref={ref}
        className="mt-textarea"
        rows={2}
        placeholder="Es. la traduzione di un bando, che prima mandavamo fuori…"
        value={val.testo}
        onChange={(e) => onSet({ ...val, testo: e.target.value })}
      />
      <div className="mtp-num-row mtp-num-row-inline">
        <input
          className="mtp-num mtp-num-sm mtp-num-euro"
          type="number"
          min="0"
          inputMode="numeric"
          placeholder="0"
          value={val.euro}
          onChange={(e) => onSet({ ...val, euro: e.target.value })}
        />
        <span className="mtp-suffix">euro in tutto, anche a spanne. Se non lo sai, lascia vuoto</span>
      </div>
    </div>
  );
}

function DurationScreen({ screen, answer, onSet, totalQ }) {
  const ref = useRef(null);
  const val = answer || { n: '', u: 'minuti' };
  useEffect(() => {
    const t = setTimeout(() => ref.current && ref.current.focus(), 320);
    return () => clearTimeout(t);
  }, [screen.id]);
  return (
    <div className="mt-screen mt-screen-q">
      <QHead screen={screen} totalQ={totalQ} />
      <div className="mtp-num-row">
        <input
          ref={ref}
          className="mtp-num"
          type="number"
          min="0"
          inputMode="numeric"
          placeholder="0"
          value={val.n}
          onChange={(e) => onSet({ ...val, n: e.target.value })}
        />
        <div className="mtp-units">
          {['minuti', 'ore'].map((u) => (
            <button
              key={u}
              type="button"
              className={`mtp-unit ${val.u === u ? 'is-selected' : ''}`}
              onClick={() => onSet({ ...val, u })}
            >
              {u}
            </button>
          ))}
        </div>
      </div>
      <div className="mt-text-hint">Ogni volta che la fai, non nella settimana.</div>
    </div>
  );
}

function RatingScreen({ screen, answer, onSet, totalQ }) {
  return (
    <div className="mt-screen mt-screen-q">
      <QHead screen={screen} totalQ={totalQ} />
      <div className="mtp-rating">
        {[1, 2, 3, 4, 5].map((n) => (
          <button
            key={n}
            type="button"
            className={`mtp-star ${answer === n ? 'is-selected' : ''} ${answer >= n ? 'is-filled' : ''}`}
            onClick={() => onSet(n)}
          >
            {n}
          </button>
        ))}
      </div>
      <div className="mtp-rating-legend">
        <span>1 · non mi è servita</span>
        <span>5 · mi ha cambiato il lavoro</span>
      </div>
    </div>
  );
}

function BandScreen({ screen, answer, onSet, totalQ }) {
  const val = answer || {};
  // Sulle attivita' di settembre il numero c'e' sempre ed e' facoltativo. Sui
  // programmi compare solo dopo "molto meno" o "un po' meno": li' serve.
  const cfg = screen.numero;
  const mostraNumero = !cfg || !cfg.solo || cfg.solo.includes(val.band);
  return (
    <div className="mt-screen mt-screen-q">
      <QHead screen={screen} totalQ={totalQ} />
      <div className="mt-options">
        {screen.options.map((opt, i) => (
          <button
            key={opt}
            type="button"
            className={`mt-option ${val.band === opt ? 'is-selected' : ''}`}
            onClick={() => onSet({ ...val, band: opt })}
          >
            <span className="mt-option-key">{i + 1}</span>
            <span className="mt-option-label">{opt}</span>
            <span className="mt-option-check">
              <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
                <path d="M3 7.5l3 3 5-6" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </span>
          </button>
        ))}
      </div>
      {mostraNumero && (
        <div className="mtp-num-row mtp-num-row-inline">
          <input
            className="mtp-num mtp-num-sm"
            type="number"
            min="0"
            step="0.5"
            inputMode="decimal"
            placeholder="?"
            autoFocus={!!cfg}
            value={val.ore === undefined ? '' : val.ore}
            onChange={(e) => onSet({ ...val, ore: e.target.value })}
          />
          <span className="mtp-suffix">{cfg ? cfg.label : 'ore precise a settimana, se le sai'}</span>
        </div>
      )}
    </div>
  );
}

function ThanksScreen({ screen, onSubmit, submitState, answers }) {
  const sent = useRef(false);
  useEffect(() => {
    if (!sent.current) { sent.current = true; onSubmit(); }
  }, []);
  return (
    <div className="mt-screen mt-screen-thanks">
      <div className="mt-thanks-mark">
        <svg width="64" height="64" viewBox="0 0 64 64" fill="none" aria-hidden="true">
          <circle cx="32" cy="32" r="30" stroke="var(--accent)" strokeWidth="1.5" />
          <path d="M20 33l8 8 16-18" stroke="var(--accent)" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" className="mt-thanks-tick" />
        </svg>
      </div>
      <h1 className="mt-title mt-thanks-title">{screen.title}</h1>
      <p className="mt-body mt-thanks-body">{screen.body}</p>
      <div className="mt-thanks-status">
        {submitState === 'sending' && <span>Sto inviando le risposte…</span>}
        {submitState === 'sent' && <span className="mt-thanks-sent">Risposte inviate ✓</span>}
        {submitState === 'parziale' && (
          <span className="mt-thanks-err">
            Le tue risposte sono salvate, le cose che hai costruito no. Scrivi a chi ti ha mandato il link.
          </span>
        )}
        {submitState === 'error' && <span className="mt-thanks-err">Errore, riprova a ricaricare la pagina</span>}
      </div>
      <div className="mt-thanks-meta">{Object.keys(answers).length} risposte registrate</div>
    </div>
  );
}

window.MartesPost = MartesPost;
