<?php
declare(strict_types=1);

if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}

$isPreview = (int)($_GET['preview'] ?? 0) === 1;

if ($isPreview) {
    $teacherLoggedIn = !empty($_SESSION['user_id'])
        && in_array(
            (string)($_SESSION['user_role'] ?? ''),
            ['teacher', 'admin'],
            true
        );

    if (!$teacherLoggedIn) {
        $_SESSION['teacher_return_url'] =
            (string)($_SERVER['REQUEST_URI'] ?? '');
        header('Location: ../teacher/login.php');
        exit;
    }
} elseif (empty($_SESSION['student_id'])) {
    $_SESSION['student_return_url'] =
        (string)($_SERVER['REQUEST_URI'] ?? '');
    header('Location: student-login.php');
    exit;
}

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../includes/student_activity_navigation.php';

$pdo = getDbConnection();

$bookSlug = trim((string)($_GET['book'] ?? ''));
$levelSlug = trim((string)($_GET['level'] ?? ''));
$levelId = max(0, (int)($_GET['level_id'] ?? 0));
$unitId = max(0, (int)($_GET['unit_id'] ?? ($_GET['id'] ?? 0)));
$lessonId = max(0, (int)($_GET['lesson_id'] ?? 0));
$activityId = max(
    0,
    (int)($_GET['activity_id'] ?? ($_GET['activity'] ?? 0))
);

if (
    $bookSlug === ''
    || $levelId <= 0
    || $unitId <= 0
    || $lessonId <= 0
    || $activityId <= 0
) {
    header('Location: student-learning.php');
    exit;
}

function vocabGameColumns(PDO $pdo, string $table): array
{
    $stmt = $pdo->prepare(
        "SELECT COUNT(*)
         FROM information_schema.TABLES
         WHERE TABLE_SCHEMA = DATABASE()
           AND TABLE_NAME = ?"
    );
    $stmt->execute([$table]);

    if ((int)$stmt->fetchColumn() === 0) {
        return [];
    }

    $rows = $pdo
        ->query("SHOW COLUMNS FROM `{$table}`")
        ->fetchAll(PDO::FETCH_ASSOC);

    return array_column($rows, null, 'Field');
}

function vocabGameAssetUrl(string $path): string
{
    $path = trim($path);

    if ($path === '') {
        return '';
    }

    if (
        str_starts_with($path, 'http://')
        || str_starts_with($path, 'https://')
        || str_starts_with($path, 'data:')
        || str_starts_with($path, '/')
    ) {
        return $path;
    }

    return '/EnglishSpeak/' . ltrim($path, './');
}

function vocabGameFirstColumn(array $columns, array $candidates): ?string
{
    foreach ($candidates as $candidate) {
        if (isset($columns[$candidate])) {
            return $candidate;
        }
    }

    return null;
}

$activityColumns = vocabGameColumns($pdo, 'activities');
$relationColumns = vocabGameColumns($pdo, 'flashcard_set_words');
$wordColumns = vocabGameColumns($pdo, 'words');

if (
    $activityColumns === []
    || $relationColumns === []
    || $wordColumns === []
) {
    http_response_code(500);
    exit('Thiếu bảng dữ liệu game từ vựng.');
}

$activityTitleColumn = vocabGameFirstColumn(
    $activityColumns,
    ['title', 'name']
);

$activitySetColumn = vocabGameFirstColumn(
    $activityColumns,
    ['flashcard_set_id', 'set_id']
);

$setFk = vocabGameFirstColumn(
    $relationColumns,
    ['set_id', 'flashcard_set_id']
);

$wordFk = vocabGameFirstColumn(
    $relationColumns,
    ['word_id', 'item_id']
);

$orderColumn = vocabGameFirstColumn(
    $relationColumns,
    ['order_no', 'sort_order', 'position', 'id']
) ?? 'id';

$wordTextColumn = vocabGameFirstColumn(
    $wordColumns,
    ['word', 'english_word', 'term', 'title', 'name']
);

