import { cn } from '@/lib/utils';

/**
 * A static row of scored tiles, drawn from the tile tokens.
 *
 * The landing's "the grader computes" passage needs a board fragment beside
 * it. It cannot import the word game's Surface — the site lane may never reach
 * into `src/demos/*` — and a screenshot would go stale. So this is the shape of
 * a scored row, painted with the same `--tile-*` tokens the real board uses,
 * which means it follows the theme AND the high-contrast toggle without knowing
 * either exists. It is a figure, not a game: nothing here is interactive.
 *
 * Each tile carries a second signal in high-contrast mode (● exact, ◆ present,
 * nothing for absent), exactly as the real board does, so the figure reads for
 * the same visitor the toggle exists for.
 */

export type TileState = 'exact' | 'present' | 'absent';

/** The pattern the landing caption spells out: `G Y X X G`. */
const DEFAULT_PATTERN: readonly TileState[] = ['exact', 'present', 'absent', 'absent', 'exact'];
const DEFAULT_LETTERS = 'CRANE';

const STATE_WORD: Record<TileState, string> = {
  exact: 'exact',
  present: 'present',
  absent: 'absent',
};

const TILE_CLASS: Record<TileState, string> = {
  // Glyph contrast on each fill is measured in index.css: 13.08 / 11.16 / 7.75
  // (light 5.74) in the standard palette, and ≥4.74 in high contrast.
  exact: 'border-tile-exact bg-tile-exact text-tile-exact-fg',
  present: 'border-tile-present bg-tile-present text-tile-present-fg',
  absent: 'border-tile-absent bg-tile-absent text-tile-absent-fg',
};

const GLYPH: Record<TileState, string | null> = { exact: '●', present: '◆', absent: null };

export interface TileRowProps {
  /** Five letters, one per tile. Uppercased for display. */
  letters?: string;
  /** One state per letter. Defaults to the `G Y X X G` pattern. */
  pattern?: readonly TileState[];
  className?: string;
}

export function TileRow({
  letters = DEFAULT_LETTERS,
  pattern = DEFAULT_PATTERN,
  className,
}: TileRowProps) {
  const cells = Array.from(letters.toUpperCase()).map((letter, index) => ({
    letter,
    state: pattern[index] ?? 'absent',
  }));

  // One sentence for a screen reader, instead of five unlabelled squares.
  const label = cells.map((cell) => `${cell.letter} ${STATE_WORD[cell.state]}`).join(', ');

  return (
    <div
      role="img"
      aria-label={`Scored row: ${label}.`}
      className={cn('flex w-fit gap-1 sm:gap-1.5', className)}
    >
      {cells.map((cell, index) => {
        const glyph = GLYPH[cell.state];
        return (
          <span
            key={index}
            aria-hidden="true"
            className={cn(
              // Board letters are content, not a terminal: sans 600 uppercase,
              // 22px rising to 24px from sm, the same as the real tiles.
              'relative grid size-10 place-items-center rounded-tile border-2 font-sans text-[1.375rem] font-semibold uppercase leading-none sm:size-12 sm:text-2xl',
              TILE_CLASS[cell.state],
            )}
          >
            {cell.letter}
            {glyph === null ? null : (
              <span
                className="pointer-events-none absolute bottom-0.5 right-0.5 text-[0.5em] leading-none opacity-0 [[data-contrast=high]_&]:opacity-100"
              >
                {glyph}
              </span>
            )}
          </span>
        );
      })}
    </div>
  );
}
