/* ===================================================================
   GAME 03 — CRAWL-DLE  (DCC-themed Wordle)
   Six guesses, five letters. The answer is drawn from the DCC word
   bank in games-data.js. Any five-letter guess is accepted (no
   dictionary gate, so proper nouns are fair game). The result screen
   reveals the word's DCC significance as a payoff. window.CrawldleGame
   =================================================================== */
const { useState: useStateCw, useEffect: useEffectCw, useRef: useRefCw } = React;
const GCW = window.DCC_GAMES;

const CWL_ROWS = 6;     // guesses
const CWL_LEN  = 5;     // letters
const KB_ROWS  = ['QWERTYUIOP', 'ASDFGHJKL', 'ZXCVBNM'];

/* Standard Wordle two-pass scoring — handles duplicate letters correctly. */
function scoreGuess(guess, target){
  const res = Array(CWL_LEN).fill('absent');
  const t = target.split('');
  for (let i = 0; i < CWL_LEN; i++){              // pass 1: exact hits
    if (guess[i] === t[i]){ res[i] = 'correct'; t[i] = null; }
  }
  for (let i = 0; i < CWL_LEN; i++){              // pass 2: present elsewhere
    if (res[i] === 'correct') continue;
    const j = t.indexOf(guess[i]);
    if (j !== -1){ res[i] = 'present'; t[j] = null; }
  }
  return res;
}

/* Best-known status per letter, for coloring the on-screen keyboard. */
const CWL_RANK = { absent:0, present:1, correct:2 };
function mergeKeyStatus(map, guess, score){
  const next = Object.assign({}, map);
  for (let i = 0; i < CWL_LEN; i++){
    const k = guess[i], s = score[i];
    if (!next[k] || CWL_RANK[s] > CWL_RANK[next[k]]) next[k] = s;
  }
  return next;
}

