// Registration form for the Florey ASO update (SCN2A and SLC6A1 families).
//
// Posts to /api/event-register, which emails the organisation's inbox and
// sends the registrant a confirmation. Nothing is stored in the browser or in
// a third-party form tool, so the privacy promise on /privacy holds as written.
//
// Every fact about the event lives in FLOREY_ASO_EVENT below. Dates are stored
// as ISO and their labels are derived, so the weekday can never drift out of
// step with the date.

const FLOREY_ASO_EVENT = {
  key: 'florey-aso-update',
  name: 'Florey ASO update',
  date: '2026-09-11',
  startTime: '1:30 pm',
  arrivalTime: '1:15 pm',
  registrationsClose: '2026-09-10',
  venue: 'The Florey',
  street: '30 Royal Parade, Parkville',
  address: '30 Royal Parade, Parkville VIC 3052',
  mapUrl: 'https://maps.google.com/?q=30+Royal+Parade,+Parkville+VIC+3052',
};

const REGISTER_ENDPOINT = '/api/event-register';
const EMAIL_RE = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;

// Australian date convention: Friday 11 September. Parsed at midday so a
// timezone offset can never roll the date back a day.
function auDate(iso, withWeekday = true) {
  const d = new Date(iso + 'T12:00:00');
  return d.toLocaleDateString('en-AU', {
    weekday: withWeekday ? 'long' : undefined,
    day: 'numeric',
    month: 'long',
  });
}

const AU_STATES = [
  'Australian Capital Territory', 'New South Wales', 'Northern Territory',
  'Queensland', 'South Australia', 'Tasmania', 'Victoria', 'Western Australia',
  'Outside Australia',
];

const GENE_OPTIONS = [
  { value: 'SCN2A', label: 'SCN2A' },
  { value: 'SLC6A1', label: 'SLC6A1' },
  { value: 'Another gene', label: 'Another gene' },
  { value: 'Not applicable', label: 'Not applicable' },
];

// ── Shared field styling ───────────────────────────────────────────────

const LABEL_STYLE = {
  display: 'block',
  fontSize: 13,
  fontWeight: 600,
  letterSpacing: '0.09em',
  textTransform: 'uppercase',
  color: 'var(--colour-muted)',
  marginBottom: 10,
};

const FIELD_STYLE = {
  width: '100%',
  boxSizing: 'border-box',
  padding: '14px 16px',
  minHeight: 52, // comfortably over the 44px tap-target floor
  border: '1px solid var(--colour-divider)',
  borderRadius: 'var(--radius-btn)',
  background: 'var(--colour-canvas)',
  fontFamily: 'inherit',
  fontSize: 16, // 16px or more stops iOS zooming the page on focus
  lineHeight: 1.4,
  color: 'var(--colour-ink)',
};

const HINT_STYLE = { fontSize: 14, lineHeight: 1.5, color: 'var(--colour-muted)', margin: '8px 0 0' };

function FieldError({ id, message }) {
  if (!message) return null;
  return (
    <div id={id} style={{
      display: 'flex', alignItems: 'flex-start', gap: 6, marginTop: 8,
      fontSize: 14, fontWeight: 600, lineHeight: 1.45, color: 'var(--colour-ink)',
    }}>
      <i data-lucide="alert-circle" style={{ width: 16, height: 16, flexShrink: 0, marginTop: 2 }} />
      <span>{message}</span>
    </div>
  );
}

// Radio row with an optional second line, used for gene and attendance.
function RadioRow({ name, value, checked, onChange, label, detail }) {
  const id = `${name}-${String(value).replace(/\W+/g, '-').toLowerCase()}`;
  return (
    <label htmlFor={id} style={{
      display: 'flex', alignItems: 'flex-start', gap: 14,
      padding: '10px 0', cursor: 'pointer',
    }}>
      <input id={id} type="radio" name={name} value={value} checked={checked} onChange={onChange}
        style={{ width: 20, height: 20, marginTop: 2, flexShrink: 0, accentColor: 'var(--colour-navy)' }} />
      <span>
        <span style={{
          display: 'block', fontSize: 16, lineHeight: 1.4, color: 'var(--colour-ink)',
          fontWeight: detail ? 700 : 500,
        }}>{label}</span>
        {detail && (
          <span style={{ display: 'block', fontSize: 14, lineHeight: 1.5, color: 'var(--colour-muted)', marginTop: 3 }}>
            {detail}
          </span>
        )}
      </span>
    </label>
  );
}

