// BookingModal.jsx — modale de réservation réelle, partagée par index.html
// et par les pages de détail des offres (offres/*.html). Créneaux depuis le
// backend, formulaire validé, confirmation seulement quand le serveur a
// confirmé (spec booking/UX-SPEC-reservation-appel.md).
// Exposé via window.BookingModal — chargé après booking-config.js et Icon.jsx.

const bookingModalStyles = {
  modalScrim: {
    position: 'fixed', inset: 0, zIndex: 200,
    background: 'rgba(42, 26, 7,.55)',
    backdropFilter: 'blur(6px)',
    WebkitBackdropFilter: 'blur(6px)',
    display: 'flex', alignItems: 'center', justifyContent: 'center',
    padding: 24,
    animation: 'b2a-fade-in 240ms cubic-bezier(.2,.8,.2,1)',
  },
  modal: {
    width: '100%',
    maxWidth: 520,
    maxHeight: 'calc(100vh - 48px)',
    overflowY: 'auto',
    background: 'var(--paper)',
    color: 'var(--ink-900)',
    border: '1px solid var(--ink-900)',
    boxShadow: '8px 8px 0 0 var(--amber-500)',
    padding: 36,
    position: 'relative',
    animation: 'b2a-modal-in 240ms cubic-bezier(.2,.8,.2,1)',
  },
  close: {
    position: 'absolute', top: 16, right: 16,
    background: 'transparent', border: 'none', cursor: 'pointer',
    padding: 8, color: 'var(--ink-900)', minWidth: 44, minHeight: 44,
    display: 'flex', alignItems: 'center', justifyContent: 'center',
  },
  modalTitle: {
    fontFamily: "'Space Grotesk', sans-serif",
    fontWeight: 600, fontSize: 30, letterSpacing: '-0.02em',
    margin: '0 0 12px', outline: 'none',
  },
  modalBody: {
    fontSize: 16, lineHeight: 1.5, color: 'var(--mist-700)', margin: '0 0 24px',
  },
  dayLabel: {
    fontFamily: "'JetBrains Mono', monospace", fontSize: 11,
    letterSpacing: '0.08em', textTransform: 'uppercase',
    color: 'var(--mist-500)', margin: '16px 0 8px',
  },
  slotRow: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 },
  slot: {
    border: '1px solid rgba(42, 26, 7,.20)',
    padding: '12px 10px',
    background: '#fff',
    cursor: 'pointer',
    fontFamily: "'Space Grotesk', sans-serif",
    fontWeight: 500, fontSize: 16,
    textAlign: 'center',
    minHeight: 44,
    transition: 'border-color 160ms, background 160ms',
  },
  slotSelected: {
    borderColor: 'var(--ink-900)',
    background: 'var(--amber-500)',
    color: 'var(--paper)',
  },
  skeleton: {
    height: 44, background: 'rgba(42, 26, 7,.07)',
    animation: 'b2a-fade-in 900ms ease-in-out infinite alternate',
  },
  notice: {
    display: 'flex', alignItems: 'flex-start', gap: 10,
    padding: '14px 16px', background: '#fff',
    border: '1px solid rgba(42, 26, 7,.20)',
    fontSize: 14, lineHeight: 1.5, margin: '0 0 16px',
  },
  noticeWarn: { borderColor: 'var(--amber-500)' },
  field: { margin: '0 0 16px' },
  label: {
    display: 'block', fontFamily: "'JetBrains Mono', monospace",
    fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase',
    color: 'var(--mist-700)', marginBottom: 6,
  },
  input: {
    width: '100%', boxSizing: 'border-box',
    border: '1px solid rgba(42, 26, 7,.30)',
    padding: '12px 14px', minHeight: 44,
    fontFamily: 'var(--font-body)', fontSize: 16,
    background: '#fff', color: 'var(--ink-900)',
  },
  inputError: { borderColor: '#C0392B' },
  fieldError: { color: '#C0392B', fontSize: 13, margin: '6px 0 0' },
  chosen: {
    display: 'flex', alignItems: 'center', justifyContent: 'space-between',
    gap: 12, padding: '12px 16px', background: '#fff',
    border: '1px solid var(--ink-900)', marginBottom: 20,
  },
  chosenText: { fontFamily: "'JetBrains Mono', monospace", fontSize: 12, letterSpacing: '0.04em' },
  changeLink: {
    background: 'transparent', border: 'none', cursor: 'pointer',
    color: 'var(--ink-900)', textDecoration: 'underline',
    fontSize: 13, padding: 8, minHeight: 44,
  },
  consent: { fontSize: 12.5, lineHeight: 1.5, color: 'var(--mist-500)', margin: '12px 0 0' },
  confirm: {
    display: 'flex', alignItems: 'center', gap: 12,
    padding: '16px', background: '#fff',
    border: '1px solid var(--ink-900)', marginBottom: 16,
  },
  confirmText: { fontFamily: "'JetBrains Mono', monospace", fontSize: 12, letterSpacing: '0.04em' },
  fallback: { fontSize: 13.5, color: 'var(--mist-500)', margin: '16px 0 0', textAlign: 'center' },
  honeypot: {
    position: 'absolute', left: '-9999px', top: 'auto',
    width: 1, height: 1, overflow: 'hidden',
  },
};