function CrawldleGame({ go, toHub }){
  const [phase, setPhase]         = useStateCw('intro');  // intro | play | done
  const [target, setTarget]       = useStateCw(null);     // { word, hint, tag }
  const [guesses, setGuesses]     = useStateCw([]);        // [{ word, score }]
  const [current, setCurrent]     = useStateCw('');
  const [keyStatus, setKeyStatus] = useStateCw({});
  const [won, setWon]             = useStateCw(false);
  const [toast, setToast]         = useStateCw('');
  const [shake, setShake]         = useStateCw(false);
  const [copied, share]           = window.useShare();
  const toastRef = useRefCw(null);
  const keyHandlerRef = useRefCw(()=>{});

  function flashToast(msg){
    setToast(msg); setShake(true);
    clearTimeout(toastRef.current);
    toastRef.current = setTimeout(()=>{ setToast(''); setShake(false); }, 1100);
  }

  function start(){
    setTarget(GCW.pickCrawldle());
    setGuesses([]); setCurrent(''); setKeyStatus({});
    setWon(false); setToast(''); setShake(false);
    setPhase('play');
  }

  function submit(){
    if (current.length < CWL_LEN){ flashToast(`Need ${CWL_LEN} letters, crawler.`); return; }
    const guess = current.toUpperCase();
    const score = scoreGuess(guess, target.word);
    const nextGuesses = guesses.concat([{ word: guess, score }]);
    setGuesses(nextGuesses);
    setKeyStatus(mergeKeyStatus(keyStatus, guess, score));
    setCurrent('');
    if (guess === target.word){ setWon(true); setTimeout(()=>setPhase('done'), 540); }
    else if (nextGuesses.length >= CWL_ROWS){ setWon(false); setTimeout(()=>setPhase('done'), 540); }
  }

  function onKey(k){
    if (phase !== 'play') return;
    if (k === 'ENTER'){ submit(); return; }
    if (k === 'DEL'){ setCurrent(c => c.slice(0, -1)); return; }
    if (/^[A-Z]$/.test(k)) setCurrent(c => (c.length < CWL_LEN ? c + k : c));
  }
  keyHandlerRef.current = onKey;  // keep the listener pointed at the latest closure

  /* physical keyboard — subscribe once, delegate through the ref */
  useEffectCw(() => {
    function handler(e){
      if (e.metaKey || e.ctrlKey || e.altKey) return;
      let k = e.key;
      if (k === 'Enter') k = 'ENTER';
      else if (k === 'Backspace') k = 'DEL';
      else if (/^[a-zA-Z]$/.test(k)) k = k.toUpperCase();
      else return;
      e.preventDefault();
      keyHandlerRef.current(k);
    }
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, []);
  useEffectCw(() => () => clearTimeout(toastRef.current), []);

  function shareResult(){
    const head = `Crawl-dle ${won ? guesses.length : 'X'}/${CWL_ROWS}`;
    const grid = guesses.map(g =>
      g.score.map(s => s === 'correct' ? '🟩' : (s === 'present' ? '🟨' : '⬛')).join('')
    ).join('\n');
    share(`${head}\n\n${grid}\n\n— System AI's Unofficial DCC Index · The Arcade`);
  }

  /* ---------------- INTRO ---------------- */
  let body;
  if (phase === 'intro'){
    body = (
      <div className="gstep">
        <div className="gintro-h">Crawl<span className="em">-dle</span></div>
        <div className="gintro-sub">Decode the System's word.</div>
        <window.SysCard from="System // Crawl-dle">
          I'm thinking of a five-letter word, crawler, pulled from the dungeon's lexicon: a name, a place, a piece
          of the show. You get <b>six</b> guesses. After each, every letter lights up
          <b style={{color:'var(--rar-uncommon)'}}> green</b> in the right spot,
          <b style={{color:'var(--rar-legend)'}}> gold</b> if it's in the word elsewhere, and gray if it isn't in the
          word at all. Any five-letter word is a valid guess. Crack it and I'll tell you what it means.
        </window.SysCard>
        <div className="gintro-rules">
          <div className="gintro-rule"><span className="rn">01</span><span>Type with your keyboard or tap the keys below. <b>Enter</b> submits, <b>⌫</b> deletes.</span></div>
          <div className="gintro-rule"><span className="rn">02</span><span>Green = right letter, right place. Gold = right letter, wrong place. Gray = not in the word.</span></div>
          <div className="gintro-rule"><span className="rn">03</span><span>Six tries, no daily streak, no saves. A fresh word every single run.</span></div>
        </div>
        <div className="gnext-wrap">
          <button className="btn" style={{borderColor:'var(--t-lootbox)',background:'var(--t-lootbox)'}} onClick={start}>Begin decode ▸</button>
        </div>
      </div>
    );
  }

  /* ---------------- PLAY / DONE (board is shown in both) ---------------- */
  else {
    const rows = [];
    for (let r = 0; r < CWL_ROWS; r++){
      let letters, statuses;
      if (r < guesses.length){ letters = guesses[r].word.split(''); statuses = guesses[r].score; }
      else if (r === guesses.length && phase === 'play'){ letters = current.padEnd(CWL_LEN, ' ').split(''); statuses = null; }
      else { letters = '     '.split(''); statuses = null; }
      const isActive = r === guesses.length && phase === 'play';
      rows.push(
        <div className={'cwl-row'+(isActive && shake ? ' shake' : '')} key={r}>
          {Array.from({length:CWL_LEN}).map((_,c)=>{
            const ch = letters[c] && letters[c] !== ' ' ? letters[c] : '';
            const st = statuses ? statuses[c] : '';
            const cls = 'cwl-tile' + (st ? ' '+st : (ch ? ' filled' : ''));
            const style = st ? {animationDelay:`${c*90}ms`} : null;
            return <div key={c} className={cls} style={style}>{ch}</div>;
          })}
        </div>
      );
    }

    const result = phase === 'done' && (
      <div className="cwl-result" style={{['--cwl-rc']: won ? 'var(--rar-uncommon)' : 'var(--warn)'}}>
        <div className="cwl-verdict">{won ? '✓ Word decoded' : '▓ Signal lost'}</div>
        <div className="cwl-rline">
          {won
            ? `Cracked in ${guesses.length} of ${CWL_ROWS}. The System logs a quiet, grudging respect.`
            : `Out of guesses, crawler. The word held. Better luck on the next broadcast.`}
        </div>
        <div className="cwl-answer">{target.word}</div>
        <div className="cwl-tag">{target.tag}</div>
        <p className="cwl-hint">{target.hint}</p>
      </div>
    );

    body = (
      <div className="gstep">
        <div className="cwl-board-wrap">
          {toast && <div className="cwl-toast">{toast}</div>}
          <div className="cwl-grid">{rows}</div>
        </div>

        {phase === 'play' && (
          <div className="cwl-kbd">
            {KB_ROWS.map((row, ri) => (
              <div className="cwl-krow" key={ri}>
                {ri === 2 && <button className="cwl-key wide" onClick={()=>onKey('ENTER')}>Enter</button>}
                {row.split('').map(k => (
                  <button key={k} className={'cwl-key'+(keyStatus[k] ? ' '+keyStatus[k] : '')} onClick={()=>onKey(k)}>{k}</button>
                ))}
                {ri === 2 && <button className="cwl-key wide" onClick={()=>onKey('DEL')}>⌫</button>}
              </div>
            ))}
          </div>
        )}

        {result}

        {phase === 'done' && (
          <React.Fragment>
            <div className="gactions">
              <button className="btn" style={{borderColor:'var(--t-lootbox)',background:'var(--t-lootbox)'}} onClick={start}>↻ New word</button>
              <button className="btn amber" onClick={shareResult}>⧉ Transmit result</button>
              <button className="btn ghost" onClick={toHub}>Back to Arcade</button>
            </div>
            <div className="gshare-note" style={{opacity: copied?1:0}}>✓ Result copied to clipboard. Paste it anywhere.</div>
            <div className="gmeta-foot">No streaks, no leaderboard, nothing the System has to honor tomorrow. Every word lands fresh, like the last one never happened.</div>
          </React.Fragment>
        )}
      </div>
    );
  }

  return (
    <div className="view"><div className="wrap">
      <div className="crumbs">
        <a onClick={()=>go({view:'home'})}>Home</a><span className="sep">/</span>
        <a onClick={toHub}>Arcade</a><span className="sep">/</span>
        <span style={{color:'var(--ink)'}}>Crawl-dle</span>
      </div>
      <window.GameStage accent={window.ACCENTS.crawldle} title="Crawl-dle · Word Decode" onExit={toHub}>
        {body}
      </window.GameStage>
    </div></div>
  );
}
window.CrawldleGame = CrawldleGame;