// ── The form ───────────────────────────────────────────────────────────

function EventRegistrationForm({ event = FLOREY_ASO_EVENT, id = 'register' }) {
  const [form, setForm] = React.useState({
    name: '', email: '', state: '', gene: '', geneOther: '', attend: '', website: '',
  });
  const [errors, setErrors] = React.useState({});
  const [status, setStatus] = React.useState('idle'); // idle | sending | sent | failed
  const [failMessage, setFailMessage] = React.useState('');
  const doneRef = React.useRef(null);

  const set = (key) => (e) => {
    const value = e.target.value;
    setForm((prev) => ({ ...prev, [key]: value }));
    setErrors((prev) => (prev[key] ? { ...prev, [key]: '' } : prev));
  };

  // Send focus to the confirmation, so keyboard and screen-reader users land
  // on the outcome instead of on a form that has just vanished.
  React.useEffect(() => {
    if (status === 'sent' && doneRef.current) doneRef.current.focus();
  }, [status]);

  const closed = React.useMemo(
    () => new Date() > new Date(event.registrationsClose + 'T23:59:59+10:00'),
    [event.registrationsClose]
  );

  const validate = () => {
    const next = {};
    if (form.name.trim().length < 2) next.name = 'Please give us your first and last name.';
    if (!EMAIL_RE.test(form.email.trim())) next.email = 'Please check your email address, your confirmation goes there.';
    if (!form.attend) next.attend = 'Please tell us whether you are coming in person or joining online.';
    if (form.gene === 'Another gene' && !form.geneOther.trim()) next.geneOther = 'Please tell us which gene.';
    setErrors(next);
    const firstBad = ['name', 'email', 'geneOther', 'attend'].find((k) => next[k]);
    if (firstBad) {
      const el = document.getElementById(`${id}-${firstBad}`) ||
        document.querySelector(`[name="${id}-${firstBad}"]`);
      if (el && el.focus) el.focus();
    }
    return !firstBad;
  };

  const submit = async (e) => {
    e.preventDefault();
    if (status === 'sending' || !validate()) return;
    setStatus('sending');
    setFailMessage('');
    try {
      const res = await fetch(REGISTER_ENDPOINT, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          event: event.key,
          name: form.name.trim(),
          email: form.email.trim(),
          state: form.state,
          gene: form.gene === 'Another gene' ? `Another gene: ${form.geneOther.trim()}` : form.gene,
          attend: form.attend,
          website: form.website,
        }),
      });
      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        throw new Error(data.error || 'Something went wrong at our end.');
      }
      setStatus('sent');
    } catch (err) {
      setStatus('failed');
      setFailMessage(err && err.message ? err.message : 'Something went wrong at our end.');
    }
  };

  const header = `${auDate(event.date)}, ${event.startTime} · ${event.street}`;

  const shell = (children) => (
    <div id={id} style={{
      maxWidth: 640,
      background: '#fff',
      border: '1px solid var(--colour-divider)',
      borderRadius: 'var(--radius-card)',
      overflow: 'hidden',
    }}>
      <div style={{
        background: 'var(--colour-navy)', color: '#fff',
        padding: '18px 26px', fontSize: 16, fontWeight: 500, lineHeight: 1.4,
      }}>
        {header}
      </div>
      {children}
    </div>
  );

  // ── Confirmed ────────────────────────────────────────────────────────
  if (status === 'sent') {
    const inPerson = form.attend === 'In person';
    return shell(
      <div ref={doneRef} tabIndex={-1} role="status" style={{ padding: '32px 26px 34px' }}>
        <i data-lucide="check-circle-2" style={{ width: 36, height: 36, color: 'var(--colour-navy)' }} />
        <h3 style={{
          fontSize: 24, fontWeight: 700, color: 'var(--colour-ink)',
          margin: '14px 0 10px', lineHeight: 1.25,
        }}>
          You are registered, {form.name.trim().split(' ')[0]}.
        </h3>
        <p style={{ fontSize: 16, lineHeight: 1.6, color: 'var(--colour-muted)', margin: '0 0 24px' }}>
          A confirmation is on its way to {form.email.trim()}, with everything below in it.
        </p>

        <div style={{
          background: 'var(--colour-mid)',
          borderLeft: '3px solid var(--colour-navy)',
          borderRadius: '0 var(--radius-card) var(--radius-card) 0',
          padding: '18px 20px',
        }}>
          {inPerson ? (
            <React.Fragment>
              <div style={{ fontSize: 17, fontWeight: 700, color: 'var(--colour-ink)', lineHeight: 1.35 }}>
                Meet in the foyer at {event.arrivalTime}
              </div>
              <p style={{ fontSize: 15, lineHeight: 1.6, color: 'var(--colour-muted)', margin: '8px 0 0' }}>
                Please arrive at {event.venue}, {event.address}, by {event.arrivalTime}. The Florey team
                will meet you in the lobby. The talk starts at {event.startTime}.
              </p>
              <p style={{ fontSize: 15, lineHeight: 1.6, color: 'var(--colour-muted)', margin: '10px 0 0' }}>
                <a href={event.mapUrl} target="_blank" rel="noopener" style={{ color: 'var(--colour-muted)' }}>Open in maps</a>
              </p>
            </React.Fragment>
          ) : (
            <React.Fragment>
              <div style={{ fontSize: 17, fontWeight: 700, color: 'var(--colour-ink)', lineHeight: 1.35 }}>
                Your Zoom link is coming by email
              </div>
              <p style={{ fontSize: 15, lineHeight: 1.6, color: 'var(--colour-muted)', margin: '8px 0 0' }}>
                We send it a few days before {auDate(event.date)}. Join a couple of minutes
                before {event.startTime} so we can start on time.
              </p>
            </React.Fragment>
          )}
        </div>

        <p style={{ fontSize: 14, lineHeight: 1.6, color: 'var(--colour-muted)', margin: '22px 0 0' }}>
          If your plans change, reply to that email and we will free up your place.
        </p>
      </div>
    );
  }

  // ── Registrations closed ─────────────────────────────────────────────
  if (closed) {
    return shell(
      <div style={{ padding: '32px 26px 34px' }}>
        <h3 style={{ fontSize: 22, fontWeight: 700, color: 'var(--colour-ink)', margin: '0 0 10px', lineHeight: 1.3 }}>
          Registrations have closed.
        </h3>
        <p style={{ fontSize: 16, lineHeight: 1.6, color: 'var(--colour-muted)', margin: 0 }}>
          Registrations closed on {auDate(event.registrationsClose)}. If you still want to come,
          email <a href="mailto:info@scn2aaustralia.org" style={{ color: 'var(--colour-ink)' }}>info@scn2aaustralia.org</a> and
          we will see what we can do.
        </p>
      </div>
    );
  }

  // ── The form ─────────────────────────────────────────────────────────
  return shell(
    <form onSubmit={submit} noValidate style={{ padding: '30px 26px 32px' }}>
      {/* Honeypot: invisible to people, tempting to bots. */}
      <div aria-hidden="true" style={{ position: 'absolute', left: -9999, width: 1, height: 1, overflow: 'hidden' }}>
        <label htmlFor={`${id}-website`}>Leave this field empty</label>
        <input id={`${id}-website`} type="text" tabIndex={-1} autoComplete="off"
          value={form.website} onChange={set('website')} />
      </div>

      <div style={{ marginBottom: 26 }}>
        <label htmlFor={`${id}-name`} style={LABEL_STYLE}>Full name</label>
        <input id={`${id}-name`} type="text" required autoComplete="name"
          placeholder="First and last name" value={form.name} onChange={set('name')}
          style={FIELD_STYLE}
          aria-invalid={errors.name ? 'true' : undefined}
          aria-describedby={errors.name ? `${id}-name-error` : undefined} />
        <FieldError id={`${id}-name-error`} message={errors.name} />
      </div>

      <div style={{ marginBottom: 26 }}>
        <label htmlFor={`${id}-email`} style={LABEL_STYLE}>Email</label>
        <input id={`${id}-email`} type="email" required autoComplete="email" inputMode="email"
          placeholder="you@example.com" value={form.email} onChange={set('email')}
          style={FIELD_STYLE}
          aria-invalid={errors.email ? 'true' : undefined}
          aria-describedby={`${id}-email-hint${errors.email ? ` ${id}-email-error` : ''}`} />
        <p id={`${id}-email-hint`} style={HINT_STYLE}>
          Where we send your confirmation and, for online attendees, the Zoom link.
        </p>
        <FieldError id={`${id}-email-error`} message={errors.email} />
      </div>

      <div style={{ marginBottom: 26 }}>
        <label htmlFor={`${id}-state`} style={LABEL_STYLE}>
          State or territory <span style={{ textTransform: 'none', letterSpacing: 0, fontWeight: 500 }}>(optional)</span>
        </label>
        <select id={`${id}-state`} value={form.state} onChange={set('state')} style={FIELD_STYLE}>
          <option value="">Select…</option>
          {AU_STATES.map((s) => <option key={s} value={s}>{s}</option>)}
        </select>
      </div>

      <fieldset style={{ border: 0, padding: 0, margin: '0 0 26px' }}>
        <legend style={{ ...LABEL_STYLE, padding: 0 }}>
          Gene <span style={{ textTransform: 'none', letterSpacing: 0, fontWeight: 500 }}>(optional)</span>
        </legend>
        {GENE_OPTIONS.map((g) => (
          <RadioRow key={g.value} name={`${id}-gene`} value={g.value}
            checked={form.gene === g.value} onChange={set('gene')} label={g.label} />
        ))}
        {form.gene === 'Another gene' && (
          <div style={{ marginTop: 10, paddingLeft: 34 }}>
            <label htmlFor={`${id}-geneOther`} style={{ ...LABEL_STYLE, marginBottom: 8 }}>Which gene</label>
            <input id={`${id}-geneOther`} type="text" value={form.geneOther} onChange={set('geneOther')}
              style={FIELD_STYLE}
              aria-invalid={errors.geneOther ? 'true' : undefined}
              aria-describedby={errors.geneOther ? `${id}-geneOther-error` : undefined} />
            <FieldError id={`${id}-geneOther-error`} message={errors.geneOther} />
          </div>
        )}
      </fieldset>

      <fieldset style={{ border: 0, padding: 0, margin: '0 0 8px' }}>
        <legend style={{ ...LABEL_STYLE, padding: 0 }}>How will you attend?</legend>
        <RadioRow name={`${id}-attend`} value="In person"
          checked={form.attend === 'In person'} onChange={set('attend')}
          label={`In person at ${event.venue}`}
          detail={`${event.street} · meet in the foyer at ${event.arrivalTime}`} />
        <RadioRow name={`${id}-attend`} value="Online"
          checked={form.attend === 'Online'} onChange={set('attend')}
          label="Online via Zoom"
          detail="Link sent after registration" />
        <FieldError id={`${id}-attend-error`} message={errors.attend} />
      </fieldset>

      <hr style={{ border: 0, borderTop: '1px solid var(--colour-divider)', margin: '26px 0 26px' }} />

      {status === 'failed' && (
        <div role="alert" style={{
          background: 'var(--colour-mid)',
          borderLeft: '3px solid var(--colour-navy)',
          borderRadius: '0 var(--radius-card) var(--radius-card) 0',
          padding: '14px 16px', margin: '0 0 22px',
          fontSize: 15, lineHeight: 1.6, color: 'var(--colour-ink)',
        }}>
          <strong>We could not save that registration.</strong> {failMessage} Please try again, or
          email <a href="mailto:info@scn2aaustralia.org" style={{ color: 'var(--colour-ink)' }}>info@scn2aaustralia.org</a> and
          we will add you by hand.
        </div>
      )}

      <Button type="submit" size="lg" variant="mulberry">
        {status === 'sending' ? 'Registering…' : 'Register'}
      </Button>
      <p aria-live="polite" style={{ minHeight: 18, fontSize: 14, color: 'var(--colour-muted)', margin: '10px 0 0' }}>
        {status === 'sending' ? 'Sending your registration…' : ''}
      </p>

      <p style={{ fontSize: 14, lineHeight: 1.6, color: 'var(--colour-muted)', margin: '18px 0 0' }}>
        Registrations close {auDate(event.registrationsClose)}. We use your details only to run this
        session and will not share them with third parties.
      </p>
    </form>
  );
}

