<?php
declare(strict_types=1);
require __DIR__ . '/../partials/auth.php';
require_once __DIR__ . '/../../config/database.php';

$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if (!$id) {
    header('Location:index.php');
    exit;
}

$pdo = getDbConnection();

$currentUserId = (int)($_SESSION['user_id'] ?? 0);
$currentUserRole = strtolower(trim((string)($_SESSION['user_role'] ?? $_SESSION['role'] ?? 'teacher')));
$isAdmin = $currentUserRole === 'admin';

$books = [];
if ($isAdmin) {
    $books = $pdo->query(
        "SELECT id, name, slug
         FROM books
         WHERE status = 'active'
         ORDER BY sort_order, name"
    )->fetchAll(PDO::FETCH_ASSOC);
} else {
    $bookStmt = $pdo->prepare(
        "SELECT b.id, b.name, b.slug
         FROM teacher_content_assignments tca
         INNER JOIN books b ON b.id = tca.book_id
         WHERE tca.teacher_id = ?
           AND tca.status = 'active'
           AND b.status = 'active'
         GROUP BY b.id, b.name, b.slug, b.sort_order
         ORDER BY b.sort_order, b.name"
    );
    $bookStmt->execute([$currentUserId]);
    $books = $bookStmt->fetchAll(PDO::FETCH_ASSOC);
}

$allowedBookIds = array_map(
    static fn(array $book): int => (int)$book['id'],
    $books
);


// Sách đang làm việc được điều khiển toàn cục bởi topbar.
$currentBookId = max(0, (int)($_SESSION['teacher_book_id'] ?? 0));
if (!in_array($currentBookId, $allowedBookIds, true)) {
    $currentBookId = $allowedBookIds[0] ?? 0;
    if ($currentBookId > 0) {
        $_SESSION['teacher_book_id'] = $currentBookId;
    }
}

$currentBook = null;
foreach ($books as $book) {
    if ((int)$book['id'] === $currentBookId) {
        $currentBook = $book;
        break;
    }
}

$levels = [];
if ($currentBookId > 0) {
    $levelStmt = $pdo->prepare(
        "SELECT id, book_id, level_number, name, slug
         FROM levels
         WHERE book_id = ?
           AND status = 'active'
         ORDER BY sort_order, level_number, name"
    );
    $levelStmt->execute([$currentBookId]);
    $levels = $levelStmt->fetchAll(PDO::FETCH_ASSOC);
}

$setBookTableExists = (int)$pdo->query(
    "SELECT COUNT(*)
     FROM information_schema.TABLES
     WHERE TABLE_SCHEMA = DATABASE()
       AND TABLE_NAME = 'flashcard_set_books'"
)->fetchColumn() > 0;

$stmt = $pdo->prepare('SELECT * FROM flashcard_sets WHERE id = ?');
$stmt->execute([$id]);
$set = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$set) {
    header('Location:index.php');
    exit;
}

$ownerId = array_key_exists('created_by_teacher_id', $set) && $set['created_by_teacher_id'] !== null
    ? (int)$set['created_by_teacher_id']
    : 0;
$canManageSet = $isAdmin || ($ownerId > 0 && $ownerId === $currentUserId);
if (!$canManageSet) {
    $_SESSION['flashcards_message'] = 'Bạn chỉ có thể chỉnh sửa Flashcard Set do chính mình tạo.';
    $_SESSION['flashcards_message_type'] = 'error';
    header('Location:preview.php?id=' . (int)$id);
    exit;
}

$linkedBookIds = [];
if ($setBookTableExists) {
    $linkedBookStmt = $pdo->prepare(
        "SELECT book_id
         FROM flashcard_set_books
         WHERE flashcard_set_id = ?
         ORDER BY book_id"
    );
    $linkedBookStmt->execute([$id]);
    $linkedBookIds = array_map('intval', $linkedBookStmt->fetchAll(PDO::FETCH_COLUMN));
}


$setLevelTableExists = (int)$pdo->query(
    "SELECT COUNT(*)
     FROM information_schema.TABLES
     WHERE TABLE_SCHEMA = DATABASE()
       AND TABLE_NAME = 'flashcard_set_levels'"
)->fetchColumn() > 0;

$levelsByBook = [];
if ($allowedBookIds !== []) {
    $levelPlaceholders = implode(',', array_fill(0, count($allowedBookIds), '?'));
    $allLevelStmt = $pdo->prepare(
        "SELECT id, book_id, level_number, name, slug
         FROM levels
         WHERE book_id IN ({$levelPlaceholders})
           AND status = 'active'
         ORDER BY book_id, sort_order, level_number, name"
    );
    $allLevelStmt->execute($allowedBookIds);
    foreach ($allLevelStmt->fetchAll(PDO::FETCH_ASSOC) as $levelRow) {
        $levelsByBook[(int)$levelRow['book_id']][] = $levelRow;
    }
}