// --- Validation côté client (mêmes règles que le serveur) ---
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
const validateBookingField = (field, value) => {
  const v = (value || '').trim();
  if (field === 'name' && !v) return 'Entrez votre prénom et votre nom.';
  if (field === 'email') {
    if (!v) return 'Le courriel est requis — c’est là qu’arrive l’invitation.';
    if (!EMAIL_RE.test(v)) return 'Ce courriel ne semble pas valide. Vérifiez le format.';
  }
  if (field === 'phone') {
    if (!v) return 'Le téléphone est requis — on vous rappelle en cas d’imprévu.';
    if (v.replace(/\D/g, '').length < 10) return 'Entrez un numéro complet (au moins 10 chiffres).';
  }
  return null;
};

// Libellé français d'une date locale YYYY-MM-DD (construit à midi UTC pour
// éviter tout glissement de jour).
const frBookingDayLabel = (dateLocal) => {
  const [y, m, d] = dateLocal.split('-').map(Number);
  return new Intl.DateTimeFormat('fr-CA', { weekday: 'short', day: 'numeric', month: 'long' })
    .format(new Date(Date.UTC(y, m - 1, d, 12)));
};

const BOOKING_MAILTO = (
  <a href="mailto:hello@theb2atek.com" className="b2a-link" style={{ color: 'inherit' }}>
    hello@theb2atek.com
  </a>
);

