// Pure helpers for the in-game "check a word" panel: input sanitising and the gate on
// when a check may be sent. Kept separate from Game.svelte so the constraints (the
// variant alphabet, the length bounds, the answered-word cache and the cool-down
// throttle) are unit-testable and stay in lockstep with the UI.

import type { Variant } from './model';

/** The longest word that fits on a standard 15-cell board line. */
export const MAX_WORD_LEN = 15;
/** The shortest word worth checking. */
export const MIN_WORD_LEN = 2;

/**
 * sanitizeCheckWord upper-cases the raw input and keeps only characters of the active
 * variant's alphabet, capped at MAX_WORD_LEN — so the field can never hold something the
 * dictionary could not contain.
 */
export function sanitizeCheckWord(raw: string, alphabet: string[]): string {
  const allowed = new Set(alphabet);
  return Array.from(raw.toUpperCase())
    .filter((ch) => allowed.has(ch))
    .slice(0, MAX_WORD_LEN)
    .join('');
}

/**
 * canCheckWord gates the Check action: the trimmed word must be of valid length, must not
 * have been answered already (cached), and must not fall inside the cool-down window.
 */
export function canCheckWord(word: string, alreadyChecked: boolean, cooling: boolean): boolean {
  const w = word.trim();
  return w.length >= MIN_WORD_LEN && w.length <= MAX_WORD_LEN && !alreadyChecked && !cooling;
}

/**
 * dictionaryLookupUrl returns the external reference-dictionary search URL for a checked word
 * in the given variant: gramota.ru for the Russian variants (scrabble_ru, erudit_ru) and
 * scrabblewordfinder.org for English. The word is lower-cased and percent-encoded, so a
 * Cyrillic query travels safely.
 */
export function dictionaryLookupUrl(word: string, variant: Variant): string {
  const w = encodeURIComponent(word.toLowerCase());
  return variant.endsWith('_ru')
    ? `https://gramota.ru/poisk?query=${w}`
    : `https://scrabblewordfinder.org/dictionary/${w}`;
}