$linkedLevelIdsByBook = [];
if ($setLevelTableExists) {
    $linkedLevelStmt = $pdo->prepare(
        "SELECT l.book_id, fsl.level_id
         FROM flashcard_set_levels fsl
         INNER JOIN levels l ON l.id = fsl.level_id
         WHERE fsl.flashcard_set_id = ?
         ORDER BY fsl.id"
    );
    $linkedLevelStmt->execute([$id]);
    foreach ($linkedLevelStmt->fetchAll(PDO::FETCH_ASSOC) as $linkedLevelRow) {
        $bookId = (int)$linkedLevelRow['book_id'];
        if (!isset($linkedLevelIdsByBook[$bookId])) {
            $linkedLevelIdsByBook[$bookId] = (int)$linkedLevelRow['level_id'];
        }
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST'
    && ($_POST['action'] ?? '') === 'save_set_info'
) {
    $setId = filter_input(INPUT_POST, 'set_id', FILTER_VALIDATE_INT);
    $title = trim((string)($_POST['title'] ?? ''));
    $description = trim((string)($_POST['description'] ?? ''));
    $postedLevelIds = [];
    foreach ((array)($_POST['level_ids'] ?? []) as $bookIdRaw => $levelIdRaw) {
        $bookIdKey = (int)$bookIdRaw;
        $levelIdValue = (int)$levelIdRaw;
        if ($bookIdKey > 0 && $levelIdValue > 0) {
            $postedLevelIds[$bookIdKey] = $levelIdValue;
        }
    }

    $postedBookIds = array_values(array_unique(array_filter(
        array_map('intval', (array)($_POST['book_ids'] ?? [])),
        static fn(int $bookId): bool => $bookId > 0
    )));
    $postedBookIds = array_values(array_intersect($postedBookIds, $allowedBookIds));

    if (!$setId || $setId !== $id) {
        header('Location:edit.php?id=' . (int)$id . '&save=invalid');
        exit;
    }

    if ($title === '') {
        header('Location:edit.php?id=' . (int)$id . '&save=title_required');
        exit;
    }

    if (!$setBookTableExists) {
        header('Location:edit.php?id=' . (int)$id . '&save=books_table_missing');
        exit;
    }

    if ($postedBookIds === []) {
        header('Location:edit.php?id=' . (int)$id . '&save=book_required');
        exit;
    }

    if (!$setLevelTableExists) {
        header('Location:edit.php?id=' . (int)$id . '&save=levels_table_missing');
        exit;
    }

    if ($currentBookId <= 0 || !in_array($currentBookId, $postedBookIds, true)) {
        header('Location:edit.php?id=' . (int)$id . '&save=current_book_required');
        exit;
    }

    $validLevelStmt = $pdo->prepare(
        "SELECT id
         FROM levels
         WHERE id = ?
           AND book_id = ?
           AND status = 'active'
         LIMIT 1"
    );

    foreach ($postedBookIds as $postedBookId) {
        $postedLevelId = (int)($postedLevelIds[$postedBookId] ?? 0);
        if ($postedLevelId <= 0) {
            header('Location:edit.php?id=' . (int)$id . '&save=level_required&book=' . $postedBookId);
            exit;
        }

        $validLevelStmt->execute([$postedLevelId, $postedBookId]);
        if (!$validLevelStmt->fetchColumn()) {
            header('Location:edit.php?id=' . (int)$id . '&save=invalid_level&book=' . $postedBookId);
            exit;
        }
    }

    // Không cho trùng tên Set trong cùng cặp Book + Level.
    $duplicateStmt = $pdo->prepare(
        "SELECT fs.id
         FROM flashcard_sets fs
         INNER JOIN flashcard_set_books fsb
                 ON fsb.flashcard_set_id = fs.id
         INNER JOIN flashcard_set_levels fsl
                 ON fsl.flashcard_set_id = fs.id
         INNER JOIN levels l
                 ON l.id = fsl.level_id
                AND l.book_id = fsb.book_id
         WHERE fsb.book_id = ?
           AND fsl.level_id = ?
           AND fs.id <> ?
           AND LOWER(TRIM(fs.title)) = LOWER(TRIM(?))
         LIMIT 1"
    );
    foreach ($postedBookIds as $postedBookId) {
        $duplicateStmt->execute([
            $postedBookId,
            (int)$postedLevelIds[$postedBookId],
            $setId,
            $title,
        ]);
        if ($duplicateStmt->fetchColumn()) {
            header('Location:edit.php?id=' . (int)$id . '&save=duplicate&book=' . $postedBookId);
            exit;
        }
    }

    try {
        $pdo->beginTransaction();

        $save = $pdo->prepare(
            'UPDATE flashcard_sets
             SET title = ?, description = ?, updated_at = CURRENT_TIMESTAMP
             WHERE id = ?'
        );
        $save->execute([$title, $description, $setId]);

        $deleteBookLinks = $pdo->prepare(
            'DELETE FROM flashcard_set_books WHERE flashcard_set_id = ?'
        );
        $deleteBookLinks->execute([$setId]);

        $insertBookLink = $pdo->prepare(
            'INSERT INTO flashcard_set_books (flashcard_set_id, book_id, created_at)
             VALUES (?, ?, NOW())'
        );

        foreach ($postedBookIds as $bookId) {
            $insertBookLink->execute([$setId, $bookId]);
        }

        // Mỗi Book được chọn phải có đúng một Level thuộc chính Book đó.
        // Xóa toàn bộ liên kết Level cũ để tránh còn Level mồ côi khi bỏ một Book khỏi Set.
        $deleteLevelLinks = $pdo->prepare(
            'DELETE FROM flashcard_set_levels WHERE flashcard_set_id = ?'
        );
        $deleteLevelLinks->execute([$setId]);

        $insertLevelLink = $pdo->prepare(
            "INSERT INTO flashcard_set_levels (flashcard_set_id, level_id, created_at)
             VALUES (?, ?, NOW())"
        );
        foreach ($postedBookIds as $postedBookId) {
            $insertLevelLink->execute([$setId, (int)$postedLevelIds[$postedBookId]]);
        }

        $pdo->commit();
        // Working book is controlled globally by the Teacher Portal topbar.
        // Editing a multi-book Set must not silently switch that global context.

        header('Location:edit.php?id=' . (int)$setId . '&save=ok');
        exit;
    } catch (Throwable $e) {
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }

        error_log('EnglishSpeak flashcards/edit.php save_set_info: ' . $e->getMessage());
        $_SESSION['flashcards_debug_error'] = $e->getMessage();
        header('Location:edit.php?id=' . (int)$id . '&save=failed');
        exit;
    }
}

$fswColumns = $pdo->query("SHOW COLUMNS FROM flashcard_set_words")->fetchAll(PDO::FETCH_COLUMN);
$hasFswExampleId = in_array('example_id', $fswColumns, true);

$wordSelect = "
    w.id,
    w.word,
    w.meaning_vi,
    w.phonetic,
    w.image_path,
    w.audio_us_path,
    w.part_of_speech,
    w.cefr_level,
    (SELECT we.example_en
       FROM word_examples we
      WHERE we.word_id = w.id AND we.status = 'active'
      ORDER BY we.sort_order, we.id
      LIMIT 1) AS example_en,
    (SELECT GROUP_CONCAT(DISTINCT t.name ORDER BY t.name SEPARATOR ', ')
       FROM topic_words tw
       INNER JOIN topics t ON t.id = tw.topic_id
      WHERE tw.word_id = w.id) AS topics
";

$selectedExtraSelect = $hasFswExampleId
    ? ", fsw.example_id,
       chosen_we.example_en AS chosen_example_en,
       chosen_we.example_vi AS chosen_example_vi"
    : ", NULL AS example_id,
       NULL AS chosen_example_en,
       NULL AS chosen_example_vi";

$selectedExampleJoin = $hasFswExampleId
    ? " LEFT JOIN word_examples chosen_we
          ON chosen_we.id = fsw.example_id
         AND chosen_we.word_id = w.id
         AND chosen_we.status = 'active' "
    : "";

