// Preinscription form — multi-child, modality per family+turn, NEE checkbox, email confirm.
// Each child becomes a separate registration row (sharing family_id) so the panel can list/sort by surname.

const PRICES = { cangur: 8.00, morning: 24.00, lunch: 46.50 };

// Centros que prestan servicio de comedor.
// El CEIP Mestre Francesc Catalan NO ofrece comedor → no se debe permitir seleccionarlo allí.
const CENTERS_WITH_LUNCH = ['CEIP Marqués de Benicarló'];

// Short id for local React keys (no DB constraint)
const uid = () => Math.random().toString(36).slice(2, 10) + Date.now().toString(36).slice(-4);

// Renderitza text amb marcadors **negreta** com a segments React segurs.
// Substitueix l'antic `dangerouslySetInnerHTML` per evitar XSS si el contingut
// del LOPD arriba a ser editable des de BD (auditoria H-03).
function renderBoldSegments(s) {
  if (!s) return null;
  const parts = [];
  const re = /\*\*([^*]+)\*\*/g;
  let last = 0; let m;
  let i = 0;
  while ((m = re.exec(s)) !== null) {
    if (m.index > last) parts.push(s.slice(last, m.index));
    parts.push(React.createElement('strong', { key: i++ }, m[1]));
    last = re.lastIndex;
  }
  if (last < s.length) parts.push(s.slice(last));
  return parts;
}
// Proper RFC4122 UUID for fields that map to Postgres uuid columns (family_id)
const uuidv4 = () => {
  if (window.crypto && window.crypto.randomUUID) return window.crypto.randomUUID();
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
    const r = Math.random() * 16 | 0;
    const v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
};
const fmtEur = (n) => Number(n || 0).toLocaleString('es-ES', { style: 'currency', currency: 'EUR' });

const emptyChild = () => ({
  id: uid(),
  firstName: "",
  lastName: "",
  birthDate: "",
  course: "",
  gender: "",
  turns: [],                                     // ['t1','t2','t3']
  hours: { t1: [], t2: [], t3: [] },             // each: ['cangur','morning','lunch']
  centerPref: { t1: '', t2: '', t3: '' },        // CEIP Marqués... / CEIP Mestre Francesc Catalan
  centerAlt:  { t1: 'si', t2: 'si', t3: 'si' },  // 'si' | 'no' — accepts alternative center if no place at preferred
  nee: false,
  neeDetail: "",
});

const emptyForm = () => ({
  // Tutor / family-level
  parentFirstName: "",
  parentLastName1: "",
  parentLastName2: "",
  dni: "",
  phone: "",
  phone2: "",
  email: "",
  emailConfirm: "",
  city: "Benicarló",
  zip: "12580",
  consent: false,
  obs: "",
  // Modality per turn (only relevant when 2+ siblings share a turn)
  modality: { t1: 'partial', t2: 'partial', t3: 'partial' },  // 'joint' | 'partial'
  // Children (at least one)
  children: [emptyChild()],
});

// =====================================================================
// Reusable field components — DEFINED OUTSIDE Form so React keeps the
// same component identity between renders. (This fixes the bug where
// the cursor jumped out of inputs after each keystroke.)
// =====================================================================
const TextField = ({ label, value, onChange, type = 'text', required, hint, error, placeholder, full, autoComplete }) => (
  <div className={`field ${full ? 'full' : ''} ${error ? 'error' : ''}`}>
    <label>{label}{required && <span className="req">*</span>}</label>
    <input
      type={type}
      value={value}
      onChange={e => onChange(e.target.value)}
      placeholder={placeholder || ''}
      autoComplete={autoComplete}
    />
    {hint && <span className="hint">{hint}</span>}
    {error && typeof error === 'string' && <span className="err">{error}</span>}
  </div>
);

const SelectField = ({ label, value, onChange, options, required, error, full }) => (
  <div className={`field ${full ? 'full' : ''} ${error ? 'error' : ''}`}>
    <label>{label}{required && <span className="req">*</span>}</label>
    <select value={value} onChange={e => onChange(e.target.value)}>
      <option value="">—</option>
      {options.map(o => <option key={o} value={o}>{o}</option>)}
    </select>
  </div>
);

const TurnDefs = (lang) => [
  { k: 't1', name: T[lang].when.t1, sub: T[lang].when.t1d },
  { k: 't2', name: T[lang].when.t2, sub: T[lang].when.t2d },
  { k: 't3', name: T[lang].when.t3, sub: T[lang].when.t3d },
];
const HourDefs = (lang) => [
  { k: 'cangur',  name: T[lang].schedule.cangur,  sub: T[lang].schedule.cangurTime,  price: PRICES.cangur },
  { k: 'morning', name: T[lang].schedule.morning, sub: T[lang].schedule.morningTime, price: PRICES.morning },
  { k: 'lunch',   name: T[lang].schedule.lunch,   sub: T[lang].schedule.lunchTime,   price: PRICES.lunch },
];

