import { useCallback, useEffect, useId, useRef, type KeyboardEvent } from 'react';

import {
  THEME_AUSWAHLEN,
  THEME_BESCHRIFTUNGEN,
  THEME_ERLAEUTERUNGEN,
  type ThemeAuswahl,
} from '../../../shared/theme';

export interface ThemaWahlProps {
  readonly auswahl: ThemeAuswahl;
  readonly onAuswahl: (auswahl: ThemeAuswahl) => void;
  /** ID der Überschrift, die die Gruppe benennt. */
  readonly beschriftetVon: string;
}

/**
 * Theme-Umschalter als echte Radiogruppe nach den ARIA Authoring Practices.
 *
 * Tastaturbedienung (APG „Radio Group – roving tabindex“):
 *   Tab / Shift+Tab  betritt bzw. verlässt die Gruppe als Ganzes
 *   Pfeil rechts/ab  nächste Option (mit Umbruch), wird sofort ausgewählt
 *   Pfeil links/auf  vorige Option (mit Umbruch), wird sofort ausgewählt
 *   Pos1 / Ende      erste bzw. letzte Option
 *   Leertaste        wählt die fokussierte Option
 *
 * Nur die aktive Option hat `tabindex="0"`; alle anderen `tabindex="-1"`.
 */
export function ThemaWahl({
  auswahl,
  onAuswahl,
  beschriftetVon,
}: ThemaWahlProps): React.JSX.Element {
  const hinweisId = useId();
  const optionRefs = useRef<(HTMLButtonElement | null)[]>([]);
  /** Fokus nur nach Tastaturnavigation setzen, nicht bei jedem Render. */
  const fokusAufIndex = useRef<number | null>(null);

  const aktiverIndex = Math.max(0, THEME_AUSWAHLEN.indexOf(auswahl));

  useEffect(() => {
    const index = fokusAufIndex.current;
    if (index !== null) {
      fokusAufIndex.current = null;
      optionRefs.current[index]?.focus();
    }
  });

  const zuIndexWechseln = useCallback(
    (index: number) => {
      const anzahl = THEME_AUSWAHLEN.length;
      const normiert = ((index % anzahl) + anzahl) % anzahl;
      const ziel = THEME_AUSWAHLEN[normiert];
      if (!ziel) {
        return;
      }
      fokusAufIndex.current = normiert;
      onAuswahl(ziel);
    },
    [onAuswahl],
  );

  const beiTaste = useCallback(
    (ereignis: KeyboardEvent<HTMLButtonElement>, index: number) => {
      switch (ereignis.key) {
        case 'ArrowRight':
        case 'ArrowDown':
          ereignis.preventDefault();
          zuIndexWechseln(index + 1);
          break;
        case 'ArrowLeft':
        case 'ArrowUp':
          ereignis.preventDefault();
          zuIndexWechseln(index - 1);
          break;
        case 'Home':
          ereignis.preventDefault();
          zuIndexWechseln(0);
          break;
        case 'End':
          ereignis.preventDefault();
          zuIndexWechseln(THEME_AUSWAHLEN.length - 1);
          break;
        case ' ':
        case 'Spacebar':
          ereignis.preventDefault();
          zuIndexWechseln(index);
          break;
        default:
          break;
      }
    },
    [zuIndexWechseln],
  );

  return (
    <>
      <div
        role="radiogroup"
        aria-labelledby={beschriftetVon}
        aria-describedby={hinweisId}
        className="themawahl__optionen"
      >
        {THEME_AUSWAHLEN.map((option, index) => {
          const gewaehlt = option === auswahl;
          return (
            <button
              key={option}
              type="button"
              role="radio"
              aria-checked={gewaehlt}
              tabIndex={index === aktiverIndex ? 0 : -1}
              className="themawahl__option"
              ref={(element) => {
                optionRefs.current[index] = element;
              }}
              onClick={() => {
                onAuswahl(option);
              }}
              onKeyDown={(ereignis) => {
                beiTaste(ereignis, index);
              }}
            >
              {/* Zustand zusätzlich als Glyph – nicht allein über Farbe (WCAG 1.4.1). */}
              <span className="themawahl__marke" aria-hidden="true">
                {gewaehlt ? '●' : '○'}
              </span>
              {THEME_BESCHRIFTUNGEN[option]}
            </button>
          );
        })}
      </div>
      <p className="themawahl__hinweis" id={hinweisId}>
        {THEME_ERLAEUTERUNGEN[auswahl]}
      </p>
    </>
  );
}