const BookingModal = ({ onClose }) => {
  const [step, setStep] = React.useState('slots');          // slots | form | done
  const [slotsStatus, setSlotsStatus] = React.useState('loading'); // loading | ready | empty | error | unconfigured
  const [slots, setSlots] = React.useState([]);
  const [selected, setSelected] = React.useState(null);     // objet créneau
  const [conflict, setConflict] = React.useState(false);    // créneau pris entre-temps
  const [form, setForm] = React.useState({ name: '', email: '', phone: '', pain: '', website: '' });
  const [errors, setErrors] = React.useState({});
  const [submitting, setSubmitting] = React.useState(false);
  const [submitError, setSubmitError] = React.useState(false);
  const [confirmedWhen, setConfirmedWhen] = React.useState('');
  const modalRef = React.useRef(null);
  const titleRef = React.useRef(null);

  const loadSlots = React.useCallback(() => {
    if (!window.isBookingConfigured()) { setSlotsStatus('unconfigured'); return; }
    setSlotsStatus('loading');
    fetch(window.bookingApiUrl('slots'), { headers: window.bookingApiHeaders() })
      .then((r) => { if (!r.ok) throw new Error(r.status); return r.json(); })
      .then((data) => {
        const list = data.slots || [];
        setSlots(list);
        setSlotsStatus(list.length ? 'ready' : 'empty');
      })
      .catch(() => setSlotsStatus('error'));
  }, []);

  React.useEffect(() => { loadSlots(); }, [loadSlots]);

  // Blocage du scroll de fond + restauration du focus au déclencheur (M3/M4)
  React.useEffect(() => {
    const trigger = document.activeElement;
    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => {
      document.body.style.overflow = prevOverflow;
      if (trigger && typeof trigger.focus === 'function') trigger.focus();
    };
  }, []);

  // Échap + focus-trap clavier (Q2)
  React.useEffect(() => {
    const node = modalRef.current;
    const focusables = () => node.querySelectorAll(
      'button:not([disabled]), [href], input:not([tabindex="-1"]), textarea, [tabindex]:not([tabindex="-1"])'
    );
    const onKey = (e) => {
      if (e.key === 'Escape') { onClose(); return; }
      if (e.key !== 'Tab') return;
      const items = focusables();
      if (!items.length) return;
      const f = items[0], l = items[items.length - 1];
      if (e.shiftKey && document.activeElement === f) { e.preventDefault(); l.focus(); }
      else if (!e.shiftKey && document.activeElement === l) { e.preventDefault(); f.focus(); }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);

  // À chaque changement d'étape, le focus va au titre (lecture d'écran + clavier)
  React.useEffect(() => {
    if (titleRef.current) titleRef.current.focus();
  }, [step, slotsStatus]);

  const setField = (field) => (e) => {
    setForm((f) => ({ ...f, [field]: e.target.value }));
    if (errors[field]) setErrors((er) => ({ ...er, [field]: null }));
  };
  const blurField = (field) => () => {
    setErrors((er) => ({ ...er, [field]: validateBookingField(field, form[field]) }));
  };

  const submit = (e) => {
    e.preventDefault();
    const errs = {};
    for (const f of ['name', 'email', 'phone']) {
      const msg = validateBookingField(f, form[f]);
      if (msg) errs[f] = msg;
    }
    setErrors(errs);
    if (Object.keys(errs).length) return;

    setSubmitting(true);
    setSubmitError(false);
    fetch(window.bookingApiUrl('book'), {
      method: 'POST',
      headers: window.bookingApiHeaders(),
      body: JSON.stringify({ slotStartUtc: selected.startUtc, ...form }),
    })
      .then((r) => r.json().then((data) => ({ status: r.status, data })))
      .then(({ status, data }) => {
        if (status === 200 && data.ok) {
          setConfirmedWhen(data.when || `${frBookingDayLabel(selected.dateLocal)} à ${selected.timeLocal} (HE)`);
          setStep('done');
        } else if (status === 409) {
          // Créneau pris entre-temps : retour étape 1, créneaux rafraîchis.
          setSelected(null);
          setConflict(true);
          setStep('slots');
          loadSlots();
        } else if (status === 400 && data.fields) {
          setErrors(data.fields);
        } else {
          setSubmitError(true);
        }
      })
      .catch(() => setSubmitError(true))
      .finally(() => setSubmitting(false));
  };

  // Groupement des créneaux par jour (max 12 jours affichés)
  const byDay = [];
  for (const s of slots) {
    const last = byDay[byDay.length - 1];
    if (last && last.dateLocal === s.dateLocal) last.items.push(s);
    else byDay.push({ dateLocal: s.dateLocal, items: [s] });
  }

  const fieldProps = (field, label, type, autoComplete, hint) => (
    <div style={bookingModalStyles.field}>
      <label style={bookingModalStyles.label} htmlFor={`bk-${field}`}>{label}</label>
      <input
        id={`bk-${field}`}
        type={type}
        autoComplete={autoComplete}
        value={form[field]}
        onChange={setField(field)}
        onBlur={blurField(field)}
        aria-invalid={Boolean(errors[field])}
        aria-describedby={errors[field] ? `bk-${field}-err` : undefined}
        style={{ ...bookingModalStyles.input, ...(errors[field] ? bookingModalStyles.inputError : {}) }}
        placeholder={hint}
      />
      {errors[field] && (
        <p id={`bk-${field}-err`} role="alert" style={bookingModalStyles.fieldError}>{errors[field]}</p>
      )}
    </div>
  );

  return (
    <div style={bookingModalStyles.modalScrim} onClick={onClose}>
      <div
        ref={modalRef}
        style={bookingModalStyles.modal}
        onClick={(e) => e.stopPropagation()}
        role="dialog"
        aria-modal="true"
        aria-labelledby="booking-title"
      >
        <button style={bookingModalStyles.close} onClick={onClose} aria-label="Fermer"><Icon name="x" size={20} /></button>

        {step === 'slots' && (
          <>
            <h3 style={bookingModalStyles.modalTitle} id="booking-title" ref={titleRef} tabIndex={-1}>
              Réserver un appel de 20 min
            </h3>
            <p style={bookingModalStyles.modalBody}>
              Choisissez un créneau (heure de l'Est). L'invitation arrive dans
              votre boîte courriel. Aucune préparation requise.
            </p>

            {conflict && (
              <div style={{ ...bookingModalStyles.notice, ...bookingModalStyles.noticeWarn }} role="alert">
                <Icon name="alert-triangle" size={18} color="var(--amber-500)" />
                <span>Ce créneau vient tout juste d'être pris. En voici d'autres.</span>
              </div>
            )}

            {slotsStatus === 'loading' && (
              <div style={bookingModalStyles.slotRow} aria-label="Chargement des créneaux">
                {[0, 1, 2, 3, 4, 5].map((i) => <div key={i} style={bookingModalStyles.skeleton} />)}
              </div>
            )}

            {slotsStatus === 'ready' && (
              <div style={{ maxHeight: 320, overflowY: 'auto', paddingRight: 4 }}>
                {byDay.map((day) => (
                  <div key={day.dateLocal}>
                    <p style={bookingModalStyles.dayLabel}>{frBookingDayLabel(day.dateLocal)}</p>
                    <div style={bookingModalStyles.slotRow}>
                      {day.items.map((s) => (
                        <button
                          key={s.startUtc}
                          style={{
                            ...bookingModalStyles.slot,
                            ...(selected && selected.startUtc === s.startUtc ? bookingModalStyles.slotSelected : {}),
                          }}
                          onClick={() => setSelected(s)}
                          aria-pressed={selected ? selected.startUtc === s.startUtc : false}
                        >
                          {s.timeLocal}
                        </button>
                      ))}
                    </div>
                  </div>
                ))}
              </div>
            )}

            {slotsStatus === 'empty' && (
              <div style={bookingModalStyles.notice}>
                <span>
                  Aucun créneau disponible pour l'instant. Écrivez-nous à {BOOKING_MAILTO} et
                  on trouve un moment.
                </span>
              </div>
            )}

            {(slotsStatus === 'error' || slotsStatus === 'unconfigured') && (
              <div style={{ ...bookingModalStyles.notice, ...bookingModalStyles.noticeWarn }} role="alert">
                <span>
                  Impossible de charger les créneaux pour le moment.{' '}
                  {slotsStatus === 'error' && (
                    <button className="b2a-link" style={bookingModalStyles.changeLink} onClick={loadSlots}>
                      Réessayer
                    </button>
                  )}{' '}
                  Ou écrivez-nous directement : {BOOKING_MAILTO}.
                </span>
              </div>
            )}

            {slotsStatus === 'ready' && (
              <button
                className="b2a-btn b2a-btn-primary"
                style={{ width: '100%', justifyContent: 'center', marginTop: 20 }}
                onClick={() => selected && setStep('form')}
                disabled={!selected}
              >
                {selected ? 'Continuer' : 'Choisissez un créneau'} <Icon name="arrow-right" size={16} />
              </button>
            )}
          </>
        )}

        {step === 'form' && (
          <>
            <h3 style={bookingModalStyles.modalTitle} id="booking-title" ref={titleRef} tabIndex={-1}>
              Vos coordonnées
            </h3>
            <div style={bookingModalStyles.chosen}>
              <span style={bookingModalStyles.chosenText}>
                {frBookingDayLabel(selected.dateLocal).toUpperCase()} · {selected.timeLocal} (HE)
              </span>
              <button style={bookingModalStyles.changeLink} onClick={() => setStep('slots')}>
                Modifier
              </button>
            </div>

            <form onSubmit={submit} noValidate>
              {fieldProps('name', 'Prénom et nom', 'text', 'name')}
              {fieldProps('email', 'Courriel', 'email', 'email', 'vous@entreprise.ca')}
              {fieldProps('phone', 'Téléphone', 'tel', 'tel', '514 555 0199')}

              <div style={bookingModalStyles.field}>
                <label style={bookingModalStyles.label} htmlFor="bk-pain">
                  Qu'est-ce qui vous gruge le plus de temps ? (optionnel)
                </label>
                <textarea
                  id="bk-pain"
                  rows={2}
                  value={form.pain}
                  onChange={setField('pain')}
                  style={{ ...bookingModalStyles.input, resize: 'vertical', fontFamily: 'var(--font-body)' }}
                />
              </div>

              {/* Pot-de-miel anti-robot : invisible pour les humains */}
              <div style={bookingModalStyles.honeypot} aria-hidden="true">
                <label htmlFor="bk-website">Ne pas remplir</label>
                <input
                  id="bk-website" type="text" tabIndex={-1} autoComplete="off"
                  value={form.website} onChange={setField('website')}
                />
              </div>

              {submitError && (
                <div style={{ ...bookingModalStyles.notice, ...bookingModalStyles.noticeWarn }} role="alert">
                  <span>
                    La réservation n'a pas pu être confirmée. Réessayez, ou
                    écrivez-nous directement : {BOOKING_MAILTO}.
                  </span>
                </div>
              )}

              <button
                type="submit"
                className="b2a-btn b2a-btn-primary"
                style={{ width: '100%', justifyContent: 'center' }}
                disabled={submitting}
              >
                {submitting ? 'Réservation…' : 'Confirmer — recevoir l\'invitation'}
                {!submitting && <Icon name="arrow-right" size={16} />}
              </button>

              <p style={bookingModalStyles.consent}>
                En réservant, vous acceptez d'être contacté au sujet de votre
                demande. Rien d'autre, pas d'infolettre.
              </p>
            </form>
          </>
        )}

        {step === 'done' && (
          <>
            <h3 style={bookingModalStyles.modalTitle} id="booking-title" ref={titleRef} tabIndex={-1}>
              C'est réservé, {form.name.split(' ')[0]}.
            </h3>
            <p style={bookingModalStyles.modalBody}>
              L'invitation est en route vers <strong>{form.email}</strong>.
              Elle contient le lien de l'appel — rien à préparer.
              <br />Au {confirmedWhen}.
            </p>
            <div style={bookingModalStyles.confirm}>
              <Icon name="check-circle" size={20} color="#34C797" />
              <span style={bookingModalStyles.confirmText}>
                INVITATION ENVOYÉE · VÉRIFIEZ VOS COURRIELS (ET LES INDÉSIRABLES)
              </span>
            </div>
            <button className="b2a-btn b2a-btn-ghost" onClick={onClose} style={{ width: '100%', justifyContent: 'center' }}>
              Fermer
            </button>
          </>
        )}

        {step !== 'done' && (
          <p style={bookingModalStyles.fallback}>
            Vous préférez écrire ? {BOOKING_MAILTO}
          </p>
        )}
      </div>
    </div>
  );
};

window.BookingModal = BookingModal;