$imageColumn = vocabGameFirstColumn(
    $wordColumns,
    ['image_path', 'image', 'image_url', 'picture_path']
);

$audioColumn = vocabGameFirstColumn(
    $wordColumns,
    ['audio_us_path', 'audio_path', 'audio', 'audio_url']
);

if (
    $activityTitleColumn === null
    || $activitySetColumn === null
    || $setFk === null
    || $wordFk === null
    || $wordTextColumn === null
) {
    http_response_code(500);
    exit('Cấu trúc dữ liệu game từ vựng chưa đầy đủ.');
}

$activityStatusWhere = isset($activityColumns['status'])
    ? "AND a.status = 'active'"
    : '';

$contextStmt = $pdo->prepare(
    "SELECT
        a.id AS activity_id,
        a.`{$activitySetColumn}` AS flashcard_set_id,
        "
        . (
            isset($activityColumns['xp_reward'])
                ? 'a.xp_reward'
                : '10 AS xp_reward'
        )
        . ",
        a.`{$activityTitleColumn}` AS activity_title,

        le.id AS lesson_id,
        le.lesson_number,
        le.title AS lesson_title,

        u.id AS unit_id,
        u.unit_number,
        u.title AS unit_title,

        l.id AS level_id,
        l.name AS level_name,
        l.slug AS level_slug,

        b.id AS book_id,
        b.name AS book_name,
        b.slug AS book_slug
     FROM activities a
     INNER JOIN lessons le
        ON le.id = a.lesson_id
     INNER JOIN units u
        ON u.id = le.unit_id
     INNER JOIN levels l
        ON l.id = u.level_id
     INNER JOIN books b
        ON b.id = l.book_id
     WHERE a.id = ?
       AND le.id = ?
       AND u.id = ?
       AND l.id = ?
       AND b.slug = ?
       {$activityStatusWhere}
     LIMIT 1"
);
$contextStmt->execute([
    $activityId,
    $lessonId,
    $unitId,
    $levelId,
    $bookSlug,
]);
$activity = $contextStmt->fetch(PDO::FETCH_ASSOC);

if (!$activity) {
    http_response_code(404);
    exit('Không tìm thấy hoạt động trong cấp độ đã chọn.');
}

$runtimeSettings = [
    'word_count' => 8,
    'show_image' => true,
    'letter_voice' => true,
    'passing_score' => 80,
];

if (vocabGameColumns($pdo, 'activity_settings') !== []) {
    $settingsStmt = $pdo->prepare(
        'SELECT settings_json
         FROM activity_settings
         WHERE activity_id = ?
         LIMIT 1'
    );
    $settingsStmt->execute([$activityId]);
    $settingsJson = $settingsStmt->fetchColumn();

    if (is_string($settingsJson) && $settingsJson !== '') {
        $decoded = json_decode($settingsJson, true);

        if (is_array($decoded)) {
            $runtimeSettings['word_count'] = max(
                1,
                min(20, (int)($decoded['word_count'] ?? 8))
            );
            $runtimeSettings['show_image'] = filter_var(
                $decoded['show_image'] ?? true,
                FILTER_VALIDATE_BOOL
            );
            $runtimeSettings['letter_voice'] = filter_var(
                $decoded['letter_voice'] ?? true,
                FILTER_VALIDATE_BOOL
            );
            $runtimeSettings['passing_score'] = max(
                0,
                min(100, (int)($decoded['passing_score'] ?? 80))
            );

            /*
             * Game từ vựng lấy Flashcard Set từ Activity Settings
             * khi activities.flashcard_set_id chưa được gán trực tiếp.
             */
            $resourceType = trim((string)($decoded['resource_type'] ?? ''));
            $resourceId = max(0, (int)($decoded['resource_id'] ?? 0));

            if (
                (int)($activity['flashcard_set_id'] ?? 0) <= 0
                && $resourceType === 'flashcard_set'
                && $resourceId > 0
            ) {
                $activity['flashcard_set_id'] = $resourceId;
            }
        }
    }
}

