import { useEffect, useId, useRef, useState } from 'react';
import type { ChangeEvent, FormEvent } from 'react';

export type PracticeValues = { participant: string; seats: string };
export type PracticeErrors = Partial<Record<keyof PracticeValues, string>>;
export function validatePractice(values: PracticeValues): PracticeErrors {
  const errors: PracticeErrors = {};
  if (values.participant !== 'Sample learner') {
    errors.participant = 'Use the fictional participant Sample learner.';
  }
  if (!['1', '2', '3', '4'].includes(values.seats)) errors.seats = 'Choose 1 to 4 practice places.';
  return errors;
}

export function PracticeForm({ eventTitle = 'Garden morning' }: { eventTitle?: string }) {
  const prefix = useId();
  const [values, setValues] = useState<PracticeValues>({ participant: '', seats: '1' });
  const [errors, setErrors] = useState<PracticeErrors>({});
  const [confirmation, setConfirmation] = useState('');
  const participantRef = useRef<HTMLInputElement>(null);
  const seatsRef = useRef<HTMLSelectElement>(null);
  const [focusRequest, setFocusRequest] = useState<{ field: keyof PracticeValues } | null>(null);
  // Focus is a browser synchronization. Wait for the error description to commit.
  // The new request object also handles a repeated invalid submission.
  useEffect(() => {
    if (focusRequest?.field === 'participant') participantRef.current?.focus();
    if (focusRequest?.field === 'seats') seatsRef.current?.focus();
  }, [focusRequest]);

  function change(field: keyof PracticeValues, event: ChangeEvent<HTMLInputElement | HTMLSelectElement>) {
    const value = event.currentTarget.value;
    setValues(previous => ({ ...previous, [field]: value }));
    setErrors(previous => ({ ...previous, [field]: undefined }));
    setConfirmation('');
  }
  function submit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const nextErrors = validatePractice(values);
    setErrors(nextErrors);
    setConfirmation('');
    if (nextErrors.participant) setFocusRequest({ field: 'participant' });
    else if (nextErrors.seats) setFocusRequest({ field: 'seats' });
    else setConfirmation(`Practice complete for ${eventTitle}: ${values.seats} place(s). Nothing was sent or saved.`);
  }
  function reset() {
    setValues({ participant: '', seats: '1' });
    setFocusRequest({ field: 'participant' });
    setErrors({});
    setConfirmation('');
  }
  return <section aria-labelledby={`${prefix}-heading`} className="practice-panel">
    <h2 id={`${prefix}-heading`}>Practice a registration</h2>
    <p id={`${prefix}-help`}>Type only “Sample learner”. Do not enter real personal details.
      This form checks synthetic values on this page. It never sends or stores them.</p>
    <form noValidate onSubmit={submit} onReset={reset} aria-describedby={`${prefix}-help`}>
      <label htmlFor={`${prefix}-participant`}>Fictional participant</label>
      <input id={`${prefix}-participant`} ref={participantRef} value={values.participant}
        required autoComplete="off" maxLength={30} pattern="Sample learner"
        aria-invalid={Boolean(errors.participant)}
        aria-describedby={errors.participant ? `${prefix}-participant-error` : undefined}
        onChange={event => change('participant', event)} />
      {errors.participant && <p id={`${prefix}-participant-error`} className="error">{errors.participant}</p>}
      <label htmlFor={`${prefix}-seats`}>Practice places</label>
      <select id={`${prefix}-seats`} ref={seatsRef} value={values.seats} required
        aria-invalid={Boolean(errors.seats)}
        aria-describedby={errors.seats ? `${prefix}-seats-error` : undefined}
        onChange={event => change('seats', event)}>
        {[1, 2, 3, 4].map(number => <option key={number} value={String(number)}>{number}</option>)}
      </select>
      {errors.seats && <p id={`${prefix}-seats-error`} className="error">{errors.seats}</p>}
      <div className="actions"><button type="submit">Check practice form</button>
        <button type="reset">Reset form</button></div>
      <p role="status" aria-atomic="true">{confirmation || (Boolean(errors.participant || errors.seats) ? 'Please correct the highlighted field.' : '')}</p>
    </form>
  </section>;
}
