<?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/sentence_image_resolver.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 swbColumns(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 swbAssetUrl(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 swbFirstColumn(array $columns, array $candidates): ?string
{
    foreach ($candidates as $candidate) {
        if (isset($columns[$candidate])) {
            return $candidate;
        }
    }

    return null;
}

$activityColumns = swbColumns($pdo, 'activities');
$sentenceSetColumns = swbColumns($pdo, 'sentence_sets');
$sentenceColumns = swbColumns($pdo, 'sentences');

$relationTable = '';
foreach (['sentence_set_sentences', 'sentence_set_items'] as $candidateTable) {
    if (swbColumns($pdo, $candidateTable) !== []) {
        $relationTable = $candidateTable;
        break;
    }
}

$relationColumns = $relationTable !== ''
    ? swbColumns($pdo, $relationTable)
    : [];

if ($activityColumns === []) {
    http_response_code(500);
    exit('Thiếu bảng dữ liệu Sentence Builder.');
}

$activityTitleColumn = isset($activityColumns['title'])
    ? 'title'
    : (isset($activityColumns['name']) ? 'name' : null);

if ($activityTitleColumn === null) {
    http_response_code(500);
    exit('Cấu trúc Activity chưa đầy đủ.');
}

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

$sentenceSetIdSelect = isset($activityColumns['sentence_set_id'])
    ? 'a.sentence_set_id AS sentence_set_id,'
    : '0 AS sentence_set_id,';

$contextStmt = $pdo->prepare(
    "SELECT
        a.id AS activity_id,
        {$sentenceSetIdSelect}
        "
        . (
            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 Sentence Builder trong cấp độ đã chọn.');
}

/*
 * Sentence Set lấy đúng theo Speaking Sentences:
 * 1. activities.sentence_set_id
 * 2. activity_settings.settings_json.resource_id khi resource_type = sentence_set
 */
$sentenceSetId = max(0, (int)($activity['sentence_set_id'] ?? 0));

$activitySettings = [];

if (swbColumns($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 !== '') {
        $decodedSettings = json_decode($settingsJson, true);

        if (is_array($decodedSettings)) {
            $activitySettings = $decodedSettings;

            if ($sentenceSetId <= 0) {
                $resourceType = trim(
                    (string)($decodedSettings['resource_type'] ?? '')
                );
                $resourceId = max(
                    0,
                    (int)($decodedSettings['resource_id'] ?? 0)
                );

                if (
                    $resourceType === 'sentence_set'
                    && $resourceId > 0
                ) {
                    $sentenceSetId = $resourceId;
                }
            }
        }
    }
}

$runtimeSettings = [
    'sentence_count' => max(
        1,
        min(
            100,
            (int)(
                $activitySettings['sentences_per_session']
                ?? $activitySettings['sentence_count']
                ?? $activitySettings['items_per_session']
                ?? 10
            )
        )
    ),
    'show_image' => filter_var(
        $activitySettings['show_image'] ?? true,
        FILTER_VALIDATE_BOOL
    ),
    'passing_score' => max(
        0,
        min(100, (int)($activitySettings['passing_score'] ?? 80))
    ),
];

/*
 * Dùng đúng cấu trúc bảng/cột của Speaking Sentences.
 */
$cards = [];

if (
    $sentenceSetId > 0
    && $sentenceColumns !== []
    && $relationColumns !== []
    && $relationTable !== ''
) {
    $setFk = isset($relationColumns['set_id'])
        ? 'set_id'
        : (isset($relationColumns['sentence_set_id'])
            ? 'sentence_set_id'
            : null);

    $sentenceFk = isset($relationColumns['sentence_id'])
        ? 'sentence_id'
        : (isset($relationColumns['item_id'])
            ? 'item_id'
            : null);

    $orderColumn = isset($relationColumns['order_no'])
        ? 'order_no'
        : (isset($relationColumns['sort_order'])
            ? 'sort_order'
            : (isset($relationColumns['position'])
                ? 'position'
                : 'id'));

    $sentenceTextColumn = isset($sentenceColumns['sentence_text'])
        ? 'sentence_text'
        : (isset($sentenceColumns['sentence'])
            ? 'sentence'
            : (isset($sentenceColumns['text'])
                ? 'text'
                : (isset($sentenceColumns['content'])
                    ? 'content'
                    : null)));

    $imageColumn = isset($sentenceColumns['image_path'])
        ? 'image_path'
        : (isset($sentenceColumns['image'])
            ? 'image'
            : null);

    $audioColumn = isset($sentenceColumns['audio_us_path'])
        ? 'audio_us_path'
        : (isset($sentenceColumns['audio_path'])
            ? 'audio_path'
            : (isset($sentenceColumns['audio'])
                ? 'audio'
                : null));

    if (
        $setFk !== null
        && $sentenceFk !== null
        && $sentenceTextColumn !== null
    ) {
        $imageSelect = $imageColumn !== null
            ? "s.`{$imageColumn}` AS image_path"
            : "'' AS image_path";

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

        $sentenceStatusWhere = isset($sentenceColumns['status'])
            ? "AND s.status = 'active'"
            : '';

        $sentenceStmt = $pdo->prepare(
            "SELECT
                s.id,
                s.`{$sentenceTextColumn}` AS sentence_text,
                {$imageSelect},
                {$audioSelect},
                rel.`{$orderColumn}` AS display_order
             FROM `{$relationTable}` rel
             INNER JOIN sentences s
                ON s.id = rel.`{$sentenceFk}`
             WHERE rel.`{$setFk}` = ?
               {$sentenceStatusWhere}
             ORDER BY rel.`{$orderColumn}` ASC, rel.id ASC"
        );

        $sentenceStmt->execute([$sentenceSetId]);

        foreach ($sentenceStmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $sentence = trim(
                (string)($row['sentence_text'] ?? '')
            );

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

            $tokens = preg_split('/\s+/u', $sentence) ?: [];
            $tokens = array_values(
                array_filter(
                    array_map(
                        static fn(string $token): string =>
                            trim(
                                $token,
                                " \t\n\r\0\x0B.,!?;:\"'“”‘’()[]{}"
                            ),
                        $tokens
                    ),
                    static fn(string $token): bool => $token !== ''
                )
            );

            if ($tokens === []) {
                continue;
            }

            $resolvedImage = esResolveSentenceImage(
                $pdo,
                $sentence,
                (string)($row['image_path'] ?? '')
            );

            $cards[] = [
                'sentence' => $sentence,
                'tokens' => $tokens,
                'image' => (string)($resolvedImage['url'] ?? ''),
                'audio' => swbAssetUrl(
                    (string)($row['audio_path'] ?? '')
                ),
            ];
        }
    }
}

/* Giới hạn số câu theo Activity Settings. */
$sentenceLimit = (int)($runtimeSettings['sentence_count'] ?? 10);

if (
    $sentenceLimit > 0
    && $sentenceLimit < 100
    && count($cards) > $sentenceLimit
) {
    $cards = array_slice($cards, 0, $sentenceLimit);
}

$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>Sentence Builder | 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(28dvh,225px);min-height:160px;display:grid;place-items:center;padding:18px;border:0;border-radius:18px;background:#fbfdff;cursor:pointer}
.image-box img{max-width:250px;max-height:220px;width:88%;height:88%;object-fit:contain}.fallback{font-size:96px}
.answer{display:flex;justify-content:center;flex-wrap:wrap;gap:8px;min-height:64px;margin-top:14px}
.slot{min-width:72px;min-height:52px;padding:0 14px;display:grid;place-items:center;border:2px solid #cfe0ec;border-radius:13px;background:#fff;color:var(--blue-dark);font-size:20px;font-weight:900}
.letters{display:flex;justify-content:center;flex-wrap:wrap;gap:16px;width:100%;margin-top:18px}
.letter{min-width:72px;height:52px;padding:0 14px;border:1px solid #bcd4e5;border-radius:14px;background:#fff;color:var(--blue-dark);font-size:18px;font-weight:900;box-shadow:0 4px 12px rgba(32,88,128,.08);cursor:pointer;transition:.16s}
.letter:active{transform:scale(1.08)}.letter.used{opacity:.28;pointer-events:none}
.letter.locked{opacity:.22;pointer-events:none}
.slot.correct{border-color:#77d59a;background:#eefbf2;color:#16823b;animation:slotSuccess .35s ease}
@keyframes slotSuccess{0%{transform:scale(.96)}60%{transform:scale(1.08)}100%{transform:scale(1)}}
.controls{display:grid;grid-template-columns:1fr 1fr;gap:10px;width:100%;margin-top:auto;padding-top:20px}
.controls-single{display:flex;justify-content:center;}
.controls-single .control{width:48%;max-width:220px;}
.control{height:52px;border:1px solid #cbddeb;border-radius:15px;background:#fff;color:var(--text);font-weight:850;cursor:pointer}.control.primary{border-color:var(--blue);background:var(--blue);color:#fff}
.feedback{display:none;width:100%;margin-top:12px;padding:13px 14px;border-radius:15px;font-weight:800;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:10px}.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}
@media(max-width:390px){.app{padding-left:10px;padding-right:10px}.topbar{margin-left:-10px;margin-right:-10px;padding-left:10px;padding-right:10px}.slot{width:40px;height:49px;font-size:24px}.letter{min-width:47px;height:49px;font-size:22px}.game-card{padding:12px}}

.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;line-height:1.2}
.xp-popup__text{margin:7px 0 0;color:#718399;font-size:14px;line-height:1.5}
.xp-popup__score{margin:17px 0;color:#f39c12;font-size:36px;font-weight:900;line-height:1}
.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}

</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') ?>" aria-label="Quay lại">←</a>
  <div class="heading">
    <strong>Unit <?= $displayUnitNumber ?></strong>
    <small><?= htmlspecialchars((string)$activity['unit_title'], ENT_QUOTES, 'UTF-8') ?></small>
  </div>
  <span class="round" aria-hidden="true" style="visibility:hidden"></span>
</header>

<?php if ($cards === []): ?>
<section class="empty">
  <h2>Chưa có câu</h2>
  <p>Hãy liên kết Sentence Set trong Activity Settings.</p>
</section>
<?php else: ?>
<section id="gameScreen">
  <div class="lesson">
    <div class="lesson__icon">🧱</div>
    <strong>Sentence Builder</strong>
  </div>

  <div class="progress-row">
    <span id="progressLabel">1 / <?= count($cards) ?></span>
    <span id="scoreLabel"></span>
  </div>
  <div class="track"><div class="fill" id="progressFill"></div></div>

  <section class="game-card">
    <button class="image-box" id="imageButton" type="button" aria-label="Nghe câu" <?= !$runtimeSettings['show_image'] ? 'hidden' : '' ?>>
      <img id="wordImage" alt="" hidden>
      <span class="fallback" id="fallback">💬</span>
    </button>

    <p style="margin:12px 0 8px;color:#718399;font-size:13px;font-weight:750;text-align:center">
      Chạm vào các từ để sắp xếp thành câu.
    </p>

    <div class="answer" id="answerSlots" aria-label="Câu trả lời"></div>
    <div class="letters" id="letterBank" aria-label="Các từ"></div>

   

    <div class="feedback" id="feedback" aria-live="polite"></div>

    <div class="next-row" id="nextRow">
      <button class="next" id="nextButton" type="button">Tiếp theo →</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 class="primary" id="againButton" type="button">↻ Again</button>
    <a href="<?= htmlspecialchars($backUrl, ENT_QUOTES, 'UTF-8') ?>">← Back</a>
  </div>
</section>
<?php endif; ?>
</main>


<div class="xp-popup" id="xpPopup" role="dialog" aria-modal="true" aria-labelledby="xpPopupTitle">
  <div class="xp-popup__card">
    <div class="xp-popup__icon" aria-hidden="true">⭐</div>
    <h2 class="xp-popup__title" id="xpPopupTitle">Great!</h2>
    <p class="xp-popup__text" id="xpPopupText">You earned</p>
    <div class="xp-popup__score" id="xpPopupScore"></div>
    <button class="xp-popup__button" id="xpPopupButton" type="button">HIện kết quả</button>
  </div>
</div>

<?php if ($cards !== []): ?>
<script>
'use strict';

const isPreview = <?= $isPreview ? 'true' : 'false' ?>;
const activityId = <?= (int)$activityId ?>;
const settings = <?= json_encode(
    $runtimeSettings,
    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
) ?>;
const cards = <?= json_encode(
    $cards,
    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
) ?>;

const $ = id => document.getElementById(id);

const gameScreen = $('gameScreen');
const finishScreen = $('finishScreen');
const wordImage = $('wordImage');
const fallback = $('fallback');
const answerSlots = $('answerSlots');
const letterBank = $('letterBank');
const progressLabel = $('progressLabel');
const progressFill = $('progressFill');
const feedback = $('feedback');
const nextRow = $('nextRow');
const finalScore = $('finalScore');
const finalPass = $('finalPass');
const finalTime = $('finalTime');
const finishTitle = $('finishTitle');
const finishSubtitle = $('finishSubtitle');
const finishMessage = $('finishMessage');
const xpPopup = $('xpPopup');
const xpPopupTitle = $('xpPopupTitle');
const xpPopupText = $('xpPopupText');
const xpPopupScore = $('xpPopupScore');
const xpPopupButton = $('xpPopupButton');
const continueButton = $('continueButton');

let currentIndex = 0;
let currentLetters = [];
let chosenLetters = [];
let correctCount = 0;
let mistakes = 0;
let startedAt = Date.now();
let saving = false;
let wordAudioTimer = null;
let autoNextTimer = null;
let wordCompleted = false;

function shuffle(items) {
    const copy = [...items];

    for (let i = copy.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [copy[i], copy[j]] = [copy[j], copy[i]];
    }

    return copy;
}

function speakText(text, rate = 0.82) {
    if (!('speechSynthesis' in window)) {
        return;
    }

    window.speechSynthesis.cancel();

    const utterance = new SpeechSynthesisUtterance(text);
    utterance.lang = 'en-US';
    utterance.rate = rate;
    utterance.pitch = 1;

    window.speechSynthesis.speak(utterance);
}

function playSentence(card) {
    if (card.audio) {
        const audio = new Audio(card.audio);
        audio.play().catch(() => speakText(card.sentence));
        return;
    }

    speakText(card.sentence);
}

function clearFeedback() {
    feedback.className = 'feedback';
    feedback.textContent = '';
}

function showFeedback(type, message) {
    feedback.className = `feedback show ${type}`;
    feedback.textContent = message;
}

function renderSlots() {
    answerSlots.innerHTML = '';

    chosenLetters.forEach((item, index) => {
        const slot = document.createElement('button');
        slot.type = 'button';
        slot.className = 'slot';
        slot.textContent = item.word;
        slot.disabled = wordCompleted;

        if (!wordCompleted) {
            slot.addEventListener('click', () => removeChosen(index));
        }

        if (wordCompleted) {
            slot.classList.add('correct');
        }

        answerSlots.appendChild(slot);
    });
}

function renderWords() {
    letterBank.innerHTML = '';

    currentLetters.forEach((item, index) => {
        const button = document.createElement('button');
        button.type = 'button';
        button.className = 'letter';
        button.textContent = item.word;

        if (item.used) {
            button.classList.add('used');
        }

        if (wordCompleted) {
            button.classList.add('locked');
            button.disabled = true;
        }

        button.addEventListener('click', () => chooseWord(index));
        letterBank.appendChild(button);
    });
}

function chooseWord(index) {
    if (wordCompleted) {
        return;
    }

    const item = currentLetters[index];

    if (!item || item.used) {
        return;
    }

    // Đọc chính từ học sinh vừa chạm vào.
    speakText(item.word, 0.78);

    item.used = true;
    chosenLetters.push({
        word: item.word,
        sourceIndex: index
    });

    renderSlots();
    renderWords();

    if (chosenLetters.length === cards[currentIndex].tokens.length) {
        checkAnswer();
    }
}

function removeChosen(index) {
    if (wordCompleted) {
        return;
    }

    const chosen = chosenLetters[index];

    if (!chosen) {
        return;
    }

    // Khi chạm từ đã chọn để trả lại, vẫn đọc lại từ đó.
    speakText(chosen.word, 0.78);

    currentLetters[chosen.sourceIndex].used = false;
    chosenLetters.splice(index, 1);

    clearFeedback();
    nextRow.classList.remove('show');
    renderSlots();
    renderWords();
}

function normalizeToken(value) {
    return String(value || '')
        .toLocaleLowerCase('en-US')
        .replace(/[.,!?;:"'“”‘’()[\]{}]/g, '')
        .trim();
}

function checkAnswer() {
    const card = cards[currentIndex];
    const answer = chosenLetters.map(item => normalizeToken(item.word));
    const target = card.tokens.map(normalizeToken);

    const isCorrect =
        answer.length === target.length
        && answer.every((word, index) => word === target[index]);

    if (isCorrect) {
        correctCount++;
        wordCompleted = true;
        renderSlots();
        renderWords();

        setTimeout(() => {
            
            nextRow.classList.add('show');
        }, 250);

        if (wordAudioTimer) {
            clearTimeout(wordAudioTimer);
        }
        if (autoNextTimer) {
            clearTimeout(autoNextTimer);
        }

        wordAudioTimer = setTimeout(() => {
            playSentence(card);
            wordAudioTimer = null;
        }, 800);

        autoNextTimer = setTimeout(() => {
            autoNextTimer = null;
            goNext();
        }, 3000);

        return;
    }

    mistakes++;
    showFeedback('try', 'Chạm vào một từ để đổi lại.');
}

function renderCard() {
    if (wordAudioTimer) {
        clearTimeout(wordAudioTimer);
        wordAudioTimer = null;
    }
    if (autoNextTimer) {
        clearTimeout(autoNextTimer);
        autoNextTimer = null;
    }

    wordCompleted = false;
    const card = cards[currentIndex];

    chosenLetters = [];
    currentLetters = shuffle(
        card.tokens.map((word, index) => ({
            id: `${index}-${word}`,
            word,
            used: false
        }))
    );

    if (
        currentLetters.length > 1
        && currentLetters.map(item => normalizeToken(item.word)).join('|')
            === card.tokens.map(normalizeToken).join('|')
    ) {
        [currentLetters[0], currentLetters[1]] =
            [currentLetters[1], currentLetters[0]];
    }

    if (card.image) {
        wordImage.src = card.image;
        wordImage.alt = card.sentence;
        wordImage.hidden = false;
        fallback.hidden = true;
    } else {
        wordImage.hidden = true;
        fallback.hidden = false;
    }

    progressLabel.textContent =
        `${currentIndex + 1} / ${cards.length}`;

    progressFill.style.width =
        `${((currentIndex + 1) / cards.length) * 100}%`;

    clearFeedback();
    nextRow.classList.remove('show');
    renderSlots();
    renderWords();
}

function getScore() {
    if (cards.length === 0) {
        return 0;
    }

    const base = Math.round(
        (correctCount / cards.length) * 100
    );

    const penalty = Math.min(
        30,
        mistakes * 5
    );

    const score = base - penalty;

    return Math.min(
        100,
        Math.max(0, score)
    );
}

function formatDuration(milliseconds) {
    const totalSeconds = Math.max(
        0,
        Math.round(milliseconds / 1000)
    );
    const minutes = String(
        Math.floor(totalSeconds / 60)
    ).padStart(2, '0');
    const seconds = String(
        totalSeconds % 60
    ).padStart(2, '0');

    return `${minutes}:${seconds}`;
}

async function saveProgress(score, elapsed) {
    if (isPreview || saving) {
        return null;
    }

    saving = true;

    try {
        const response = 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: true,
                    passing_score: Number(
                        settings.passing_score || 80
                    ),
                    preview: false
                })
            }
        );

        const result = await response.json().catch(() => null);

        if (!response.ok || !result || result.ok === false) {
            throw new Error(
                result?.message || 'Could not save progress.'
            );
        }

        return result.data || result;
    } catch (error) {
        console.warn(
            'Could not save Sentence Builder progress:',
            error
        );
        return null;
    } finally {
        saving = false;
    }
}

function showXpResult(result) {
    if (isPreview || !result || !xpPopup) {
        return;
    }

    const xpAdded = Number(result.xp_added || 0);
    const eventType = String(result.xp_event_type || '');

    xpPopupTitle.textContent = 'Great!';

    if (xpAdded > 0) {
        xpPopupScore.textContent = `+${xpAdded} XP`;

        if (eventType === 'completion') {
            xpPopupText.textContent = 'Completion Reward';
        } else if (eventType === 'new_best') {
            xpPopupText.textContent = 'New Best Reward';
        } else {
            xpPopupText.textContent = 'Practice Reward';
        }
    } else {
        const score = getScore();
        xpPopupTitle.textContent = score >= Number(settings.passing_score || 80)
            ? 'Great!'
            : '😊 Good effort!';
        xpPopupScore.textContent = `${score}%`;
        xpPopupText.textContent = score >= Number(settings.passing_score || 80)
            ? ''
            : 'Em chưa đạt mức yêu cầu. Hãy thử lại nhé.';
    }

    xpPopup.classList.add('show');
}

function hideXpResult() {
    xpPopup?.classList.remove('show');
}

async function finishGame() {
    const score = getScore();
    const elapsed = Date.now() - startedAt;
    const passed =
        score >= Number(settings.passing_score || 80);

    finalScore.textContent = `${score}/100`;
    finalPass.textContent = passed ? 'Yes' : 'No';
    finalTime.textContent = formatDuration(elapsed);

    if (continueButton) {
        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');

    const progressResult = await saveProgress(score, elapsed);
    showXpResult(progressResult);
}

xpPopupButton?.addEventListener('click', hideXpResult);

$('resetButton')?.addEventListener('click', () => {
    clearFeedback();
    nextRow.classList.remove('show');
    renderCard();
});

function goNext() {
    if (wordAudioTimer) {
        clearTimeout(wordAudioTimer);
        wordAudioTimer = null;
    }
    if (autoNextTimer) {
        clearTimeout(autoNextTimer);
        autoNextTimer = null;
    }

    if (currentIndex < cards.length - 1) {
        currentIndex++;
        renderCard();
        return;
    }

    finishGame();
}

$('nextButton')?.addEventListener('click', goNext);

$('againButton')?.addEventListener('click', () => {
    hideXpResult();
    currentIndex = 0;
    correctCount = 0;
    mistakes = 0;
    startedAt = Date.now();
    saving = false;

    finishScreen.classList.remove('show');
    gameScreen.style.display = 'block';
    renderCard();
});

renderCard();
</script>
<?php endif; ?>
</body>
</html>