$stmt = $pdo->prepare("SELECT {$wordSelect}, fsw.order_no {$selectedExtraSelect}
    FROM flashcard_set_words fsw
    INNER JOIN words w ON w.id = fsw.word_id
    {$selectedExampleJoin}
    WHERE fsw.set_id = ?
    ORDER BY fsw.order_no, fsw.id");
$stmt->execute([$id]);
$selected = $stmt->fetchAll();
$selectedIds = array_map(static fn(array $row): int => (int)$row['id'], $selected);

$examplesByWordId = [];
if ($selectedIds !== []) {
    $placeholders = implode(',', array_fill(0, count($selectedIds), '?'));
    $examplesStmt = $pdo->prepare(
        "SELECT id, word_id, example_en, example_vi, sort_order
         FROM word_examples
         WHERE status = 'active'
           AND word_id IN ({$placeholders})
         ORDER BY word_id, sort_order, id"
    );
    $examplesStmt->execute($selectedIds);
    foreach ($examplesStmt->fetchAll(PDO::FETCH_ASSOC) as $exampleRow) {
        $examplesByWordId[(int)$exampleRow['word_id']][] = $exampleRow;
    }
}

$stmt = $pdo->query("SELECT {$wordSelect}
    FROM words w
    WHERE w.status = 'active'
    ORDER BY w.word");
$library = $stmt->fetchAll();

$cefrFilterOptions = $pdo->query(
    "SELECT
        cefr_level,
        COUNT(*) AS word_count
     FROM words
     WHERE status = 'active'
       AND cefr_level IN ('Pre-A1', 'A1', 'A2', 'B1', 'B2', 'C1', 'C2')
     GROUP BY cefr_level
     ORDER BY FIELD(cefr_level, 'Pre-A1', 'A1', 'A2', 'B1', 'B2', 'C1', 'C2')"
)->fetchAll(PDO::FETCH_ASSOC);

$posFilterOptions = $pdo->query(
    "SELECT
        part_of_speech,
        COUNT(*) AS word_count
     FROM words
     WHERE status = 'active'
       AND COALESCE(TRIM(part_of_speech), '') <> ''
     GROUP BY part_of_speech
     ORDER BY part_of_speech"
)->fetchAll(PDO::FETCH_ASSOC);

$topicFilterOptions = $pdo->query(
    "SELECT
        t.id,
        t.name,
        COUNT(DISTINCT tw.word_id) AS word_count
     FROM topics t
     INNER JOIN topic_words tw ON tw.topic_id = t.id
     INNER JOIN words w ON w.id = tw.word_id
     WHERE t.status = 'active'
       AND w.status = 'active'
     GROUP BY t.id, t.name
     ORDER BY t.name"
)->fetchAll(PDO::FETCH_ASSOC);

$pageTitle = 'Edit Flashcard Set';
$pageSubtitle = $set['title'];
$activeTeacherNav = 'flashcards';

function fcWordData(array $word): string
{
    $qualityFields = [
        !empty($word['image_path']),
        !empty($word['audio_us_path']),
        !empty($word['phonetic']),
        !empty($word['meaning_vi']),
        !empty($word['cefr_level']),
        !empty($word['example_en']),
        !empty($word['topics']),
    ];

    $qualityScore = count(array_filter($qualityFields));
    $qualityLabel = $qualityScore >= 7
        ? 'Complete'
        : ($qualityScore >= 4 ? 'Missing' : 'Incomplete');

    $payload = [
        'id' => (int)$word['id'],
        'word' => (string)$word['word'],
        'meaning' => (string)($word['meaning_vi'] ?? ''),
        'ipa' => (string)($word['phonetic'] ?? ''),
        'image' => !empty($word['image_path']) ? es_url($word['image_path']) : '',
        'audio' => !empty($word['audio_us_path']) ? es_url($word['audio_us_path']) : '',
        'partOfSpeech' => (string)($word['part_of_speech'] ?? ''),
        'cefr' => (string)($word['cefr_level'] ?? ''),
        'level' => (string)($word['cefr_level'] ?? ''),
        'example' => (string)($word['chosen_example_en'] ?? $word['example_en'] ?? ''),
        'topics' => (string)($word['topics'] ?? ''),
        'qualityScore' => $qualityScore,
        'qualityLabel' => $qualityLabel,
        'editUrl' => '../word-library/index.php?edit=' . (int)$word['id'],
        'libraryUrl' => '../word-library/index.php?search=' . rawurlencode((string)$word['word']),
    ];

    return htmlspecialchars(
        json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
        ENT_QUOTES,
        'UTF-8'
    );
}

ob_start(); ?>
<link rel="stylesheet" href="../assets/css/flashcards.css?v=2">
<div id="flashcardsEditor" data-set-id="<?= (int)$id ?>">
    <div class="fc-page-head">
        <form id="flashcardSetInfoForm" class="fc-title-area" method="post" action="edit.php?id=<?= (int)$id ?>">
            <input type="hidden" name="action" value="save_set_info">
            <input type="hidden" name="set_id" value="<?= (int)$id ?>">

            <input
                id="setTitle"
                name="title"
                class="fc-title-input"
                value="<?= htmlspecialchars($set['title']) ?>"
                maxlength="255"
                required
            >

            <textarea
                id="setDescription"
                name="description"
                class="fc-desc-input"
                rows="2"
                placeholder="Description"
            ><?= htmlspecialchars((string)$set['description']) ?></textarea>

            <div class="fc-book-box">
                <span class="fc-book-label">Sách sử dụng Set này + Lớp / Level *</span>
                <small style="display:block;margin-bottom:10px;">
                    Mỗi sách được chọn bắt buộc phải có Level riêng thuộc chính sách đó.
                </small>

                <div class="fc-book-level-list" style="display:grid;gap:10px;">
                    <?php foreach ($books as $book): ?>
                        <?php
                        $bookId = (int)$book['id'];
                        $isLinkedBook = in_array($bookId, $linkedBookIds, true);
                        $selectedLevelForBook = (int)($linkedLevelIdsByBook[$bookId] ?? 0);
                        $bookLevels = $levelsByBook[$bookId] ?? [];
                        ?>
                        <div class="fc-book-level-row" data-book-row="<?= $bookId ?>" style="display:grid;grid-template-columns:minmax(180px,1fr) minmax(180px,260px);gap:10px;align-items:center;">
                            <label class="fc-book-option" style="margin:0;">
                                <input
                                    type="checkbox"
                                    class="js-book-toggle"
                                    name="book_ids[]"
                                    value="<?= $bookId ?>"
                                    data-book-id="<?= $bookId ?>"
                                    <?= $isLinkedBook ? 'checked' : '' ?>
                                    <?= $bookId === $currentBookId ? 'data-current-book="1"' : '' ?>
                                >
                                <span>📘 <?= htmlspecialchars((string)$book['name'], ENT_QUOTES, 'UTF-8') ?></span>
                            </label>

                            <select
                                class="fc-filter-select js-book-level"
                                name="level_ids[<?= $bookId ?>]"
                                data-book-id="<?= $bookId ?>"
                                <?= $isLinkedBook ? 'required' : 'disabled' ?>
                            >
                                <option value="">-- Chọn Lớp / Level --</option>
                                <?php foreach ($bookLevels as $level): ?>
                                    <?php $levelIdOption = (int)$level['id']; ?>
                                    <option
                                        value="<?= $levelIdOption ?>"
                                        <?= $selectedLevelForBook === $levelIdOption ? 'selected' : '' ?>
                                    >
                                        <?= htmlspecialchars((string)$level['name'], ENT_QUOTES, 'UTF-8') ?>
                                    </option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                    <?php endforeach; ?>
                </div>
                <small>Một Set có thể dùng cho nhiều sách nhưng không được có Book nào thiếu Level.</small>
            </div>

            <div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;">
                <?php $saveState = (string)($_GET['save'] ?? ''); ?>
                <?php if ($saveState === 'ok'): ?>
                    <small class="fc-save-status" style="color:#15803d;">Saved</small>
                <?php elseif ($saveState === 'title_required'): ?>
                    <small class="fc-save-status" style="color:#b91c1c;">Title is required</small>
                <?php elseif ($saveState === 'book_required'): ?>
                    <small class="fc-save-status" style="color:#b91c1c;">Hãy chọn ít nhất 1 sách</small>
                <?php elseif ($saveState === 'books_table_missing'): ?>
                    <small class="fc-save-status" style="color:#b91c1c;">Chưa có bảng flashcard_set_books</small>
                <?php elseif ($saveState === 'levels_table_missing'): ?>
                    <small class="fc-save-status" style="color:#b91c1c;">Chưa có bảng flashcard_set_levels</small>
                <?php elseif ($saveState === 'level_required'): ?>
                    <small class="fc-save-status" style="color:#b91c1c;">Mỗi sách được chọn phải có Lớp / Level</small>
                <?php elseif ($saveState === 'invalid_level'): ?>
                    <small class="fc-save-status" style="color:#b91c1c;">Level đã chọn không thuộc đúng sách</small>
                <?php elseif ($saveState === 'current_book_required'): ?>
                    <small class="fc-save-status" style="color:#b91c1c;">Set phải thuộc sách đang làm việc</small>
                <?php elseif ($saveState === 'duplicate'): ?>
                    <small class="fc-save-status" style="color:#b91c1c;">Tên Set này đã tồn tại trong sách đang làm việc</small>
                <?php elseif ($saveState === 'failed' || $saveState === 'invalid'): ?>
                    <small class="fc-save-status" style="color:#b91c1c;">
                        Save failed
                        <?php if (!empty($_SESSION['flashcards_debug_error'])): ?>
                            — <?= htmlspecialchars((string)$_SESSION['flashcards_debug_error'], ENT_QUOTES, 'UTF-8') ?>
                            <?php unset($_SESSION['flashcards_debug_error']); ?>
                        <?php endif; ?>
                    </small>
                <?php endif; ?>
            </div>
        </form>
        <div class="fc-head-actions">
            <a class="button button-secondary" href="index.php">← List</a>
            <a class="button button-secondary" href="preview.php?id=<?= (int)$id ?>">Student Preview</a>
            <button class="button button-primary" type="submit" form="flashcardSetInfoForm">Save Changes</button>
        </div>
    </div>

    <div class="fc-summary" aria-label="Flashcard set summary">
        <div><span>Total words</span><strong id="summaryTotalCount"><?= count($library) ?></strong></div>
        <div><span>Showing</span><strong id="summaryLibraryCount"><?= count($library) ?></strong></div>
        <div><span>Selected</span><strong id="summarySelectedCount"><?= count($selected) ?></strong></div>
    </div>

    <div class="flashcards-editor">
        <section class="fc-panel">
            <div class="fc-panel-head">
                <strong>Word Library</strong>
                <span id="libraryCount"><?= count($library) ?></span>
            </div>
            <div class="fc-panel-body">
                <div class="fc-library-tools">
                    <input
                        id="wordSearch"
                        class="fc-search"
                        placeholder="Search word, meaning or IPA..."
                        autocomplete="off"
                    >

                    <div class="fc-filter-row">
                        <label class="fc-filter-field">
                            <span>Topic</span>
                            <select id="topicFilter" class="fc-filter-select">
                                <option value="">All Topics</option>
                                <?php foreach ($topicFilterOptions as $topic): ?>
                                <option value="<?= htmlspecialchars(
                                    mb_strtolower((string)$topic['name']),
                                    ENT_QUOTES,
                                    'UTF-8'
                                ) ?>">
                                    <?= htmlspecialchars((string)$topic['name'], ENT_QUOTES, 'UTF-8') ?>
                                    (<?= (int)$topic['word_count'] ?>)
                                </option>
                                <?php endforeach; ?>
                            </select>
                        </label>

                        <label class="fc-filter-field">
                            <span>CEFR</span>
                            <select id="cefrFilter" class="fc-filter-select">
                                <option value="">All CEFR</option>
                                <?php foreach ($cefrFilterOptions as $cefr): ?>
                                <option value="<?= htmlspecialchars(
                                    (string)$cefr['cefr_level'],
                                    ENT_QUOTES,
                                    'UTF-8'
                                ) ?>">
                                    <?= htmlspecialchars((string)$cefr['cefr_level'], ENT_QUOTES, 'UTF-8') ?>
                                    (<?= (int)$cefr['word_count'] ?>)
                                </option>
                                <?php endforeach; ?>
                            </select>
                        </label>

                        <label class="fc-filter-field">
                            <span>Part of Speech</span>
                            <select id="posFilter" class="fc-filter-select">
                                <option value="">All POS</option>
                                <?php foreach ($posFilterOptions as $pos): ?>
                                <option value="<?= htmlspecialchars(
                                    mb_strtolower((string)$pos['part_of_speech']),
                                    ENT_QUOTES,
                                    'UTF-8'
                                ) ?>">
                                    <?= htmlspecialchars(ucfirst((string)$pos['part_of_speech']), ENT_QUOTES, 'UTF-8') ?>
                                    (<?= (int)$pos['word_count'] ?>)
                                </option>
                                <?php endforeach; ?>
                            </select>
                        </label>
                    </div>

                    <div class="fc-filter-actions">
                        <button
                            type="button"
                            class="button button-sm button-secondary"
                            id="selectVisibleBtn"
                        >
                            Select Visible
                        </button>

                        <button
                            type="button"
                            class="button button-sm button-secondary"
                            id="clearSelectionBtn"
                            <?= empty($selected) ? 'disabled' : '' ?>
                        >
                            Clear Selection
                        </button>
                    </div>

                    <div class="fc-filter-status" id="filterStatus" aria-live="polite"></div>
                </div>

                <div id="wordLibrary" class="fc-word-list">
                    <?php foreach ($library as $word):
                        $isSelected = in_array((int)$word['id'], $selectedIds, true); ?>
                        <button
                            class="fc-word-item<?= $isSelected ? ' is-selected' : '' ?>"
                            data-add-word="<?= (int)$word['id'] ?>"
                            data-word-json="<?= fcWordData($word) ?>"
                            data-search-text="<?= htmlspecialchars(
                                mb_strtolower(
                                    trim(
                                        (string)$word['word']
                                        . ' '
                                        . (string)($word['meaning_vi'] ?? '')
                                        . ' '
                                        . (string)($word['phonetic'] ?? '')
                                        . ' '
                                        . (string)($word['part_of_speech'] ?? '')
                                        . ' '
                                        . (string)($word['cefr_level'] ?? '')
                                        . ' '
                                        . (string)($word['topics'] ?? '')
                                    )
                                ),
                                ENT_QUOTES,
                                'UTF-8'
                            ) ?>"
                            data-topics="<?= htmlspecialchars(
                                mb_strtolower((string)($word['topics'] ?? '')),
                                ENT_QUOTES,
                                'UTF-8'
                            ) ?>"
                            data-cefr="<?= htmlspecialchars(
                                (string)($word['cefr_level'] ?? ''),
                                ENT_QUOTES,
                                'UTF-8'
                            ) ?>"
                            data-pos="<?= htmlspecialchars(
                                mb_strtolower((string)($word['part_of_speech'] ?? '')),
                                ENT_QUOTES,
                                'UTF-8'
                            ) ?>"
                            type="button"
                           
                        >
                            <span class="fc-thumb">
                                <?php if ($word['image_path']): ?>
                                    <img src="<?= htmlspecialchars(es_url($word['image_path'])) ?>" alt="">
                                <?php else: ?>
                                    <?= htmlspecialchars(mb_strtoupper(mb_substr($word['word'], 0, 1))) ?>
                                <?php endif; ?>
                            </span>
                            <span class="fc-word-copy">
                                <strong><?= htmlspecialchars($word['word']) ?></strong>
                                <small><?= htmlspecialchars((string)$word['meaning_vi']) ?></small>
                            </span>
                            <span class="fc-add-label"><?= $isSelected ? '✓ Added' : '+ Add' ?></span>
                        </button>
                    <?php endforeach; ?>
                </div>
            </div>
        </section>

        <section class="fc-panel">
            <div class="fc-panel-head">
                <strong>Selected Words</strong>
                <span id="selectedCount"><?= count($selected) ?></span>
            </div>
            <div class="fc-panel-body">
                <div id="selectedWords" class="fc-selected-list">
                    <?php foreach ($selected as $word): ?>
                        <div
                            class="fc-selected-item"
                            draggable="true"
                            data-word-id="<?= (int)$word['id'] ?>"
                            data-word-json="<?= fcWordData($word) ?>"
                        >
                            <span class="fc-drag" title="Drag to reorder">⋮⋮</span>
                            <span class="fc-order"><?= (int)$word['order_no'] ?></span>
                            <span class="fc-thumb fc-selected-thumb">
                                <?php if ($word['image_path']): ?>
                                    <img src="<?= htmlspecialchars(es_url($word['image_path'])) ?>" alt="">
                                <?php else: ?>
                                    <?= htmlspecialchars(mb_strtoupper(mb_substr($word['word'], 0, 1))) ?>
                                <?php endif; ?>
                            </span>
                            <span class="fc-selected-copy">
                                <strong><?= htmlspecialchars($word['word']) ?></strong>
                                <small><?= htmlspecialchars((string)$word['meaning_vi']) ?></small>
                                <?php if (!empty($word['part_of_speech'])): ?>
                                    <em><?= htmlspecialchars((string)$word['part_of_speech']) ?></em>
                                <?php endif; ?>
                                <?php $wordExamples = $examplesByWordId[(int)$word['id']] ?? []; ?>
                                <?php if ($wordExamples !== []): ?>
                                    <label class="fc-example-picker-label">Example</label>
                                    <select
                                        class="fc-example-picker"
                                        data-example-picker
                                        data-word-id="<?= (int)$word['id'] ?>"
                                        <?= !$hasFswExampleId ? 'disabled' : '' ?>
                                    >
                                        <?php foreach ($wordExamples as $exampleOption): ?>
                                            <?php
                                            $exampleOptionId = (int)$exampleOption['id'];
                                            $selectedExampleId = (int)($word['example_id'] ?? 0);
                                            // Existing Sets with no explicit choice keep the first example as default.
                                            $isExampleSelected = $selectedExampleId > 0
                                                ? $selectedExampleId === $exampleOptionId
                                                : $exampleOption === $wordExamples[0];
                                            ?>
                                            <option
                                                value="<?= $exampleOptionId ?>"
                                                data-example-en="<?= htmlspecialchars((string)$exampleOption['example_en'], ENT_QUOTES, 'UTF-8') ?>"
                                                <?= $isExampleSelected ? 'selected' : '' ?>
                                            >
                                                <?= htmlspecialchars((string)$exampleOption['example_en']) ?>
                                            </option>
                                        <?php endforeach; ?>
                                    </select>
                                <?php else: ?>
                                    <small class="fc-example-empty">No example yet.</small>
                                <?php endif; ?>
                            </span>
                            <button type="button" data-remove-word="<?= (int)$word['id'] ?>" aria-label="Remove <?= htmlspecialchars($word['word']) ?>">×</button>
                        </div>
                    <?php endforeach; ?>
                </div>
                <div id="selectedEmpty" class="fc-empty-small" <?= $selected ? 'hidden' : '' ?>>Add words from the library.</div>
            </div>
        </section>

        <aside class="fc-panel">
            <div class="fc-panel-head">
                <strong>Preview</strong>
                <span class="fc-preview-hint">Word details</span>
            </div>
            <div class="fc-panel-body">
                <div class="fc-preview-pro" id="previewCard">
                    <div class="fc-preview-media" id="previewImage">
                        <span>A</span>
                    </div>

                    <div class="fc-preview-title-row">
                        <div>
                            <h2 id="previewWord">Select a word</h2>
                            <div id="previewIpa" class="fc-preview-ipa" hidden></div>
                        </div>

                        <span
                            id="previewQuality"
                            class="fc-quality-badge fc-quality-empty"
                        >
                            No data
                        </span>
                    </div>

                    <div class="fc-preview-details">
                        <div class="fc-preview-field">
                            <span>Meaning</span>
                            <strong id="previewMeaning">Click a word to preview it.</strong>
                        </div>

                        <div class="fc-preview-field">
                            <span>CEFR</span>
                            <strong id="previewCefr">—</strong>
                        </div>

                        <div class="fc-preview-field">
                            <span>Part of Speech</span>
                            <strong id="previewPos">—</strong>
                        </div>

                        <div class="fc-preview-field fc-preview-field-wide">
                            <span>Topic</span>
                            <strong id="previewTopics">—</strong>
                        </div>
                    </div>

                    <div id="previewExampleWrap" class="fc-preview-example-pro" hidden>
                        <span>Example</span>
                        <p id="previewExample"></p>
                    </div>

                    <div class="fc-preview-actions">
                        <button
                            id="speakButton"
                            class="button button-sm button-primary"
                            type="button"
                            disabled
                        >
                            🔊 Listen
                        </button>

                        <a
                            id="previewEditLink"
                            class="button button-sm button-secondary is-disabled"
                            href="#"
                            aria-disabled="true"
                        >
                            Edit Word
                        </a>

                        <a
                            id="previewLibraryLink"
                            class="button button-sm button-secondary is-disabled"
                            href="#"
                            aria-disabled="true"
                        >
                            Open Library
                        </a>
                    </div>
                </div>
            </div>
        </aside>
    </div>