// =====================================================================
// Supabase submit (with localStorage fallback)
// Maps camelCase frontend records → snake_case columns of public.registrations
// =====================================================================
async function submitRecordsToSupabase(records, lang) {
  const url = window.__SUPABASE_URL__;
  const key = window.__SUPABASE_ANON_KEY__;
  // Not configured → return early so caller falls back to localStorage
  if (!url || !key || url.includes('YOUR_PROJECT')) {
    return { ok: false, reason: 'not_configured' };
  }
  try {
    // Mapejar a snake_case que espera l'edge function submit-registration.
    // (Migrat 2026-05-12: abans s'inseria directament des del client amb la
    // anon key. Ara passa per edge function amb rate limit, validació
    // servidor i RLS més estricta a public.registrations.)
    const rows = records.map(r => ({
      family_id: r.familyId,
      sibling_order: r.siblingOrder,
      siblings_total: r.siblingsTotal,
      child_first_name: r.childFirstName,
      child_last_name: r.childLastName,
      child_name: r.childName,
      birth_date: r.birthDate,
      course: r.course,
      gender: r.gender || null,
      parent_first_name: r.parentFirstName,
      parent_last_name1: r.parentLastName1,
      parent_last_name2: r.parentLastName2 || null,
      parent_name: r.parentName,
      dni: r.dni,
      phone: r.phone,
      phone2: r.phone2 || null,
      email: r.email,
      city: r.city || 'Benicarló',
      zip: r.zip || '12580',
      address: r.address || null,
      center: r.center || (r.centerPref && Object.values(r.centerPref).find(Boolean)) || '',
      turns: r.turns,
      hours: r.hours,
      center_pref: r.centerPref,
      center_alt: r.centerAlt,
      modality: r.modality,
      nee: !!r.nee,
      nee_detail: r.neeDetail || null,
      total_eur: Number(r.total || 0).toFixed(2),
      bonif_applied: !!r.bonifApplied,
      status: r.status || 'preinscribed',
      obs: r.obs || null,
    }));

    const res = await fetch(`${url}/functions/v1/submit-registration`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        // L'edge function necessita l'apikey per a què Supabase la enrutei.
        'apikey': key,
        'Authorization': `Bearer ${key}`,
      },
      body: JSON.stringify({
        lang: lang === 'val' ? 'va' : 'es',
        records: rows,
      }),
    });
    let data = null;
    try { data = await res.json(); } catch { /* resposta sense body */ }

    if (!res.ok) {
      console.error('[Supabase submit] edge function error:', res.status, data);
      // Cas especial: 429 (rate limit) → mostrem missatge més clar.
      if (res.status === 429) {
        return { ok: false, reason: 'rate_limit', error: data?.error || 'Massa peticions' };
      }
      return { ok: false, reason: 'db_error', error: data?.error || `HTTP ${res.status}` };
    }
    return { ok: true, ids: data?.ids || [] };
  } catch (e) {
    console.error('[Supabase submit] exception:', e);
    return { ok: false, reason: 'exception', error: e };
  }
}

// =====================================================================
// Pricing
// =====================================================================
const childRawTotal = (c) => {
  let total = 0;
  for (const tk of c.turns) {
    for (const hk of (c.hours[tk] || [])) total += PRICES[hk];
  }
  return total;
};

// Bonification rule (option A): 3rd and 4th sibling registered in the
// same family submission pay 50%. 1st, 2nd and 5th+ pay 100%.
const bonifFactor = (idx, total) => (total >= 3 && (idx === 2 || idx === 3)) ? 0.5 : 1;

