import { Check, CircleAlert } from 'lucide-preact';

/**
 * Piezas comunes de las preguntas del recorrido. Usan las clases que el sitio ya
 * tiene (form de /estimate y layout):
 * - Eyebrow con las mismas clases que `x-home.section-header`.
 * - Opciones con `.btn-choice` / `.btn-choice-stacked` (radios ocultos,
 *   `has-[:checked]` pinta la elegida).
 * - Botones con `.btn` + `.btn-primary` / `.btn-muted`.
 */

/**
 * El encabezado de una pregunta. El título recibe el foco cuando la pregunta pasa
 * a ser la activa (`tabIndex=-1`), así el lector de pantalla la anuncia.
 *
 * `meta` completa el eyebrow (ej. «Step 3 of 7» dentro del bloque de un área):
 * sin `meta` no lleva raya, para que no quede colgando.
 *
 * @param {{ eyebrow?: string, meta?: string, title: string, hint?: string, headingRef?: any, id: string }} props
 */
export function QuestionHeader({ eyebrow, meta, title, hint, headingRef, id }) {
  return (
    <header>
      {eyebrow && (
        <p class="text-xs font-semibold tracking-[0.22em] text-muted uppercase">
          {eyebrow}
          {meta && <span class="text-muted-2"> — {meta}</span>}
        </p>
      )}
      <h2
        id={id}
        ref={headingRef}
        tabIndex={-1}
        class="mt-3 font-serif text-[1.8rem] leading-tight text-fg outline-none sm:text-[2rem]"
      >
        {title}
      </h2>
      {hint && <p class="mt-3 max-w-xl text-base leading-relaxed font-light text-muted">{hint}</p>}
    </header>
  );
}

/**
 * Lo que falta en esta pregunta (skill progressive-survey: la explicación va en
 * la pregunta, además del punto rojo).
 *
 * @param {{ message: string | null | undefined }} props
 */
export function QuestionError({ message }) {
  if (!message) return null;
  return (
    <p role="alert" class="mt-4 flex items-start gap-2 text-sm text-red-400">
      <CircleAlert class="mt-0.5 size-4 flex-none" aria-hidden="true" />
      {message}
    </p>
  );
}

/**
 * @typedef {object} Choice
 * @property {string} value
 * @property {string} label
 * @property {string} [description]
 * @property {string | null} [image]
 * @property {any} [Icon] Componente de ícono (opciones `segmented`).
 */

/** Cómo se acomodan las opciones según el tipo de pregunta. */
const LAYOUTS = {
  // Tarjetas con foto (`radio-card`, servicios): 3 por fila con lugar, 2 en la
  // columna angosta (40% de preguntas con una foto horizontal).
  cards: 'mt-8 grid grid-cols-2 gap-3 @xl:grid-cols-3',
  // Opciones con texto y, a veces, aclaración (`radio`, «¿mismo diseño?», toggles).
  list: 'mt-8 grid grid-cols-1 gap-2.5 sm:grid-cols-2',
  // Muchas opciones cortas (los `select` del catálogo): chips compactos. Flex que
  // envuelve (no grilla fija): cada chip mide al menos su texto en una línea.
  chips: 'mt-8 flex flex-wrap gap-2',
  // Pocas opciones lado a lado, con ícono (`segmented`): mismo criterio.
  segmented: 'mt-8 flex flex-wrap gap-2',
};

/**
 * Cada opción de chips y segmented: el texto nunca se parte (una opción de dos
 * líneas quedaba más alta que las demás). Crece para llenar la fila y, si no
 * entra, pasa entera a la siguiente; `min-w-fit` evita que se achique por debajo
 * de su texto.
 */
const ITEMS = {
  chips: 'min-w-fit grow basis-36 whitespace-nowrap px-3 py-2',
  segmented: 'min-w-fit grow basis-0 flex-col gap-1.5 whitespace-nowrap py-3',
};

/**
 * Opciones de respuesta única. `onPick(value, byPointer)`: `byPointer` es `true`
 * cuando se eligió con un clic o un toque (el recorrido avanza solo), y `false`
 * con el teclado (las flechas cambian la selección sin avanzar; se confirma con
 * Continue).
 *
 * @param {{
 *   name: string,
 *   labelledBy: string,
 *   options: Choice[],
 *   value: string | null | undefined,
 *   onPick: (value: string, byPointer: boolean) => void,
 *   variant?: keyof typeof LAYOUTS,
 * }} props
 */
export function ChoiceList({ name, labelledBy, options, value, onPick, variant }) {
  const layout = variant ?? (options.some((option) => option.image) ? 'cards' : 'list');
  const cards = layout === 'cards';

  return (
    <div role="radiogroup" aria-labelledby={labelledBy} class={LAYOUTS[layout]}>
      {options.map((option) => {
        const selected = value === option.value;
        return (
          <label
            key={option.value}
            class={`btn-choice relative ${ITEMS[layout] ?? 'btn-choice-stacked'} ${
              cards ? 'p-2' : ''
            }`}
            onClick={(event) => {
              // El clic del label llega con `detail > 0`; Espacio sobre el radio, no.
              if (event.detail > 0) onPick(option.value, true);
            }}
          >
            <input
              type="radio"
              name={name}
              value={option.value}
              checked={selected}
              onChange={() => onPick(option.value, false)}
              class="sr-only"
            />
            {option.image && (
              <img
                src={option.image}
                alt=""
                loading="lazy"
                decoding="async"
                class="mb-2 aspect-4/3 w-full rounded-md object-cover"
              />
            )}
            {option.Icon && <option.Icon class="size-7" />}
            <span class={cards ? 'px-1 pb-1' : ''}>{option.label}</span>
            {option.description && (
              <span class={`text-xs text-muted ${cards ? 'px-1 pb-1' : ''}`}>
                {option.description}
              </span>
            )}
            {selected && cards && (
              <span
                aria-hidden="true"
                class="absolute top-3 right-3 flex size-6 items-center justify-center rounded-full bg-brand text-surface shadow-md"
              >
                <Check class="size-3.5" strokeWidth={3} />
              </span>
            )}
          </label>
        );
      })}
    </div>
  );
}

/**
 * La barra de acciones de una pregunta.
 *
 * @param {{ children: any }} props
 */
export function QuestionActions({ children }) {
  return <div class="mt-10 flex flex-wrap items-center gap-3">{children}</div>;
}