</div>

<style>
.fc-library-tools{
    display:grid;
    gap:9px;
    margin-bottom:10px;
}
.fc-filter-row{
    display:grid;
    grid-template-columns:repeat(3,minmax(0,1fr));
    gap:8px;
}
.fc-filter-field{
    display:grid;
    gap:5px;
}
.fc-filter-field>span{
    color:#64748b;
    font-size:11px;
    font-weight:800;
    letter-spacing:.04em;
    text-transform:uppercase;
}
.fc-filter-select{
    width:100%;
    min-height:40px;
    padding:0 10px;
    border:1px solid #dbe2ea;
    border-radius:10px;
    background:#fff;
    color:#0f172a;
    font:inherit;
}
.fc-filter-actions{
    display:flex;
    align-items:center;
    gap:8px;
    flex-wrap:wrap;
}
.fc-filter-status{
    min-height:18px;
    color:#64748b;
    font-size:12px;
}
.fc-filter-actions button[disabled]{
    opacity:.55;
    cursor:not-allowed;
}
.fc-word-item[hidden]{
    display:none !important;
}
.fc-preview-pro{
    display:grid;
    gap:15px;
}
.fc-preview-media{
    display:flex;
    align-items:center;
    justify-content:center;
    width:100%;
    min-height:210px;
    padding:14px;
    overflow:hidden;
    border:1px solid #e5e7eb;
    border-radius:18px;
    background:#f8fafc;
    color:#2563eb;
    font-size:64px;
    font-weight:900;
}
.fc-preview-media img{
    display:block;
    width:100%;
    max-height:250px;
    object-fit:contain;
}
.fc-preview-title-row{
    display:flex;
    align-items:flex-start;
    justify-content:space-between;
    gap:12px;
}
.fc-preview-title-row h2{
    margin:0;
    color:#0f172a;
    font-size:26px;
    line-height:1.15;
}
.fc-preview-ipa{
    margin-top:5px;
    color:#64748b;
    font-size:13px;
}
.fc-quality-badge{
    display:inline-flex;
    align-items:center;
    gap:6px;
    flex:0 0 auto;
    padding:5px 9px;
    border-radius:999px;
    font-size:10px;
    font-weight:850;
}
.fc-quality-badge::before{
    content:'';
    width:7px;
    height:7px;
    border-radius:50%;
    background:currentColor;
}
.fc-quality-complete{background:#ecfdf5;color:#047857}
.fc-quality-missing{background:#fff7ed;color:#c2410c}
.fc-quality-incomplete{background:#fef2f2;color:#b91c1c}
.fc-quality-empty{background:#f1f5f9;color:#64748b}
.fc-preview-details{
    display:grid;
    grid-template-columns:repeat(2,minmax(0,1fr));
    gap:9px;
}
.fc-preview-field{
    min-width:0;
    padding:10px 11px;
    border:1px solid #e5e7eb;
    border-radius:12px;
    background:#fff;
}
.fc-preview-field-wide{
    grid-column:1 / -1;
}
.fc-preview-field span,
.fc-preview-example-pro>span{
    display:block;
    margin-bottom:4px;
    color:#94a3b8;
    font-size:9px;
    font-weight:850;
    letter-spacing:.08em;
    text-transform:uppercase;
}
.fc-preview-field strong{
    display:block;
    overflow-wrap:anywhere;
    color:#334155;
    font-size:12px;
    line-height:1.45;
}
.fc-preview-example-pro{
    padding:12px;
    border:1px solid #dbeafe;
    border-radius:13px;
    background:#eff6ff;
}
.fc-preview-example-pro p{
    margin:0;
    color:#1e3a8a;
    font-size:13px;
    line-height:1.5;
}
.fc-preview-actions{
    display:flex;
    gap:8px;
    flex-wrap:wrap;
}
.fc-preview-actions .is-disabled{
    opacity:.5;
    pointer-events:none;
}
.fc-word-item.is-previewing,
.fc-selected-item.is-previewing{
    outline:2px solid #3b82f6;
    outline-offset:-2px;
    background:#eff6ff;
}
.fc-book-box{
    display:grid;
    gap:8px;
    margin-top:12px;
    padding:12px 14px;
    border:1px solid #dbeafe;
    border-radius:12px;
    background:#f8fbff;
}
.fc-book-label{
    color:#0f172a;
    font-size:12px;
    font-weight:800;
}
.fc-book-options{
    display:flex;
    flex-wrap:wrap;
    gap:8px;
}
.fc-book-option{
    display:inline-flex;
    align-items:center;
    gap:7px;
    padding:7px 10px;
    border:1px solid #dbe2ea;
    border-radius:999px;
    background:#fff;
    color:#334155;
    font-size:12px;
    font-weight:700;
    cursor:pointer;
}
.fc-book-option input{margin:0}
.fc-book-box small{color:#64748b;font-size:11px}

@media(max-width:760px){
    .fc-filter-row{grid-template-columns:1fr}
}
</style>

<script>
(function () {
    const form = document.querySelector('.fc-title-area');
    if (!form) return;

    const toggles = Array.from(form.querySelectorAll('.js-book-toggle'));

    function syncBookLevel(toggle) {
        const bookId = toggle.dataset.bookId || '';
        const select = form.querySelector('.js-book-level[data-book-id="' + bookId + '"]');
        if (!select) return;

        select.disabled = !toggle.checked;
        select.required = toggle.checked;
        if (!toggle.checked) {
            select.value = '';
        }
    }

    toggles.forEach(function (toggle) {
        syncBookLevel(toggle);
        toggle.addEventListener('change', function () {
            syncBookLevel(toggle);
        });
    });

    form.addEventListener('submit', function (event) {
        const selectedBooks = toggles.filter(function (toggle) { return toggle.checked; });
        if (selectedBooks.length === 0) {
            event.preventDefault();
            alert('Hãy chọn ít nhất 1 sách.');
            return;
        }

        for (const toggle of selectedBooks) {
            const bookId = toggle.dataset.bookId || '';
            const select = form.querySelector('.js-book-level[data-book-id="' + bookId + '"]');
            if (!select || !select.value) {
                event.preventDefault();
                if (select) select.focus();
                alert('Mỗi sách được chọn phải có Lớp / Level tương ứng.');
                return;
            }
        }
    });
})();
</script>

<style>
.fc-example-picker-label{
    display:block;
    margin-top:7px;
    margin-bottom:3px;
    font-size:11px;
    font-weight:700;
    color:#64748b;
}
.fc-example-picker{
    display:block;
    width:100%;
    max-width:360px;
    min-height:34px;
    padding:5px 30px 5px 8px;
    border:1px solid #cbd5e1;
    border-radius:8px;
    background:#fff;
    color:#0f172a;
    font-size:12px;
}
.fc-example-empty{
    display:block;
    margin-top:6px;
    color:#94a3b8;
}
.fc-example-picker.is-saving{opacity:.55}
.fc-example-picker.is-error{border-color:#ef4444}
</style>
<script src="../assets/js/flashcards.js?v=2"></script>



<script>
(function () {
    'use strict';

    const searchInput = document.getElementById('wordSearch');
    const topicFilter = document.getElementById('topicFilter');
    const cefrFilter = document.getElementById('cefrFilter');
    const posFilter = document.getElementById('posFilter');
    const library = document.getElementById('wordLibrary');
    const libraryCount = document.getElementById('libraryCount');
    const summaryLibraryCount = document.getElementById('summaryLibraryCount');
    const summarySelectedCount = document.getElementById('summarySelectedCount');
    const selectedCount = document.getElementById('selectedCount');
    const selectedWords = document.getElementById('selectedWords');
    const selectVisibleBtn = document.getElementById('selectVisibleBtn');
    const clearSelectionBtn = document.getElementById('clearSelectionBtn');
    const filterStatus = document.getElementById('filterStatus');

    if (!searchInput || !topicFilter || !cefrFilter || !posFilter || !library) {
        return;
    }

    function normalize(value) {
        return String(value || '')
            .toLocaleLowerCase('vi')
            .normalize('NFD')
            .replace(/[\u0300-\u036f]/g, '')
            .trim();
    }

    function selectedWordCount() {
        if (!selectedWords) return 0;
        return selectedWords.querySelectorAll('.fc-selected-item').length;
    }

    function updateBulkButtons() {
        const selectedTotal = selectedWordCount();

        if (clearSelectionBtn) {
            clearSelectionBtn.disabled = selectedTotal === 0;
        }

        if (summarySelectedCount) {
            summarySelectedCount.textContent = String(selectedTotal);
        }

        if (selectedCount) {
            selectedCount.textContent = String(selectedTotal);
        }

        if (selectVisibleBtn) {
            const availableVisible = Array.from(
                library.querySelectorAll('.fc-word-item')
            ).filter(function (item) {
                return !item.hidden
                    && item.style.display !== 'none'
                    && !item.classList.contains('is-selected')
                    && item.dataset.selected !== '1';
            }).length;

            selectVisibleBtn.disabled = availableVisible === 0;
        }
    }

    function applyLibraryFilters() {
        const keyword = normalize(searchInput.value);
        const topic = normalize(topicFilter.value);
        const cefr = String(cefrFilter.value || '');
        const pos = normalize(posFilter.value);
        const items = Array.from(library.querySelectorAll('.fc-word-item'));
        let visibleCount = 0;

        items.forEach(function (item) {
            const searchText = normalize(item.dataset.searchText);
            const itemTopics = normalize(item.dataset.topics);
            const itemCefr = String(item.dataset.cefr || '');
            const itemPos = normalize(item.dataset.pos);

            const matchesSearch =
                keyword === '' || searchText.includes(keyword);

            const matchesTopic =
                topic === ''
                || itemTopics
                    .split(',')
                    .map(function (value) { return value.trim(); })
                    .includes(topic);

            const matchesCefr =
                cefr === '' || itemCefr === cefr;

            const matchesPos =
                pos === '' || itemPos === pos;

            const visible =
                matchesSearch
                && matchesTopic
                && matchesCefr
                && matchesPos;

            /*
             * Gán đồng thời hidden và display để xóa nội dung Search
             * luôn khôi phục toàn bộ danh sách, kể cả khi flashcards.js
             * trước đó đã ẩn phần tử bằng style.
             */
            item.hidden = !visible;
            item.style.display = visible ? '' : 'none';

            if (visible) {
                visibleCount++;
            }
        });

        if (libraryCount) {
            libraryCount.textContent = String(visibleCount);
        }

        if (summaryLibraryCount) {
            summaryLibraryCount.textContent = String(visibleCount);
        }

        if (filterStatus) {
            const filtering = keyword !== '' || topic !== '' || cefr !== '' || pos !== '';
            filterStatus.textContent = filtering
                ? visibleCount + ' matching words'
                : visibleCount + ' words available';
        }

        updateBulkButtons();
    }

    function scheduleFilter() {
        window.setTimeout(applyLibraryFilters, 0);
    }

    function waitUntil(test, timeoutMs) {
        return new Promise(function (resolve) {
            const started = Date.now();

            function check() {
                if (test()) {
                    resolve(true);
                    return;
                }

                if (Date.now() - started >= timeoutMs) {
                    resolve(false);
                    return;
                }

                window.setTimeout(check, 40);
            }

            check();
        });
    }

    async function selectVisibleWords() {
        if (!selectVisibleBtn || selectVisibleBtn.disabled) return;

        const targets = Array.from(
            library.querySelectorAll('.fc-word-item')
        ).filter(function (item) {
            return !item.hidden
                && item.style.display !== 'none'
                && !item.classList.contains('is-selected')
                && item.dataset.selected !== '1';
        });

        if (!targets.length) return;

        selectVisibleBtn.disabled = true;
        clearSelectionBtn.disabled = true;

        const originalText = selectVisibleBtn.textContent;
        let completed = 0;

        for (const item of targets) {
            selectVisibleBtn.textContent =
                'Adding ' + (completed + 1) + ' / ' + targets.length + '…';

            const wordId = String(item.dataset.addWord || '');
            item.click();

            await waitUntil(function () {
                return item.classList.contains('is-selected')
                    || item.dataset.selected === '1'
                    || !wordId;
            }, 5000);

            completed++;
        }

        selectVisibleBtn.textContent = originalText;
        applyLibraryFilters();
    }

    async function clearSelectedWords() {
        if (!clearSelectionBtn || clearSelectionBtn.disabled || !selectedWords) {
            return;
        }

        const removeButtons = Array.from(
            selectedWords.querySelectorAll('[data-remove-word]')
        );

        if (!removeButtons.length) {
            updateBulkButtons();
            return;
        }

        selectVisibleBtn.disabled = true;
        clearSelectionBtn.disabled = true;

        const originalText = clearSelectionBtn.textContent;
        let completed = 0;

        for (const button of removeButtons) {
            const wordId = String(button.dataset.removeWord || '');
            clearSelectionBtn.textContent =
                'Removing ' + (completed + 1) + ' / ' + removeButtons.length + '…';

            button.click();

            await waitUntil(function () {
                return !selectedWords.querySelector(
                    '[data-word-id="' + wordId + '"]'
                );
            }, 5000);

            completed++;
        }

        clearSelectionBtn.textContent = originalText;
        applyLibraryFilters();
    }

    if (selectVisibleBtn) {
        selectVisibleBtn.addEventListener('click', selectVisibleWords);
    }

    if (clearSelectionBtn) {
        clearSelectionBtn.addEventListener('click', clearSelectedWords);
    }

    /*
     * flashcards.js cập nhật danh sách Selected bằng AJAX.
     * Theo dõi DOM để bộ đếm và trạng thái nút luôn đồng bộ.
     */
    if (selectedWords && 'MutationObserver' in window) {
        const observer = new MutationObserver(function () {
            updateBulkButtons();
        });

        observer.observe(selectedWords, {
            childList: true,
            subtree: true
        });
    }

    searchInput.addEventListener('input', function () {
        applyLibraryFilters();
    });
    searchInput.addEventListener('search', function () {
        applyLibraryFilters();
    });
    searchInput.addEventListener('keyup', function (event) {
        if (
            event.key === 'Backspace'
            || event.key === 'Delete'
            || event.key === 'Escape'
        ) {
            applyLibraryFilters();
        }
    });
    topicFilter.addEventListener('change', scheduleFilter);
    cefrFilter.addEventListener('change', scheduleFilter);
    posFilter.addEventListener('change', scheduleFilter);

    document.addEventListener('DOMContentLoaded', applyLibraryFilters);
    window.addEventListener('load', applyLibraryFilters);
    applyLibraryFilters();
    updateBulkButtons();
})();
</script>

<script>
(function () {
    'use strict';

    const library = document.getElementById('wordLibrary');
    const selectedWords = document.getElementById('selectedWords');
    const previewImage = document.getElementById('previewImage');
    const previewWord = document.getElementById('previewWord');
    const previewIpa = document.getElementById('previewIpa');
    const previewMeaning = document.getElementById('previewMeaning');
    const previewCefr = document.getElementById('previewCefr');
    const previewPos = document.getElementById('previewPos');
    const previewTopics = document.getElementById('previewTopics');
    const previewQuality = document.getElementById('previewQuality');
    const previewExampleWrap = document.getElementById('previewExampleWrap');
    const previewExample = document.getElementById('previewExample');
    const speakButton = document.getElementById('speakButton');
    const editLink = document.getElementById('previewEditLink');
    const libraryLink = document.getElementById('previewLibraryLink');

    let currentWord = null;

    function parseWordData(element) {
        if (!element || !element.dataset.wordJson) return null;

        try {
            return JSON.parse(element.dataset.wordJson);
        } catch (error) {
            return null;
        }
    }

    function qualityClass(label) {
        const normalized = String(label || '').toLowerCase();

        if (normalized === 'complete') return 'fc-quality-complete';
        if (normalized === 'missing') return 'fc-quality-missing';
        if (normalized === 'incomplete') return 'fc-quality-incomplete';

        return 'fc-quality-empty';
    }

    function setLink(link, href) {
        if (!link) return;

        if (href) {
            link.href = href;
            link.classList.remove('is-disabled');
            link.setAttribute('aria-disabled', 'false');
        } else {
            link.href = '#';
            link.classList.add('is-disabled');
            link.setAttribute('aria-disabled', 'true');
        }
    }

    function highlightSource(source) {
        document.querySelectorAll(
            '.fc-word-item.is-previewing, .fc-selected-item.is-previewing'
        ).forEach(function (item) {
            item.classList.remove('is-previewing');
        });

        if (source) source.classList.add('is-previewing');
    }

    function renderPreview(data, source) {
        if (!data) return;

        currentWord = data;
        highlightSource(source);

        const word = String(data.word || '');
        const firstLetter = word ? word.charAt(0).toUpperCase() : '?';

        previewImage.innerHTML = data.image
            ? '<img src="' + String(data.image).replace(/"/g, '&quot;') + '" alt="">'
            : '<span>' + firstLetter + '</span>';

        previewWord.textContent = word || '—';

        previewIpa.textContent = data.ipa || '';
        previewIpa.hidden = !data.ipa;

        previewMeaning.textContent = data.meaning || 'No meaning yet.';
        previewCefr.textContent = data.cefr || 'Not assigned';
        previewPos.textContent = data.partOfSpeech
            ? data.partOfSpeech.charAt(0).toUpperCase() + data.partOfSpeech.slice(1)
            : 'Not assigned';
        previewTopics.textContent = data.topics || 'No Topic';

        const label = data.qualityLabel || 'Incomplete';
        previewQuality.textContent =
            label + ' · ' + String(data.qualityScore || 0) + '/7';
        previewQuality.className =
            'fc-quality-badge ' + qualityClass(label);

        previewExample.textContent = data.example || '';
        previewExampleWrap.hidden = !data.example;

        speakButton.disabled = !word;
        setLink(editLink, data.editUrl || '');
        setLink(libraryLink, data.libraryUrl || '');
    }

    function previewFromEvent(event) {
        const source = event.target.closest(
            '.fc-word-item[data-word-json], .fc-selected-item[data-word-json]'
        );

        if (!source) return;

        /*
         * Remove buttons and Add actions keep their original behavior.
         * Clicking elsewhere on the item opens Preview Pro.
         */
        if (event.target.closest('[data-remove-word]')) return;

        const data = parseWordData(source);
        if (data) renderPreview(data, source);
    }

    document.addEventListener('click', previewFromEvent);

    document.addEventListener('change', async function (event) {
        const picker = event.target.closest('[data-example-picker]');
        if (!picker) return;

        const selectedItem = picker.closest('.fc-selected-item');
        const option = picker.options[picker.selectedIndex];
        const wordId = String(picker.dataset.wordId || '');
        const exampleId = String(picker.value || '');

        if (!wordId || !exampleId) return;

        picker.classList.remove('is-error');
        picker.classList.add('is-saving');
        picker.disabled = true;

        try {
            const body = new URLSearchParams();
            body.set('set_id', String(<?= (int)$id ?>));
            body.set('word_id', wordId);
            body.set('example_id', exampleId);

            const response = await fetch('ajax/update_example.php', {
                method: 'POST',
                headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'},
                body: body.toString()
            });
            const result = await response.json();

            if (!response.ok || !result.success) {
                throw new Error(result.message || 'Could not save Example.');
            }

            if (selectedItem && selectedItem.dataset.wordJson) {
                try {
                    const data = JSON.parse(selectedItem.dataset.wordJson);
                    data.example = option ? String(option.dataset.exampleEn || option.textContent || '') : '';
                    selectedItem.dataset.wordJson = JSON.stringify(data);
                    renderPreview(data, selectedItem);
                } catch (ignore) {}
            }
        } catch (error) {
            picker.classList.add('is-error');
            window.alert(error.message || 'Could not save Example.');
        } finally {
            picker.disabled = false;
            picker.classList.remove('is-saving');
        }
    });

    speakButton.addEventListener('click', function () {
        if (!currentWord || !currentWord.word) return;

        if (currentWord.audio) {
            const audio = new Audio(currentWord.audio);
            audio.play().catch(function () {});
            return;
        }

        if (
            'speechSynthesis' in window
            && 'SpeechSynthesisUtterance' in window
        ) {
            window.speechSynthesis.cancel();

            const utterance = new SpeechSynthesisUtterance(currentWord.word);
            utterance.lang = 'en-US';
            utterance.rate = 0.85;

            window.speechSynthesis.speak(utterance);
        }
    });

    /*
     * Open the first selected word automatically.
     * If the set is empty, preview the first library word.
     */
    window.setTimeout(function () {
        const first =
            selectedWords?.querySelector('.fc-selected-item[data-word-json]')
            || library?.querySelector('.fc-word-item[data-word-json]');

        const data = parseWordData(first);
        if (data) renderPreview(data, first);
    }, 0);
})();
</script>
<?php
$content = ob_get_clean();
require __DIR__ . '/../layouts/app.php';