// =====================================================================
// Format validators
// =====================================================================
// Spanish phone: 9 digits, may start with +34 / 34
const validatePhone = (v) => {
  if (!v) return false;
  const digits = String(v).replace(/[\s\-\.()]/g, '').replace(/^\+?34/, '');
  return /^[6789]\d{8}$/.test(digits);
};
// DNI: 8 digits + letter; check letter against modulo 23
const DNI_LETTERS = 'TRWAGMYFPDXBNJZSQVHLCKE';
const validateDNI = (v) => {
  if (!v) return false;
  const s = String(v).toUpperCase().replace(/[\s\-]/g, '');
  if (!/^\d{8}[A-Z]$/.test(s)) return false;
  const num = parseInt(s.slice(0, 8), 10);
  return DNI_LETTERS[num % 23] === s.charAt(8);
};
// NIE: X|Y|Z + 7 digits + letter
const validateNIE = (v) => {
  if (!v) return false;
  const s = String(v).toUpperCase().replace(/[\s\-]/g, '');
  if (!/^[XYZ]\d{7}[A-Z]$/.test(s)) return false;
  const lead = { X: '0', Y: '1', Z: '2' }[s.charAt(0)];
  const num = parseInt(lead + s.slice(1, 8), 10);
  return DNI_LETTERS[num % 23] === s.charAt(8);
};
// Passport: alphanumeric, 5–15 chars (international, loose validation)
const validatePassport = (v) => {
  if (!v) return false;
  const s = String(v).toUpperCase().replace(/[\s\-]/g, '');
  return /^[A-Z0-9]{5,15}$/.test(s);
};
const validateID = (v) => validateDNI(v) || validateNIE(v) || validatePassport(v);

const computeTotal = (f) => {
  const childTotals = f.children.map(childRawTotal);
  let total = 0;
  let bonifApplied = false;
  childTotals.forEach((ct, i) => {
    const factor = bonifFactor(i, f.children.length);
    if (factor < 1) bonifApplied = true;
    total += ct * factor;
  });
  return { total, bonifApplied, childTotals };
};