Object.assign(window, { EventRegistrationForm, FLOREY_ASO_EVENT });

// The event's own page at /florey-aso-update: summary, arrival instructions
// and the form. Removes itself the day after the event (the router falls
// back to home for unknown routes, so the link never 404s).
function FloreyASORegistrationPage({ navigate }) {
  const ev = FLOREY_ASO_EVENT;
  const over = new Date() > new Date(ev.date + 'T23:59:59+10:00');
  return (
    <div data-screen-label="Florey ASO update">
      <PageHero
        eyebrow="Community event · SCN2A and SLC6A1 families"
        title="Florey ASO update."
        body="Hear directly from the Florey team on where the antisense oligonucleotide (ASO) work is up to for SCN2A and SLC6A1, and put your questions to the researchers. Come to Parkville or join on Zoom."
        kicker={`${auDate(ev.date)}, ${ev.startTime} · ${ev.venue}, Parkville, or online via Zoom`}
        navigate={navigate}
      />
      <Breadcrumbs items={[{ label: 'Get Involved', to: 'involved' }, { label: 'Florey ASO update' }]} navigate={navigate} />

      <section style={{ background: 'var(--colour-canvas)', padding: '72px 0 96px' }}>
        <div className="container pad-mobile">
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.3fr', gap: 48, alignItems: 'start' }} className="stack-mobile">
            <div style={{ maxWidth: 480 }}>
              <div className="eyebrow" style={{ color: 'var(--colour-ink)' }}>The details</div>
              <h2 className="h2-mobile" style={{
                fontSize: 'clamp(26px, 3vw, 34px)', fontWeight: 700, color: 'var(--colour-ink)',
                margin: '14px 0 16px', lineHeight: 1.15, letterSpacing: '-0.01em',
              }}>
                When, where and how to find us.
              </h2>
              <hr className="rule-teal" />
              <dl style={{ margin: '26px 0 0', display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '12px 18px', fontSize: 16, lineHeight: 1.55 }}>
                <dt style={{ fontWeight: 700, color: 'var(--colour-ink)' }}>When</dt>
                <dd style={{ margin: 0, color: 'var(--colour-muted)' }}>{auDate(ev.date)}, {ev.startTime}</dd>
                <dt style={{ fontWeight: 700, color: 'var(--colour-ink)' }}>Where</dt>
                <dd style={{ margin: 0, color: 'var(--colour-muted)' }}>
                  {ev.venue}, <a href={ev.mapUrl} target="_blank" rel="noopener" style={{ color: 'inherit' }}>{ev.address}</a>
                  <br />or online via Zoom
                </dd>
                <dt style={{ fontWeight: 700, color: 'var(--colour-ink)' }}>Arrive</dt>
                <dd style={{ margin: 0, color: 'var(--colour-ink)', fontWeight: 600 }}>
                  Arrive at {ev.arrivalTime}. The Florey team will meet you in the lobby.
                </dd>
                <dt style={{ fontWeight: 700, color: 'var(--colour-ink)' }}>Cost</dt>
                <dd style={{ margin: 0, color: 'var(--colour-muted)' }}>Free. Registration is required so the building has a list of names.</dd>
              </dl>
              <p style={{ fontSize: 15, lineHeight: 1.6, color: 'var(--colour-muted)', margin: '26px 0 0' }}>
                Questions about the session? Email <a href="mailto:info@scn2aaustralia.org" style={{ color: 'var(--colour-ink)' }}>info@scn2aaustralia.org</a>.
              </p>
            </div>

            {over ? (
              <div style={{ background: '#fff', border: '1px solid var(--colour-divider)', borderRadius: 'var(--radius-card)', padding: '32px 26px' }}>
                <h2 style={{ fontSize: 22, fontWeight: 700, color: 'var(--colour-ink)', margin: '0 0 10px' }}>This event has been held.</h2>
                <p style={{ fontSize: 16, lineHeight: 1.6, color: 'var(--colour-muted)', margin: 0 }}>
                  Thank you to everyone who came along or joined online. Keep an eye on our news page for what came out of it.
                </p>
              </div>
            ) : (
              <EventRegistrationForm />
            )}
          </div>
        </div>
      </section>
    </div>
  );
}

Object.assign(window, { FloreyASORegistrationPage });