$imageSelect = $imageColumn !== null
    ? "w.`{$imageColumn}` AS image_path"
    : "'' AS image_path";

$audioSelect = $audioColumn !== null
    ? "w.`{$audioColumn}` AS audio_path"
    : "'' AS audio_path";

$wordStatusWhere = isset($wordColumns['status'])
    ? "AND w.status = 'active'"
    : '';

$wordStmt = $pdo->prepare(
    "SELECT
        w.id,
        w.`{$wordTextColumn}` AS word_text,
        {$imageSelect},
        {$audioSelect},
        fsw.`{$orderColumn}` AS display_order
     FROM flashcard_set_words fsw
     INNER JOIN words w
        ON w.id = fsw.`{$wordFk}`
     WHERE fsw.`{$setFk}` = ?
       {$wordStatusWhere}
     ORDER BY fsw.`{$orderColumn}` ASC, fsw.id ASC
     LIMIT " . (int)$runtimeSettings['word_count']
);
$wordStmt->execute([
    (int)$activity['flashcard_set_id'],
]);

$rows = $wordStmt->fetchAll(PDO::FETCH_ASSOC);

$cards = [];

foreach ($rows as $row) {
    $word = strtoupper(
        preg_replace(
            '/[^A-Za-z]/',
            '',
            (string)($row['word_text'] ?? '')
        )
    );

    if ($word === '') {
        continue;
    }

    $cards[] = [
        'word' => $word,
        'display_word' => trim((string)($row['word_text'] ?? '')),
        'image' => vocabGameAssetUrl((string)($row['image_path'] ?? '')),
        'audio' => vocabGameAssetUrl((string)($row['audio_path'] ?? '')),
    ];
}

$rawUnitNumber = trim((string)$activity['unit_number']);
$rawLessonNumber = trim((string)$activity['lesson_number']);

$displayUnitNumber = preg_match('/(\d+)/', $rawUnitNumber, $unitMatch)
    ? (int)$unitMatch[1]
    : $rawUnitNumber;

$displayLessonNumber = preg_match('/(\d+)/', $rawLessonNumber, $lessonMatch)
    ? (int)$lessonMatch[1]
    : $rawLessonNumber;

$backUrl = $isPreview
    ? '../teacher/activity-preview/index.php?activity_id=' . (int)$activityId
    : 'student-activities.php?' . http_build_query([
        'book' => (string)$activity['book_slug'],
        'level' => (string)$activity['level_slug'],
        'level_id' => (int)$activity['level_id'],
        'unit_id' => (int)$activity['unit_id'],
        'lesson_id' => (int)$activity['lesson_id'],
        'lesson' => $displayLessonNumber,
    ]);

/*
 * Nút Tiếp tục chỉ điều hướng.
 * Helper chung đọc activities.sort_order trong đúng Lesson hiện tại.
 */
$nextActivityUrl = englishSpeakGetNextActivityUrl($pdo, $activityId);

if ($isPreview && str_contains($nextActivityUrl, 'student-runtime/index.php')) {
    $nextActivityUrl .= (str_contains($nextActivityUrl, '?') ? '&' : '?') . 'preview=1';
}

$_SESSION['last_learning_url'] =
    (string)($_SERVER['REQUEST_URI'] ?? '');
?>
<!doctype html><html lang="vi"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><title>Find the Word | EnglishSpeak</title>