// =====================================================================
// Child block (one per participant)
// =====================================================================
const ChildBlock = ({
  child, idx, t, lang, errors,
  onChange, onToggleTurn, onToggleHour, onCenterPref, onCenterAlt, onRemove,
}) => {
  const turnDefs = TurnDefs(lang);
  const hourDefs = HourDefs(lang);
  return (
    <div className="form-section">
      <h3>
        <span className="n">{idx + 1}</span>
        {idx === 0 ? t.s1 : t.s1Sibling}
        {idx > 0 && <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink-mute)', marginLeft: 8 }}>{t.siblingN}{idx + 1}</span>}
        {onRemove && (
          <button type="button" className="lk danger" style={{ marginLeft: 'auto' }} onClick={onRemove}>✕ {t.removeSibling}</button>
        )}
      </h3>
      <p className="desc">{idx === 0 ? t.s1d : t.s1SiblingD}</p>

      <div className="form-grid">
        <TextField
          label={t.childFirstName} value={child.firstName}
          onChange={v => onChange('firstName', v)}
          required error={!!errors[`child_${idx}_firstName`]}
          hint={t.childFirstNameHint}
        />
        <TextField
          label={t.childLastName} value={child.lastName}
          onChange={v => onChange('lastName', v)}
          required error={!!errors[`child_${idx}_lastName`]}
          hint={t.childLastNameHint}
        />
        <TextField
          label={t.birthDate} type="date" value={child.birthDate}
          onChange={v => onChange('birthDate', v)}
          required error={!!errors[`child_${idx}_birthDate`]}
        />
        <SelectField
          label={t.course} value={child.course}
          onChange={v => onChange('course', v)}
          options={t.courses}
          required error={!!errors[`child_${idx}_course`]}
        />
        <SelectField
          label={t.gender} value={child.gender}
          onChange={v => onChange('gender', v)}
          options={t.genders}
        />
      </div>

      {/* Turns */}
      <div className={`field ${errors[`child_${idx}_turns`] ? 'error' : ''}`} style={{ marginTop: 18 }}>
        <label>{t.turnsLabel}<span className="req">*</span></label>
        <div className="opt-group three">
          {turnDefs.map(td => (
            <label key={td.k} className={`opt ${child.turns.includes(td.k) ? 'selected' : ''}`}>
              <input type="checkbox" checked={child.turns.includes(td.k)} onChange={() => onToggleTurn(td.k)} />
              <div className="top">
                <div className="name">{td.name}</div>
                <div className="price-tag">{child.turns.includes(td.k) ? '✓' : '+'}</div>
              </div>
              <div className="sub">{td.sub}</div>
            </label>
          ))}
        </div>
      </div>

      {/* Per-turn config: services + center + accept-alt */}
      {child.turns.length > 0 && (
        <div className="field" style={{ marginTop: 14 }}>
          <label>{t.hoursLabel}</label>
          <div style={{ display: 'grid', gap: 14, marginTop: 6 }}>
            {['t1', 't2', 't3'].filter(k => child.turns.includes(k)).map(tk => {
              const td = turnDefs.find(x => x.k === tk);
              const hasErrH = errors[`child_${idx}_hours_${tk}`];
              const hasErrC = errors[`child_${idx}_centerPref_${tk}`];
              return (
                <div key={tk} style={{ padding: '14px 16px', background: 'var(--sand-50)', borderRadius: 12, border: '1px solid var(--line)' }}>
                  <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--ink-soft)', marginBottom: 10 }}>
                    {td.name} · <span style={{ color: 'var(--sea-700)' }}>{td.sub}</span>
                  </div>

                  {/* Services for this turn */}
                  <div className={`field ${hasErrH ? 'error' : ''}`} style={{ marginBottom: 12 }}>
                    <label style={{ fontSize: 11.5, marginBottom: 6 }}>
                      {lang === 'val' ? 'Serveis' : 'Servicios'}
                    </label>
                    <div className="opt-group three">
                      {hourDefs.map(hd => {
                        // El comedor solo se presta en CEIP Marqués de Benicarló.
                        // Si el centro elegido para este turno es otro, deshabilitar la opción.
                        const lunchBlocked = hd.k === 'lunch'
                          && child.centerPref[tk]
                          && !CENTERS_WITH_LUNCH.includes(child.centerPref[tk]);
                        const selected = (child.hours[tk] || []).includes(hd.k);
                        return (
                          <label
                            key={hd.k}
                            className={`opt ${selected ? 'selected' : ''}`}
                            style={lunchBlocked ? { opacity: 0.45, cursor: 'not-allowed', pointerEvents: 'none' } : null}
                            title={lunchBlocked ? (lang === 'val' ? 'No es presta menjador en aquest centre' : 'No se presta comedor en este centro') : undefined}
                          >
                            <input
                              type="checkbox"
                              checked={selected}
                              disabled={lunchBlocked}
                              onChange={() => { if (!lunchBlocked) onToggleHour(tk, hd.k); }}
                            />
                            <div className="top">
                              <div className="name">{hd.name}</div>
                              <div className="price-tag">{fmtEur(hd.price)}</div>
                            </div>
                            <div className="sub">
                              {lunchBlocked
                                ? (lang === 'val' ? 'No disponible en aquest centre' : 'No disponible en este centro')
                                : hd.sub}
                            </div>
                          </label>
                        );
                      })}
                    </div>
                  </div>

                  {/* Preferred center for this turn */}
                  <div className={`field ${hasErrC ? 'error' : ''}`} style={{ marginBottom: 8 }}>
                    <label style={{ fontSize: 11.5, marginBottom: 6 }}>{t.center}<span className="req">*</span></label>
                    <div className="opt-group two">
                      {t.centers.map(c => (
                        <label key={c} className={`opt ${child.centerPref[tk] === c ? 'selected' : ''}`}>
                          <input type="radio" name={`center_${idx}_${tk}`} value={c} checked={child.centerPref[tk] === c} onChange={() => onCenterPref(tk, c)} />
                          <div className="name">{c}</div>
                        </label>
                      ))}
                    </div>
                  </div>

                  {/* Accept alternative center */}
                  <div className="field">
                    <label style={{ fontSize: 11.5, marginBottom: 6 }}>{t.centerAlt}</label>
                    <div className="opt-group two">
                      {[['si', 'Sí'], ['no', 'No']].map(([v, l]) => (
                        <label key={v} className={`opt ${child.centerAlt[tk] === v ? 'selected' : ''}`} style={{ padding: '8px 12px' }}>
                          <input type="radio" name={`alt_${idx}_${tk}`} value={v} checked={child.centerAlt[tk] === v} onChange={() => onCenterAlt(tk, v)} />
                          <div className="name">{l}</div>
                        </label>
                      ))}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* NEE — checkbox + optional detail */}
      <div style={{ marginTop: 18, padding: '14px 16px', background: 'var(--sand-50)', borderRadius: 12, border: '1px solid var(--line)' }}>
        <label className="check" style={{ background: 'transparent', border: 0, padding: 0 }}>
          <input type="checkbox" checked={child.nee} onChange={e => onChange('nee', e.target.checked)} />
          <span className="txt"><strong>{t.nee}</strong></span>
        </label>
        {child.nee && (
          <div className="field" style={{ marginTop: 10 }}>
            <label style={{ fontSize: 11.5 }}>{t.neeDetail}</label>
            <textarea
              value={child.neeDetail}
              onChange={e => onChange('neeDetail', e.target.value)}
              placeholder={t.neeDetailHint}
              style={{ minHeight: 60 }}
            />
            <span className="hint">{t.neeDetailHint}</span>
          </div>
        )}
      </div>
    </div>
  );
};

// =====================================================================
// Modality section — appears only when 2+ siblings share a turn
// =====================================================================
const ModalitySection = ({ f, t, lang, onChange }) => {
  if (f.children.length < 2) return null;
  const sharedTurns = ['t1', 't2', 't3'].filter(tk =>
    f.children.filter(c => c.turns.includes(tk)).length >= 2
  );
  if (sharedTurns.length === 0) return null;
  return (
    <div className="form-section">
      <h3><span className="n">M</span>{lang === 'val' ? 'Modalitat per a germans' : 'Modalidad para hermanos'}</h3>
      <p className="desc">{t.modalityNote}</p>
      <div style={{ display: 'grid', gap: 12, marginTop: 12 }}>
        {sharedTurns.map(tk => (
          <div key={tk} style={{ padding: '12px 14px', background: 'var(--sand-50)', borderRadius: 12, border: '1px solid var(--line)' }}>
            <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--ink-soft)', marginBottom: 8 }}>
              {T[lang].when[tk]} · {T[lang].when[tk + 'd']}
            </div>
            <div className="opt-group two">
              {[['joint', t.modalityJoint], ['partial', t.modalityPartial]].map(([v, l]) => (
                <label key={v} className={`opt ${f.modality[tk] === v ? 'selected' : ''}`}>
                  <input type="radio" name={`mod_${tk}`} value={v} checked={f.modality[tk] === v} onChange={() => onChange(tk, v)} />
                  <div className="name">{l}</div>
                </label>
              ))}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

// =====================================================================
// Live summary (lateral)
// =====================================================================
const Summary = ({ lang, f }) => {
  const st = T[lang].summary;
  const { total, bonifApplied, childTotals } = computeTotal(f);
  const hourLabels = { cangur: T[lang].schedule.cangur, morning: T[lang].schedule.morning, lunch: T[lang].schedule.lunch };
  const turnLabels = { t1: T[lang].when.t1, t2: T[lang].when.t2, t3: T[lang].when.t3 };

  const childRows = f.children.map((c, i) => {
    const lines = [];
    for (const tk of c.turns) {
      for (const hk of (c.hours[tk] || [])) {
        lines.push(`${turnLabels[tk]} · ${hourLabels[hk]}`);
      }
    }
    const nameDisp = (c.firstName || c.lastName)
      ? `${c.firstName} ${c.lastName}`.trim()
      : `${st.childN} ${i + 1}`;
    const factor = bonifFactor(i, f.children.length);
    return { name: nameDisp, lines, raw: childTotals[i], total: childTotals[i] * factor, bonif: factor < 1 };
  });

  const hasAnything = childRows.some(c => c.lines.length > 0);

  return (
    <aside className="summary">
      <h3>{st.title}</h3>
      <div className="muted">{st.muted}</div>

      {!hasAnything ? (
        <div className="sum-row empty">{st.empty}</div>
      ) : (
        childRows.map((cr, i) => (
          <div key={i} style={{ marginBottom: 12, paddingBottom: 8, borderBottom: '1px dashed var(--line)' }}>
            <div style={{ fontWeight: 800, fontSize: 14, marginBottom: 4 }}>{cr.name}</div>
            {cr.lines.length === 0
              ? <div style={{ fontSize: 13, color: 'var(--ink-mute)', fontStyle: 'italic' }}>—</div>
              : cr.lines.map((l, j) => <div key={j} style={{ fontSize: 13, color: 'var(--ink-soft)' }}>· {l}</div>)
            }
            <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 6, alignItems: 'baseline' }}>
              <span style={{ fontSize: 11.5, color: cr.bonif ? 'var(--coral-600)' : 'var(--ink-mute)', fontWeight: 700 }}>
                {cr.bonif ? '−50%' : ''}
              </span>
              <span style={{ fontFamily: 'var(--font-mono)', fontWeight: 700 }}>
                {fmtEur(cr.total)}
              </span>
            </div>
          </div>
        ))
      )}

      {bonifApplied && (
        <div className="sum-bonif">★ {st.bonifApplied}</div>
      )}

      <div className="sum-total">
        <span className="k">{st.total}</span>
        <span className="v">{fmtEur(total)}</span>
      </div>
      <div className="sum-note">{st.note}</div>
    </aside>
  );
};

// =====================================================================
// Form root
// =====================================================================
const Form = ({ lang, onSubmitted }) => {
  const t = T[lang].form;
  const [f, setF] = React.useState(emptyForm());
  const [errors, setErrors] = React.useState({});
  const [toast, setToast] = React.useState(null);
  const [lopdOpen, setLopdOpen] = React.useState(false);

  const updParent = (k, v) => setF(s => ({ ...s, [k]: v }));
  const updChild = (idx, k, v) => setF(s => ({
    ...s,
    children: s.children.map((c, i) => i === idx ? { ...c, [k]: v } : c),
  }));
  const toggleChildTurn = (idx, turn) => setF(s => ({
    ...s,
    children: s.children.map((c, i) => {
      if (i !== idx) return c;
      const has = c.turns.includes(turn);
      const turns = has ? c.turns.filter(x => x !== turn) : [...c.turns, turn];
      const hours = { ...c.hours };
      if (!has && hours[turn].length === 0) hours[turn] = ['morning'];
      if (has) hours[turn] = [];
      return { ...c, turns, hours };
    }),
  }));
  const toggleChildHour = (idx, turn, hour) => setF(s => ({
    ...s,
    children: s.children.map((c, i) => {
      if (i !== idx) return c;
      const cur = c.hours[turn] || [];
      const has = cur.includes(hour);
      return { ...c, hours: { ...c.hours, [turn]: has ? cur.filter(x => x !== hour) : [...cur, hour] } };
    }),
  }));
  const updChildCenterPref = (idx, turn, value) => setF(s => ({
    ...s,
    children: s.children.map((c, i) => {
      if (i !== idx) return c;
      // Si el centro elegido no presta comedor, quitarlo automáticamente del array de servicios
      const newHours = { ...c.hours };
      if (!CENTERS_WITH_LUNCH.includes(value) && (newHours[turn] || []).includes('lunch')) {
        newHours[turn] = newHours[turn].filter(h => h !== 'lunch');
      }
      return { ...c, centerPref: { ...c.centerPref, [turn]: value }, hours: newHours };
    }),
  }));
  const updChildCenterAlt = (idx, turn, value) => setF(s => ({
    ...s,
    children: s.children.map((c, i) => i === idx ? { ...c, centerAlt: { ...c.centerAlt, [turn]: value } } : c),
  }));
  const addChild = () => setF(s => ({ ...s, children: [...s.children, emptyChild()] }));
  const removeChild = (idx) => setF(s => ({ ...s, children: s.children.filter((_, i) => i !== idx) }));
  const updModality = (turn, value) => setF(s => ({ ...s, modality: { ...s.modality, [turn]: value } }));

  const validate = () => {
    const e = {};
    if (!f.parentFirstName.trim()) e.parentFirstName = true;
    if (!f.parentLastName1.trim()) e.parentLastName1 = true;
    if (!f.dni.trim()) e.dni = true;
    else if (!validateID(f.dni)) e.dni = t.dniInvalid;
    if (!f.phone.trim()) e.phone = true;
    else if (!validatePhone(f.phone)) e.phone = t.phoneInvalid;
    if (f.phone2 && f.phone2.trim() && !validatePhone(f.phone2)) e.phone2 = t.phoneInvalid;
    if (!f.email.trim() || !/.+@.+\..+/.test(f.email)) e.email = true;
    if (!f.emailConfirm.trim() || f.email.trim().toLowerCase() !== f.emailConfirm.trim().toLowerCase()) e.emailConfirm = true;
    if (!f.consent) e.consent = true;
    f.children.forEach((c, i) => {
      if (!c.firstName.trim()) e[`child_${i}_firstName`] = true;
      if (!c.lastName.trim()) e[`child_${i}_lastName`] = true;
      if (!c.birthDate) e[`child_${i}_birthDate`] = true;
      if (!c.course) e[`child_${i}_course`] = true;
      if (c.turns.length === 0) e[`child_${i}_turns`] = true;
      else {
        for (const tk of c.turns) {
          if ((c.hours[tk] || []).length === 0) e[`child_${i}_hours_${tk}`] = true;
          if (!c.centerPref[tk]) e[`child_${i}_centerPref_${tk}`] = true;
        }
      }
    });
    return e;
  };

  const submit = async () => {
    const e = validate();
    setErrors(e);
    if (Object.keys(e).length) {
      setToast({ kind: 'error', msg: t.errors });
      setTimeout(() => setToast(null), 3200);
      setTimeout(() => {
        const el = document.querySelector('.field.error');
        if (el) {
          const y = el.getBoundingClientRect().top + window.scrollY - 120;
          window.scrollTo({ top: y, behavior: 'smooth' });
        }
      }, 50);
      return;
    }

    const familyId = uuidv4();
    const { total, bonifApplied, childTotals } = computeTotal(f);
    const records = f.children.map((c, i) => {
      const factor = bonifFactor(i, f.children.length);
      const firstTurn = c.turns[0];
      const legacyCenter = firstTurn ? c.centerPref[firstTurn] : '';
      return {
        id: Date.now().toString(36) + Math.random().toString(36).slice(2, 6),
        createdAt: new Date().toISOString(),
        familyId,
        siblingOrder: i + 1,
        siblingsTotal: f.children.length,
        // Child basics
        childFirstName: c.firstName,
        childLastName: c.lastName,
        childName: `${c.firstName} ${c.lastName}`.trim(),    // legacy compat
        birthDate: c.birthDate,
        course: c.course,
        gender: c.gender,
        // Tutor
        parentFirstName: f.parentFirstName,
        parentLastName1: f.parentLastName1,
        parentLastName2: f.parentLastName2,
        parentName: `${f.parentFirstName} ${f.parentLastName1} ${f.parentLastName2}`.trim(),
        dni: f.dni,
        phone: f.phone,
        phone2: f.phone2,
        email: f.email,
        city: f.city,
        zip: f.zip,
        address: '',
        // Per-child turn/services/center
        turns: c.turns,
        hours: c.hours,
        centerPref: c.centerPref,
        centerAlt: c.centerAlt,
        center: legacyCenter,
        modality: f.modality,
        // NEE
        nee: c.nee,
        neeDetail: c.neeDetail,
        // Deferred to matriculation phase
        large: false, largeNum: '',
        allergies: '', medication: '',
        imageAuth: false, pickupAuth: false, pickupList: '',
        signature: '', payment: null,
        // Pricing
        childRawTotal: childTotals[i],
        bonifFactor: factor,
        bonifApplied: factor < 1,
        total: childTotals[i] * factor,
        familyTotal: total,
        familyBonifApplied: bonifApplied,
        // Status flow
        status: 'preinscribed',
        // Misc
        consent: f.consent,
        obs: f.obs,
        language: lang,
      };
    });

    // Submit to Supabase
    setToast({ kind: 'success', msg: lang === 'val' ? 'Enviant…' : 'Enviando…' });
    const sbResult = await submitRecordsToSupabase(records, lang);

    if (sbResult.ok) {
      onSubmitted(records);
      setF(emptyForm());
      setErrors({});
      setToast({ kind: 'success', msg: t.saved });
    } else {
      // Real error — keep form filled and ask to retry
      setToast({
        kind: 'error',
        msg: lang === 'val'
          ? 'Error d\'enviament. Torneu a intentar-ho o contacteu amb estiubenicarlo@gmail.com.'
          : 'Error de envío. Volved a intentarlo o contactad con estiubenicarlo@gmail.com.',
      });
      console.error('[Form submit] failed:', sbResult);
    }

    setTimeout(() => setToast(null), 4500);
    window.scrollTo({ top: document.getElementById('inscribe').offsetTop - 80, behavior: 'smooth' });
  };

  const reset = () => { setF(emptyForm()); setErrors({}); };

  return (
    <section className="block" id="inscribe">
      <div className="container">
        <div className="tag">{t.tag}</div>
        <h2 className="section-title">{t.title}</h2>
        <p className="section-sub">{t.body}</p>

        <div className="form-wrap">
          <div className="form-card">

            {/* Per-child blocks */}
            {f.children.map((child, idx) => (
              <ChildBlock
                key={child.id}
                child={child}
                idx={idx}
                t={t}
                lang={lang}
                errors={errors}
                onChange={(k, v) => updChild(idx, k, v)}
                onToggleTurn={(turn) => toggleChildTurn(idx, turn)}
                onToggleHour={(turn, hour) => toggleChildHour(idx, turn, hour)}
                onCenterPref={(turn, c) => updChildCenterPref(idx, turn, c)}
                onCenterAlt={(turn, v) => updChildCenterAlt(idx, turn, v)}
                onRemove={f.children.length > 1 ? () => removeChild(idx) : null}
              />
            ))}

            {/* Add sibling */}
            <div className="form-section" style={{ borderBottom: 'none', paddingBottom: 8 }}>
              <button type="button" className="btn ghost" onClick={addChild}>{t.addSiblingBtn}</button>
            </div>

            {/* Modality (only if siblings share a turn) */}
            <ModalitySection f={f} t={t} lang={lang} onChange={updModality} />

            {/* Tutor section */}
            <div className="form-section">
              <h3><span className="n">A</span>{t.s2}</h3>
              <p className="desc">{t.s2d}</p>
              <div className="form-grid">
                <TextField label={t.parentFirstName} value={f.parentFirstName} onChange={v => updParent('parentFirstName', v)} required error={!!errors.parentFirstName} autoComplete="given-name" />
                <TextField label={t.parentLastName1} value={f.parentLastName1} onChange={v => updParent('parentLastName1', v)} required error={!!errors.parentLastName1} autoComplete="family-name" />
                <TextField label={t.parentLastName2} value={f.parentLastName2} onChange={v => updParent('parentLastName2', v)} />
                <TextField label={t.dni} value={f.dni} onChange={v => updParent('dni', v)} required
                  error={typeof errors.dni === 'string' ? errors.dni : !!errors.dni}
                  hint={t.dniHint} placeholder="12345678A · X1234567L · ABC123456" />
                <TextField label={t.phone} type="tel" value={f.phone} onChange={v => updParent('phone', v)} required
                  error={typeof errors.phone === 'string' ? errors.phone : !!errors.phone}
                  hint={t.phoneHint} autoComplete="tel" placeholder="600123456" />
                <TextField label={t.phone2} type="tel" value={f.phone2} onChange={v => updParent('phone2', v)}
                  error={typeof errors.phone2 === 'string' ? errors.phone2 : !!errors.phone2}
                  placeholder="600123456" />
                <TextField label={t.email} type="email" value={f.email} onChange={v => updParent('email', v)} required error={!!errors.email} full autoComplete="email" placeholder="email@example.com" />
                <TextField label={t.emailConfirm} type="email" value={f.emailConfirm} onChange={v => updParent('emailConfirm', v)} required error={errors.emailConfirm ? t.emailMismatch : false} hint={t.emailConfirmHint} full autoComplete="off" />
              </div>
            </div>

            {/* Observations */}
            <div className="form-section">
              <h3><span className="n">B</span>{t.s5}</h3>
              <p className="desc">{t.s5d}</p>
              <div className="field">
                <textarea value={f.obs} onChange={e => updParent('obs', e.target.value)} />
              </div>
            </div>

            {/* Consent */}
            <label className={`check ${errors.consent ? 'error' : ''}`} style={{ background: errors.consent ? 'color-mix(in oklab, var(--coral-500) 8%, white)' : 'var(--sand-50)', border: errors.consent ? '1.5px solid var(--coral-500)' : '1px solid var(--line)' }}>
              <input type="checkbox" checked={f.consent} onChange={e => updParent('consent', e.target.checked)} />
              <span className="txt">
                {t.consent} <span className="req">*</span>
                {' '}
                <button type="button" onClick={(e) => { e.preventDefault(); setLopdOpen(true); }} style={{ background:'transparent', border:0, padding:0, color:'var(--brand-500, #2b6cb0)', textDecoration:'underline', cursor:'pointer', fontSize:'inherit', fontFamily:'inherit' }}>
                  {t.lopdLink || 'Veure política completa'}
                </button>
              </span>
            </label>

            <div className="lopd-inline">
              <span className="lopd-icon" aria-hidden="true">
                <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" /></svg>
              </span>
              <span>{t.lopdShort}</span>
            </div>

            {lopdOpen && (
              <div role="dialog" aria-modal="true" onClick={(e) => { if (e.target === e.currentTarget) setLopdOpen(false); }}
                   style={{ position:'fixed', inset:0, background:'rgba(0,0,0,0.5)', zIndex:1000, display:'flex', alignItems:'center', justifyContent:'center', padding:'20px' }}>
                <div style={{ background:'#fff', borderRadius:14, maxWidth:680, width:'100%', maxHeight:'85vh', overflowY:'auto', padding:'28px 32px' }}>
                  <h2 style={{ marginTop:0, fontSize:18, lineHeight:1.3 }}>{t.lopdTitle || 'Política de protección de datos'}</h2>
                  <div style={{ fontSize:13.5, lineHeight:1.6, color:'#1a2330' }}>
                    {(t.lopdFull || []).map((p, i) => (
                      <p key={i} style={{ margin:'10px 0' }}>{renderBoldSegments(String(p))}</p>
                    ))}
                  </div>
                  <div style={{ marginTop:18, display:'flex', justifyContent:'flex-end' }}>
                    <button type="button" className="btn primary" onClick={() => setLopdOpen(false)}>Tancar / Cerrar</button>
                  </div>
                </div>
              </div>
            )}

            <div className="form-actions" style={{ marginTop: 22 }}>
              <button className="btn ghost" type="button" onClick={reset}>{t.reset}</button>
              <button className="btn primary" type="button" onClick={submit}>{t.submit} →</button>
            </div>
            <p style={{ fontSize: 12.5, color: 'var(--ink-mute)', marginTop: 12 }}>{t.placesDisclaimer}</p>

          </div>

          <Summary lang={lang} f={f} />
        </div>
      </div>

      {toast && <div className={`toast ${toast.kind}`}>{toast.kind === 'success' ? '✓' : '⚠'} {toast.msg}</div>}
    </section>
  );
};

window.Form = Form;
window.PRICES = PRICES;
window.computeTotal = computeTotal;
window.fmtEur = fmtEur;