<style>
:root{--blue:#198fe3;--blue-dark:#0868c7;--page:#f4f8fc;--text:#15314b;--muted:#718399;--line:#dfe8f0;--green:#26a65b;--orange:#f39c12;--width:520px;--shadow:0 7px 22px rgba(31,71,108,.10)}
*{box-sizing:border-box} html,body{margin:0;min-height:100%;background:var(--page);color:var(--text);font-family:"Segoe UI",Tahoma,Arial,sans-serif}
body{display:flex;justify-content:center} button,a{font:inherit;-webkit-tap-highlight-color:transparent}
.app{width:min(100%,var(--width));min-height:100dvh;padding:0 13px 24px;background:#fff;box-shadow:0 0 28px rgba(30,79,115,.08)}
.topbar{position:sticky;top:0;z-index:40;display:grid;grid-template-columns:46px minmax(0,1fr) 46px;align-items:center;gap:9px;min-height:76px;margin:0 -13px 14px;padding:12px 13px;background:linear-gradient(135deg,#3488ef,#17b8e4);color:#fff;box-shadow:0 5px 15px rgba(31,135,210,.22)}
.round{display:grid;width:44px;height:44px;place-items:center;border:0;border-radius:50%;background:rgba(255,255,255,.15);color:#fff;text-decoration:none;font-size:24px;font-weight:850}
.heading{text-align:center;min-width:0}.heading strong{display:block;font-size:22px}.heading small{display:block;margin-top:4px;color:rgba(255,255,255,.92);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lesson{display:grid;grid-template-columns:52px minmax(0,1fr);align-items:center;gap:11px;min-height:72px;margin-bottom:12px;padding:12px 14px;border-radius:20px;background:linear-gradient(135deg,#edf6ff,#e6f1ff)}
.lesson__icon{width:48px;height:48px;display:grid;place-items:center;border-radius:14px;background:#fff;font-size:29px}.lesson strong{font-size:18px}
.progress-row{display:flex;justify-content:space-between;gap:10px;color:#38536c;font-size:13px;font-weight:800}.track{height:9px;margin:8px 0 13px;overflow:hidden;border-radius:999px;background:#dceaf5}.fill{width:0;height:100%;border-radius:inherit;background:linear-gradient(90deg,#1c7ce4,#18a9e7);transition:width .2s}
.game-card{min-height:calc(100dvh - 292px);padding:15px;border:1px solid #e2eaf1;border-radius:22px;background:#fff;box-shadow:var(--shadow);display:flex;flex-direction:column;align-items:center}
.image-box{width:100%;height:min(30dvh,235px);min-height:170px;display:grid;place-items:center;padding:16px;border:0;border-radius:18px;background:#fbfdff}
.image-box img{max-width:260px;max-height:225px;width:90%;height:90%;object-fit:contain}.fallback{font-size:96px}
.feedback{display:none;width:100%;margin-top:14px;padding:13px 14px;border-radius:15px;font-weight:850;text-align:center}.feedback.show{display:block}.feedback.good{border:1px solid #bce5c8;background:#eefbf2;color:#19783a}.feedback.try{border:1px solid #f0d7a5;background:#fff8e8;color:#8a5c08}
.next-row{display:none;width:100%;margin-top:12px}.next-row.show{display:grid}.next{height:52px;border:0;border-radius:15px;background:var(--blue);color:#fff;font-weight:850;cursor:pointer}
.finish{display:none;min-height:calc(100dvh - 110px);padding:38px 18px;align-items:center;justify-content:center;flex-direction:column;text-align:center}.finish.show{display:flex}.finish__icon{font-size:76px}.finish h2{margin:14px 0 8px;font-size:40px;color:#123e62}.finish p{margin:0;color:var(--muted)}
.summary{width:100%;margin-top:22px;padding:5px 17px;border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow)}.summary-row{display:flex;justify-content:space-between;align-items:center;min-height:58px;border-bottom:1px solid #e5ecf2}.summary-row:last-child{border:0}.summary-row strong{color:var(--blue-dark);font-size:19px}
.finish-actions{display:grid;gap:10px;width:100%;margin-top:18px}.finish-actions button,.finish-actions a{min-height:54px;display:grid;place-items:center;border:1px solid var(--blue);border-radius:15px;background:#fff;color:var(--blue-dark);text-decoration:none;font-weight:850}.finish-actions .primary{background:var(--blue);color:#fff}
.preview-banner{margin:10px 0;padding:9px 12px;border:1px solid #bfdbfe;border-radius:13px;background:#eff6ff;color:#1d4ed8;text-align:center;font-size:13px;font-weight:800}.empty{padding:50px 20px;text-align:center}
.xp-popup{position:fixed;z-index:10000;inset:0;display:none;align-items:center;justify-content:center;padding:20px;background:rgba(18,49,74,.38);backdrop-filter:blur(5px)}.xp-popup.show{display:flex}
.xp-popup__card{width:min(100%,350px);padding:24px 20px 20px;border-radius:24px;background:#fff;box-shadow:0 18px 50px rgba(18,49,74,.24);text-align:center}.xp-popup__icon{width:76px;height:76px;display:grid;place-items:center;margin:0 auto 10px;border-radius:50%;background:linear-gradient(135deg,#fff6bf,#ffe06e);font-size:42px}
.xp-popup__title{margin:0;color:#15314b;font-size:27px}.xp-popup__text{margin:7px 0 0;color:#718399;font-size:14px}.xp-popup__score{margin:17px 0;color:#f39c12;font-size:36px;font-weight:900}.xp-popup__button{width:100%;min-height:52px;border:0;border-radius:15px;background:linear-gradient(135deg,#237fe1,#159ddd);color:#fff;font-weight:850;cursor:pointer}
@media(max-width:390px){.app{padding-left:10px;padding-right:10px}.topbar{margin-left:-10px;margin-right:-10px;padding-left:10px;padding-right:10px}.game-card{padding:12px}}
</style>

<style>
.word-options{display:grid;grid-template-columns:1fr 1fr;gap:12px;width:100%;margin-top:18px}
.word-option{min-height:58px;padding:10px 12px;border:1px solid #bfd4e4;border-radius:15px;background:#fff;color:var(--blue-dark);font-size:18px;font-weight:900;cursor:pointer;transition:.18s}
.word-option:active{transform:scale(.98)}.word-option.wrong{opacity:0;transform:scale(.82);pointer-events:none}.word-option.correct{border-color:#73d094;background:#eefbf2;color:#16823b}
@media(max-width:390px){.word-options{grid-template-columns:1fr}.word-option{min-height:52px}}
</style>
</head><body><main class="app">
<?php if ($isPreview): ?><div class="preview-banner">Preview mode — Không lưu XP hoặc tiến trình học sinh.</div><?php endif; ?>
<header class="topbar"><a class="round" href="<?= htmlspecialchars($backUrl, ENT_QUOTES, 'UTF-8') ?>">←</a><div class="heading"><strong>Unit <?= $displayUnitNumber ?></strong><small><?= htmlspecialchars((string)$activity['unit_title'], ENT_QUOTES, 'UTF-8') ?></small></div><span class="round" style="visibility:hidden"></span></header>
<?php if ($cards === []): ?><section class="empty"><h2>Chưa có từ vựng</h2><p>Hãy liên kết Flashcard Set trong Activity Settings.</p></section>
<?php else: ?>
<section id="gameScreen"><div class="lesson"><div class="lesson__icon">🖼️</div><strong>Find the Word</strong></div><div class="progress-row"><span id="progressLabel"></span><span></span></div><div class="track"><div class="fill" id="progressFill"></div></div>
<section class="game-card"><div class="image-box"><img id="wordImage" alt="" hidden><span class="fallback" id="fallback">🖼️</span></div><div class="word-options" id="wordOptions"></div><div class="feedback" id="feedback"></div><div class="next-row" id="nextRow"><button class="next" id="nextButton">Next →</button></div></section></section>

<section class="finish" id="finishScreen">
<div class="finish__icon">🎉</div><h2 id="finishTitle">Great!</h2><p id="finishSubtitle">All done!</p>
<div class="summary"><div class="summary-row"><span>Done</span><strong><?= count($cards) ?>/<?= count($cards) ?></strong></div><div class="summary-row"><span>Score</span><strong id="finalScore">0/100</strong></div><div class="summary-row"><span>Pass</span><strong id="finalPass">No</strong></div><div class="summary-row"><span>Time</span><strong id="finalTime">00:00</strong></div></div>
<p id="finishMessage" style="margin-top:14px;font-weight:800;color:#38536c"></p>
<div class="finish-actions"><a class="primary" id="continueButton" style="display:none" href="<?= htmlspecialchars($nextActivityUrl, ENT_QUOTES, 'UTF-8') ?>">➡ Next</a><button id="againButton" type="button">↻ Again</button><a href="<?= htmlspecialchars($backUrl, ENT_QUOTES, 'UTF-8') ?>">← Back</a></div>
</section>
<div class="xp-popup" id="xpPopup"><div class="xp-popup__card"><div class="xp-popup__icon">⭐</div><h2 class="xp-popup__title" id="xpPopupTitle">Great!</h2><p class="xp-popup__text" id="xpPopupText"></p><div class="xp-popup__score" id="xpPopupScore"></div><button class="xp-popup__button" id="xpPopupButton" type="button">Xem kết quả</button></div></div>

<?php endif; ?></main>
<?php if ($cards !== []): ?><script>

function $(id){return document.getElementById(id)}
const cards=<?= json_encode($cards, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) ?>;
const settings=<?= json_encode($runtimeSettings, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) ?>;
const activityId=<?= (int)$activityId ?>; const isPreview=<?= $isPreview ? 'true' : 'false' ?>;
let currentIndex=0,totalPoints=0,startedAt=Date.now(),saving=false,solved=false;
function shuffle(items){const a=[...items];for(let i=a.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[a[i],a[j]]=[a[j],a[i]]}return a}
let currentAudio=null;
function playTone(kind){
  try{
    const Ctx=window.AudioContext||window.webkitAudioContext;
    if(!Ctx)return;
    const ctx=new Ctx(),osc=ctx.createOscillator(),gain=ctx.createGain();
    osc.connect(gain);gain.connect(ctx.destination);
    const now=ctx.currentTime;
    if(kind==='good'){
      osc.type='sine';osc.frequency.setValueAtTime(660,now);osc.frequency.setValueAtTime(880,now+.09);
      gain.gain.setValueAtTime(.10,now);gain.gain.exponentialRampToValueAtTime(.001,now+.22);
      osc.start(now);osc.stop(now+.22);
    }else if(kind==='try'){
      osc.type='sine';osc.frequency.setValueAtTime(260,now);
      gain.gain.setValueAtTime(.045,now);gain.gain.exponentialRampToValueAtTime(.001,now+.12);
      osc.start(now);osc.stop(now+.12);
    }else{
      osc.type='sine';osc.frequency.setValueAtTime(523,now);osc.frequency.setValueAtTime(659,now+.10);osc.frequency.setValueAtTime(784,now+.20);
      gain.gain.setValueAtTime(.09,now);gain.gain.exponentialRampToValueAtTime(.001,now+.34);
      osc.start(now);osc.stop(now+.34);
    }
  }catch(e){}
}
function playWordAudio(card){
  const src=String(card?.audio||'').trim();
  if(!src)return;
  try{
    if(currentAudio){currentAudio.pause();currentAudio=null}
    currentAudio=new Audio(src);
    currentAudio.volume=.9;
    currentAudio.play().catch(()=>{});
  }catch(e){}
}
function formatDuration(ms){const s=Math.max(0,Math.round(ms/1000));return `${String(Math.floor(s/60)).padStart(2,'0')}:${String(s%60).padStart(2,'0')}`}
function scoreForMistakes(n){return n<=0?100:n===1?75:n===2?50:25}
function showFeedback(type,msg){const el=$('feedback');el.className=`feedback show ${type}`;el.textContent=msg}
function clearFeedback(){const el=$('feedback');el.className='feedback';el.textContent=''}
function progress(){ $('progressLabel').textContent=`${currentIndex+1} / ${cards.length}`; $('progressFill').style.width=`${((currentIndex+1)/cards.length)*100}%` }
function renderImage(card){const img=$('wordImage'),fb=$('fallback');if(card.image){img.src=card.image;img.hidden=false;fb.hidden=true}else{img.hidden=true;fb.hidden=false}}
function getScore(){return cards.length?Math.round(totalPoints/cards.length):0}
async function saveProgress(score,elapsed){
 if(isPreview||saving)return null;saving=true;
 try{const r=await fetch('/EnglishSpeak/api/save-activity-progress.php',{method:'POST',credentials:'same-origin',cache:'no-store',headers:{'Content-Type':'application/json','Accept':'application/json'},body:JSON.stringify({activity_id:activityId,score,duration:elapsed,completed:score>=Number(settings.passing_score||80),passing_score:Number(settings.passing_score||80),preview:false})});const result=await r.json().catch(()=>null);if(!r.ok||!result||result.ok===false)throw new Error(result?.message||'Could not save progress.');return result.data||result}catch(e){console.warn('Could not save progress:',e);return null}finally{saving=false}
}
function showXpResult(result,score){if(isPreview||!result)return;const xp=Number(result.xp_added||0);$('xpPopupTitle').textContent='Great!';$('xpPopupScore').textContent=xp>0?`+${xp} XP`:`${score}%`;$('xpPopupText').textContent='';playTone('finish');$('xpPopup').classList.add('show')}
$('xpPopupButton')?.addEventListener('click',()=> $('xpPopup').classList.remove('show'));
async function finishGame(){const score=getScore(),elapsed=Date.now()-startedAt,passed=score>=Number(settings.passing_score||80);$('finalScore').textContent=`${score}/100`;$('finalPass').textContent=passed?'Yes':'No';$('finalTime').textContent=formatDuration(elapsed);$('continueButton').style.display=passed?'grid':'none';if(score>=90){$('finishTitle').textContent='Great!';$('finishSubtitle').textContent='All done!';$('finishMessage').textContent=''}else if(passed){$('finishTitle').textContent='Good job!';$('finishSubtitle').textContent='Practice complete.';$('finishMessage').textContent='Nice work!'}else{$('finishTitle').textContent='Keep going!';$('finishSubtitle').textContent='Try again.';$('finishMessage').textContent='You can do it!'}$('gameScreen').style.display='none';$('finishScreen').classList.add('show');showXpResult(await saveProgress(score,elapsed),score)}
function goNext(){if(currentIndex<cards.length-1){currentIndex++;renderCard()}else{finishGame()}}
$('nextButton')?.addEventListener('click',goNext);
$('againButton')?.addEventListener('click',()=>{currentIndex=0;totalPoints=0;startedAt=Date.now();saving=false;solved=false;$('finishScreen').classList.remove('show');$('gameScreen').style.display='block';renderCard()});

let mistakesThisWord=0;
function renderCard(){solved=false;mistakesThisWord=0;clearFeedback();$('nextRow').classList.remove('show');const card=cards[currentIndex];renderImage(card);progress();playWordAudio(card);const pool=cards.filter((_,i)=>i!==currentIndex);const distractors=shuffle(pool).slice(0,3).map(x=>x.display_word);const options=shuffle([card.display_word,...distractors]);const box=$('wordOptions');box.innerHTML='';options.forEach(word=>{const b=document.createElement('button');b.type='button';b.className='word-option';b.textContent=word;b.addEventListener('click',()=>chooseWord(b,word,card.display_word));box.appendChild(b)})}
function chooseWord(button,chosen,correct){if(solved)return;if(chosen===correct){solved=true;button.classList.add('correct');totalPoints+=scoreForMistakes(mistakesThisWord);playTone('good');showFeedback('good','Great!');$('nextRow').classList.add('show')}else{mistakesThisWord++;button.classList.add('wrong');playTone('try');showFeedback('try','Try again!')}}
renderCard();
</script><?php endif; ?></body></html>
