<?php
declare(strict_types=1);

require __DIR__ . '/../partials/auth.php';
require_once __DIR__ . '/../../config/database.php';

$pdo = getDbConnection();
$currentUserId = (int)($_SESSION['user_id'] ?? 0);
$currentUserRole = strtolower(trim((string)($_SESSION['user_role'] ?? $_SESSION['role'] ?? 'teacher')));
$isAdmin = $currentUserRole === 'admin';
$pageTitle = 'Dialogue Sets';
$pageSubtitle = 'Create question-and-answer dialogue practice';
$activeTeacherNav = 'dialogue-sets';

function dsTableExists(PDO $pdo, string $table): bool
{
    $stmt = $pdo->prepare(
        "SELECT COUNT(*) FROM information_schema.TABLES
         WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?"
    );
    $stmt->execute([$table]);
    return (int)$stmt->fetchColumn() > 0;
}

function dsInstall(PDO $pdo): void
{
    if (!dsTableExists($pdo, 'dialogue_sets')) {
        $pdo->exec(
            "CREATE TABLE dialogue_sets (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                created_by_teacher_id BIGINT UNSIGNED NULL,
                title VARCHAR(255) NOT NULL,
                description TEXT NULL,
                status VARCHAR(20) NOT NULL DEFAULT 'active',
                created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                KEY idx_dialogue_sets_status (status),
                KEY idx_dialogue_sets_created_by_teacher_id (created_by_teacher_id)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
        );
    }

    if (!dsTableExists($pdo, 'dialogue_items')) {
        $pdo->exec(
            "CREATE TABLE dialogue_items (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                dialogue_set_id BIGINT UNSIGNED NOT NULL,
                sort_order INT NOT NULL DEFAULT 1,
                speaker_name VARCHAR(80) NOT NULL DEFAULT 'A',
                prompt_text TEXT NOT NULL,
                correct_response TEXT NOT NULL,
                distractor_1 TEXT NULL,
                distractor_2 TEXT NULL,
                distractor_3 TEXT NULL,
                prompt_audio VARCHAR(500) NULL,
                response_audio VARCHAR(500) NULL,
                image_path VARCHAR(500) NULL,
                status VARCHAR(20) NOT NULL DEFAULT 'active',
                created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                KEY idx_dialogue_items_set (dialogue_set_id, sort_order),
                CONSTRAINT fk_dialogue_items_set
                    FOREIGN KEY (dialogue_set_id) REFERENCES dialogue_sets(id)
                    ON DELETE CASCADE
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
        );
    }

    if (!dsTableExists($pdo, 'dialogue_set_books')) {
        $pdo->exec(
            "CREATE TABLE dialogue_set_books (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                dialogue_set_id BIGINT UNSIGNED NOT NULL,
                book_id BIGINT UNSIGNED NOT NULL,
                UNIQUE KEY uq_dialogue_set_book (dialogue_set_id, book_id),
                KEY idx_dialogue_set_books_set (dialogue_set_id),
                KEY idx_dialogue_set_books_book (book_id)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
        );
    }

    if (!dsTableExists($pdo, 'dialogue_set_levels')) {
        $pdo->exec(
            "CREATE TABLE dialogue_set_levels (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                dialogue_set_id BIGINT UNSIGNED NOT NULL,
                level_id BIGINT UNSIGNED NOT NULL,
                UNIQUE KEY uq_dialogue_set_level (dialogue_set_id, level_id),
                KEY idx_dialogue_set_levels_set (dialogue_set_id),
                KEY idx_dialogue_set_levels_level (level_id)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
        );
    }
}

dsInstall($pdo);

/*
 * Current working Book + Level.
 * Admin can use every active Book; Teachers only use assigned Books.
 */
$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
);

$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;
    }
}

$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);
}

$allowedLevelIds = array_map(
    static fn(array $level): int => (int)$level['id'],
    $levels
);
$requestedLevelId = max(0, (int)($_GET['level_id'] ?? 0));
$currentLevelId = in_array($requestedLevelId, $allowedLevelIds, true)
    ? $requestedLevelId
    : ($allowedLevelIds[0] ?? 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;
    }
}

// Backward-compatible support for multiple equally-correct responses.
try {
    $cols = $pdo->query("SHOW COLUMNS FROM dialogue_items LIKE 'accepted_responses'")->fetchAll(PDO::FETCH_ASSOC);
    if ($cols === []) {
        $pdo->exec("ALTER TABLE dialogue_items ADD COLUMN accepted_responses TEXT NULL AFTER correct_response");
    }
} catch (Throwable $e) {
    // Keep the page usable if the DB account cannot alter schema.
}

// Keep a live link to Word Library images so Dialogue always uses the newest image.
try {
    $cols = $pdo->query("SHOW COLUMNS FROM dialogue_items LIKE 'image_word_id'")->fetchAll(PDO::FETCH_ASSOC);
    if ($cols === []) {
        $pdo->exec("ALTER TABLE dialogue_items ADD COLUMN image_word_id BIGINT UNSIGNED NULL AFTER image_path");
    }
} catch (Throwable $e) {
    // Backward compatible: image_path still works if schema alteration is unavailable.
}

function dsGetOwner(PDO $pdo, int $setId): ?int
{
    if ($setId <= 0) return null;
    $stmt = $pdo->prepare('SELECT created_by_teacher_id FROM dialogue_sets WHERE id = ? LIMIT 1');
    $stmt->execute([$setId]);
    $owner = $stmt->fetchColumn();
    return ($owner === false || $owner === null) ? null : (int)$owner;
}

function dsCanManage(PDO $pdo, int $setId, bool $isAdmin, int $currentUserId): bool
{
    if ($isAdmin) return true;
    $owner = dsGetOwner($pdo, $setId);
    return $owner !== null && $owner === $currentUserId;
}

$returnActivityId = max(0, (int)($_GET['return_activity_id'] ?? $_POST['return_activity_id'] ?? 0));
$setId = max(0, (int)($_GET['id'] ?? $_POST['id'] ?? 0));
$editItemId = max(0, (int)($_GET['item_id'] ?? 0));
$message = '';
$messageType = 'success';

function dsNormalizeResponses(array $values): array
{
    $out = [];
    foreach ($values as $value) {
        $value = trim((string)$value);
        if ($value === '') continue;
        $key = mb_strtolower(preg_replace('/\s+/u', ' ', $value));
        if (!isset($out[$key])) $out[$key] = $value;
    }
    return array_values($out);
}

function dsAutoDistractors(string $correct): array
{
    $clean = trim(preg_replace('/\s+/u', ' ', $correct));
    $plain = rtrim($clean, " .!?\t\n\r\0\x0B");
    $candidates = [];

    // Conservative grammar-error patterns; teachers no longer need to type distractors.
    if (preg_match('/^I[’\']m\s+(.+)$/iu', $plain, $m)) {
        $name = trim($m[1]);
        $candidates = ["I $name.", "My name $name.", "Your name is $name."];
    } elseif (preg_match('/^My name is\s+(.+)$/iu', $plain, $m)) {
        $name = trim($m[1]);
        $candidates = ["My name $name.", "I $name.", "Your name is $name."];
    } else {
        $words = preg_split('/\s+/u', $plain, -1, PREG_SPLIT_NO_EMPTY) ?: [];
        if (count($words) >= 3) {
            $a = $words; unset($a[1]); $candidates[] = implode(' ', array_values($a)) . '.';
            $b = $words; [$b[0], $b[1]] = [$b[1], $b[0]]; $candidates[] = implode(' ', $b) . '.';
            $c = $words; array_pop($c); $candidates[] = implode(' ', $c) . '.';
        }
    }

    $correctKey = mb_strtolower(rtrim($plain, '.!?'));
    $out = [];
    foreach ($candidates as $candidate) {
        $candidate = trim($candidate);
        if ($candidate === '') continue;
        if (mb_strtolower(rtrim($candidate, '.!?')) === $correctKey) continue;
        if (!in_array($candidate, $out, true)) $out[] = $candidate;
        if (count($out) === 3) break;
    }
    return array_pad($out, 3, '');
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $action = trim((string)($_POST['action'] ?? ''));

    try {
        // Existing shared/Admin Sets and Sets owned by another Teacher are read-only.
        if ($setId > 0 && in_array($action, ['save_set', 'save_item', 'delete_item', 'move_item', 'delete_set'], true)) {
            if (!dsCanManage($pdo, $setId, $isAdmin, $currentUserId)) {
                http_response_code(403);
                throw new RuntimeException('Bạn không có quyền sửa Dialogue Set này.');
            }
        }
        if ($action === 'save_set') {
            $title = trim((string)($_POST['title'] ?? ''));
            $description = trim((string)($_POST['description'] ?? ''));
            $status = (string)($_POST['status'] ?? 'active') === 'inactive' ? 'inactive' : 'active';

            $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));

            $postedLevelIds = [];
            foreach ((array)($_POST['level_ids'] ?? []) as $bookIdRaw => $levelIdRaw) {
                $bookIdKey = (int)$bookIdRaw;
                $levelIdValue = (int)$levelIdRaw;
                if ($bookIdKey > 0 && $levelIdValue > 0) {
                    $postedLevelIds[$bookIdKey] = $levelIdValue;
                }
            }

            if ($title === '') {
                throw new RuntimeException('Dialogue Set name is required.');
            }
            if ($postedBookIds === []) {
                throw new RuntimeException('Hãy chọn ít nhất 1 sách.');
            }
            if ($currentBookId <= 0 || !in_array($currentBookId, $postedBookIds, true)) {
                throw new RuntimeException('Set phải thuộc sách đang làm việc.');
            }

            $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) {
                    throw new RuntimeException('Mỗi sách được chọn phải có Lớp / Level tương ứng.');
                }
                $validLevelStmt->execute([$postedLevelId, $postedBookId]);
                if (!$validLevelStmt->fetchColumn()) {
                    throw new RuntimeException('Level đã chọn không thuộc đúng sách.');
                }
            }

            $pdo->beginTransaction();
            try {
                if ($setId > 0) {
                    $stmt = $pdo->prepare(
                        'UPDATE dialogue_sets SET title = ?, description = ?, status = ?, updated_at = NOW() WHERE id = ?'
                    );
                    $stmt->execute([$title, $description, $status, $setId]);
                    $message = 'Dialogue Set saved.';
                } else {
                    $stmt = $pdo->prepare(
                        'INSERT INTO dialogue_sets (created_by_teacher_id, title, description, status) VALUES (?, ?, ?, ?)'
                    );
                    $stmt->execute([$isAdmin ? null : $currentUserId, $title, $description, $status]);
                    $setId = (int)$pdo->lastInsertId();
                    $message = 'Dialogue Set created.';
                }

                $pdo->prepare('DELETE FROM dialogue_set_books WHERE dialogue_set_id = ?')->execute([$setId]);
                $insertBook = $pdo->prepare(
                    'INSERT INTO dialogue_set_books (dialogue_set_id, book_id) VALUES (?, ?)'
                );
                foreach ($postedBookIds as $postedBookId) {
                    $insertBook->execute([$setId, $postedBookId]);
                }

                $pdo->prepare('DELETE FROM dialogue_set_levels WHERE dialogue_set_id = ?')->execute([$setId]);
                $insertLevel = $pdo->prepare(
                    'INSERT INTO dialogue_set_levels (dialogue_set_id, level_id) VALUES (?, ?)'
                );
                foreach ($postedBookIds as $postedBookId) {
                    $insertLevel->execute([$setId, (int)$postedLevelIds[$postedBookId]]);
                }

                $pdo->commit();
            } catch (Throwable $saveException) {
                if ($pdo->inTransaction()) $pdo->rollBack();
                throw $saveException;
            }
        }

        if ($action === 'save_item') {
            $itemId = max(0, (int)($_POST['item_id'] ?? 0));
            $speakerName = trim((string)($_POST['speaker_name'] ?? 'A'));
            $promptText = trim((string)($_POST['prompt_text'] ?? ''));
            $correctResponses = dsNormalizeResponses((array)($_POST['correct_responses'] ?? []));
            if ($correctResponses === []) {
                $legacyCorrect = trim((string)($_POST['correct_response'] ?? ''));
                if ($legacyCorrect !== '') $correctResponses = [$legacyCorrect];
            }
            $correctResponse = $correctResponses[0] ?? '';
            $acceptedResponses = array_slice($correctResponses, 1);
            $distractorMode = (string)($_POST['distractor_mode'] ?? 'auto') === 'manual' ? 'manual' : 'auto';
            if ($distractorMode === 'manual') {
                $manualDistractors = dsNormalizeResponses((array)($_POST['manual_distractors'] ?? []));
                $manualDistractors = array_values(array_filter($manualDistractors, static function(string $value) use ($correctResponses): bool {
                    $key = mb_strtolower(rtrim(trim($value), '.!?'));
                    foreach ($correctResponses as $correct) {
                        if ($key === mb_strtolower(rtrim(trim($correct), '.!?'))) return false;
                    }
                    return true;
                }));
                [$d1, $d2, $d3] = array_pad(array_slice($manualDistractors, 0, 3), 3, '');
            } else {
                [$d1, $d2, $d3] = dsAutoDistractors($correctResponse);
            }
            $promptAudio = trim((string)($_POST['prompt_audio'] ?? ''));
            $responseAudio = trim((string)($_POST['response_audio'] ?? ''));
            $imagePath = trim((string)($_POST['image_path'] ?? ''));
            $imageWordId = max(0, (int)($_POST['image_word_id'] ?? 0));

            if ($setId <= 0 || $promptText === '' || $correctResponse === '') {
                throw new RuntimeException('Question and correct response are required.');
            }

            if ($itemId > 0) {
                $stmt = $pdo->prepare(
                    'UPDATE dialogue_items
                     SET speaker_name = ?, prompt_text = ?, correct_response = ?, accepted_responses = ?,
                         distractor_1 = ?, distractor_2 = ?, distractor_3 = ?,
                         prompt_audio = ?, response_audio = ?, image_path = ?, image_word_id = ?, updated_at = NOW()
                     WHERE id = ? AND dialogue_set_id = ?'
                );
                $stmt->execute([
                    $speakerName !== '' ? $speakerName : 'A',
                    $promptText, $correctResponse, json_encode($acceptedResponses, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                    $d1 !== '' ? $d1 : null,
                    $d2 !== '' ? $d2 : null,
                    $d3 !== '' ? $d3 : null,
                    $promptAudio !== '' ? $promptAudio : null,
                    $responseAudio !== '' ? $responseAudio : null,
                    $imagePath !== '' ? $imagePath : null,
                    $imageWordId > 0 ? $imageWordId : null,
                    $itemId, $setId
                ]);
                $message = 'Dialogue turn updated.';
            } else {
                $sortStmt = $pdo->prepare(
                    'SELECT COALESCE(MAX(sort_order), 0) + 1 FROM dialogue_items WHERE dialogue_set_id = ?'
                );
                $sortStmt->execute([$setId]);
                $sortOrder = max(1, (int)$sortStmt->fetchColumn());

                $stmt = $pdo->prepare(
                    'INSERT INTO dialogue_items
                     (dialogue_set_id, sort_order, speaker_name, prompt_text, correct_response, accepted_responses,
                      distractor_1, distractor_2, distractor_3, prompt_audio, response_audio, image_path, image_word_id, status)
                     VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "active")'
                );
                $stmt->execute([
                    $setId, $sortOrder,
                    $speakerName !== '' ? $speakerName : 'A',
                    $promptText, $correctResponse, json_encode($acceptedResponses, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                    $d1 !== '' ? $d1 : null,
                    $d2 !== '' ? $d2 : null,
                    $d3 !== '' ? $d3 : null,
                    $promptAudio !== '' ? $promptAudio : null,
                    $responseAudio !== '' ? $responseAudio : null,
                    $imagePath !== '' ? $imagePath : null,
                    $imageWordId > 0 ? $imageWordId : null
                ]);
                $message = 'Dialogue turn added.';
            }
        }

        if ($action === 'delete_item') {
            $itemId = max(0, (int)($_POST['item_id'] ?? 0));
            if ($setId > 0 && $itemId > 0) {
                $stmt = $pdo->prepare('DELETE FROM dialogue_items WHERE id = ? AND dialogue_set_id = ?');
                $stmt->execute([$itemId, $setId]);
                $message = 'Dialogue turn deleted.';
            }
        }

        if ($action === 'move_item') {
            $itemId = max(0, (int)($_POST['item_id'] ?? 0));
            $direction = (string)($_POST['direction'] ?? 'down');

            $itemsStmt = $pdo->prepare(
                'SELECT id FROM dialogue_items WHERE dialogue_set_id = ? ORDER BY sort_order, id'
            );
            $itemsStmt->execute([$setId]);
            $ids = array_map('intval', $itemsStmt->fetchAll(PDO::FETCH_COLUMN));
            $idx = array_search($itemId, $ids, true);

            if ($idx !== false) {
                $target = $direction === 'up' ? $idx - 1 : $idx + 1;
                if ($target >= 0 && $target < count($ids)) {
                    [$ids[$idx], $ids[$target]] = [$ids[$target], $ids[$idx]];
                }
                $upd = $pdo->prepare('UPDATE dialogue_items SET sort_order = ? WHERE id = ? AND dialogue_set_id = ?');
                foreach ($ids as $i => $id) {
                    $upd->execute([$i + 1, $id, $setId]);
                }
            }
        }

        if ($action === 'delete_set') {
            if ($setId > 0) {
                $pdo->prepare('DELETE FROM dialogue_set_levels WHERE dialogue_set_id = ?')->execute([$setId]);
                $pdo->prepare('DELETE FROM dialogue_set_books WHERE dialogue_set_id = ?')->execute([$setId]);
                $stmt = $pdo->prepare('DELETE FROM dialogue_sets WHERE id = ?');
                $stmt->execute([$setId]);
                header('Location: index.php');
                exit;
            }
        }
    } catch (Throwable $e) {
        $message = $e->getMessage();
        $messageType = 'error';
    }
}

$set = null;
$items = [];
$editItem = null;
$canManageCurrentSet = false;
$linkedBookIds = [];
$linkedLevelIdsByBook = [];

if ($setId > 0) {
    $stmt = $pdo->prepare('SELECT * FROM dialogue_sets WHERE id = ? LIMIT 1');
    $stmt->execute([$setId]);
    $set = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;

    if (!$set) {
        http_response_code(404);
        exit('Dialogue Set not found.');
    }

    $linkedBookStmt = $pdo->prepare(
        'SELECT book_id FROM dialogue_set_books WHERE dialogue_set_id = ? ORDER BY book_id'
    );
    $linkedBookStmt->execute([$setId]);
    $linkedBookIds = array_map('intval', $linkedBookStmt->fetchAll(PDO::FETCH_COLUMN));

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

    $canManageCurrentSet = dsCanManage($pdo, $setId, $isAdmin, $currentUserId);
    if (!$canManageCurrentSet && (int)($_GET['preview'] ?? 0) !== 1) {
        $url = 'index.php?id=' . $setId . '&preview=1';
        if ($returnActivityId > 0) $url .= '&return_activity_id=' . $returnActivityId;
        header('Location: ' . $url);
        exit;
    }

    $stmt = $pdo->prepare(
        'SELECT * FROM dialogue_items WHERE dialogue_set_id = ? ORDER BY sort_order, id'
    );
    $stmt->execute([$setId]);
    $items = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // If a Dialogue image came from Word Library, always use that word's current image_path.
    if (dsTableExists($pdo, 'words')) {
        $imageWordColumn = $pdo->query("SHOW COLUMNS FROM dialogue_items LIKE 'image_word_id'")->fetchAll(PDO::FETCH_ASSOC);
        if ($imageWordColumn !== []) {
            $wordIds = [];
            foreach ($items as $row) {
                $wid = (int)($row['image_word_id'] ?? 0);
                if ($wid > 0) $wordIds[$wid] = $wid;
            }
            if ($wordIds !== []) {
                $ph = implode(',', array_fill(0, count($wordIds), '?'));
                $wst = $pdo->prepare("SELECT id, image_path FROM words WHERE id IN ($ph)");
                $wst->execute(array_values($wordIds));
                $currentImages = [];
                foreach ($wst->fetchAll(PDO::FETCH_ASSOC) as $wr) {
                    $currentImages[(int)$wr['id']] = trim((string)($wr['image_path'] ?? ''));
                }
                foreach ($items as &$row) {
                    $wid = (int)($row['image_word_id'] ?? 0);
                    if ($wid > 0 && !empty($currentImages[$wid])) {
                        $row['image_path'] = $currentImages[$wid];
                    }
                }
                unset($row);
            }
        }
    }

    if ($editItemId > 0) {
        $stmt = $pdo->prepare(
            'SELECT * FROM dialogue_items WHERE id = ? AND dialogue_set_id = ? LIMIT 1'
        );
        $stmt->execute([$editItemId, $setId]);
        $editItem = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;

        if ($editItem && (int)($editItem['image_word_id'] ?? 0) > 0 && dsTableExists($pdo, 'words')) {
            $wst = $pdo->prepare('SELECT image_path FROM words WHERE id = ? LIMIT 1');
            $wst->execute([(int)$editItem['image_word_id']]);
            $currentImage = trim((string)($wst->fetchColumn() ?: ''));
            if ($currentImage !== '') $editItem['image_path'] = $currentImage;
        }
    }
}

if ($setId <= 0 && $linkedBookIds === [] && $currentBookId > 0) {
    $linkedBookIds = [$currentBookId];
}

$setWhere = [];
$setParams = [];
if ($currentBookId > 0) {
    $setWhere[] = "(
        EXISTS (
            SELECT 1 FROM dialogue_set_books dsb_filter
            WHERE dsb_filter.dialogue_set_id = ds.id
              AND dsb_filter.book_id = ?
        )
        OR NOT EXISTS (
            SELECT 1 FROM dialogue_set_books dsb_legacy
            WHERE dsb_legacy.dialogue_set_id = ds.id
        )
    )";
    $setParams[] = $currentBookId;
}
if ($currentLevelId > 0) {
    $setWhere[] = "(
        EXISTS (
            SELECT 1 FROM dialogue_set_levels dsl_filter
            WHERE dsl_filter.dialogue_set_id = ds.id
              AND dsl_filter.level_id = ?
        )
        OR NOT EXISTS (
            SELECT 1 FROM dialogue_set_levels dsl_legacy
            WHERE dsl_legacy.dialogue_set_id = ds.id
        )
    )";
    $setParams[] = $currentLevelId;
}
$setWhereSql = $setWhere !== [] ? 'WHERE ' . implode(' AND ', $setWhere) : '';

$setsStmt = $pdo->prepare(
    "SELECT ds.*,
            (SELECT COUNT(*) FROM dialogue_items di WHERE di.dialogue_set_id = ds.id AND di.status = 'active') AS item_count,
            COALESCE(
                (
                    SELECT GROUP_CONCAT(
                        DISTINCT CONCAT(b.name, ' → ', l.name)
                        ORDER BY b.sort_order, b.name, l.sort_order, l.level_number, l.name
                        SEPARATOR ' · '
                    )
                    FROM dialogue_set_levels dsl_label
                    INNER JOIN levels l ON l.id = dsl_label.level_id
                    INNER JOIN books b ON b.id = l.book_id
                    INNER JOIN dialogue_set_books dsb_label
                            ON dsb_label.dialogue_set_id = dsl_label.dialogue_set_id
                           AND dsb_label.book_id = l.book_id
                    WHERE dsl_label.dialogue_set_id = ds.id
                ),
                ''
            ) AS book_level_pairs
     FROM dialogue_sets ds
     {$setWhereSql}
     ORDER BY ds.updated_at DESC, ds.id DESC"
);
$setsStmt->execute($setParams);
$sets = $setsStmt->fetchAll(PDO::FETCH_ASSOC);

/*
 * Word Library image picker.
 * Reuses Word Library images. image_word_id keeps a live link; image_path remains as fallback.
 */
$wordLibrary = [];
$wordTopics = [];

if (
    dsTableExists($pdo, 'words')
    && dsTableExists($pdo, 'topics')
    && dsTableExists($pdo, 'topic_words')
) {
    try {
        $wordLibrary = $pdo->query(
            "SELECT
                w.id,
                w.word,
                COALESCE(w.image_path, '') AS image_path,
                GROUP_CONCAT(DISTINCT t.name ORDER BY t.name SEPARATOR ', ') AS topic_names,
                GROUP_CONCAT(DISTINCT t.id ORDER BY t.id SEPARATOR ',') AS topic_ids
             FROM words w
             LEFT JOIN topic_words tw ON tw.word_id = w.id
             LEFT JOIN topics t ON t.id = tw.topic_id AND t.status = 'active'
             WHERE w.status = 'active'
               AND COALESCE(TRIM(w.image_path), '') <> ''
             GROUP BY w.id, w.word, w.image_path
             ORDER BY w.word ASC"
        )->fetchAll(PDO::FETCH_ASSOC);

        $wordTopics = $pdo->query(
            "SELECT DISTINCT t.id, t.name
             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'
               AND COALESCE(TRIM(w.image_path), '') <> ''
             ORDER BY t.name ASC"
        )->fetchAll(PDO::FETCH_ASSOC);
    } catch (Throwable $e) {
        $wordLibrary = [];
        $wordTopics = [];
    }
}

function dsImageUrl(string $path): string
{
    $path = trim($path);
    if ($path === '') return '';
    if (preg_match('~^(?:https?:)?//|^data:~i', $path)) return $path;

    $relative = preg_replace('~^/EnglishSpeak/~i', '', $path);
    $relative = preg_replace('~^(?:\.\./)+~', '', (string)$relative);
    $relative = preg_replace('~^EnglishSpeak/~i', '', (string)$relative);
    $relative = ltrim((string)$relative, '/');

    $url = '/EnglishSpeak/' . $relative;
    $file = dirname(__DIR__, 2) . '/' . $relative;
    if (is_file($file)) {
        $url .= '?v=' . (string)filemtime($file);
    }

    return $url;
}

ob_start();
?>
<style>
.ds-page{display:grid;gap:16px;max-width:1180px;margin:0 auto}
.ds-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.ds-kicker{color:#7c3aed;font-size:12px;font-weight:900;text-transform:uppercase;letter-spacing:.08em}
.ds-head h2{margin:4px 0 0;color:#0f172a}
.ds-card{padding:17px;border:1px solid #e5e7eb;border-radius:16px;background:#fff}
.ds-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.ds-field{display:grid;gap:6px}.ds-field-full{grid-column:1/-1}
.ds-field span{font-size:12px;font-weight:800;color:#334155}
.ds-input,.ds-textarea,.ds-select{width:100%;border:1px solid #dbe2ea;border-radius:10px;background:#fff;color:#0f172a;font:inherit}
.ds-input,.ds-select{height:42px;padding:0 11px}.ds-textarea{min-height:84px;padding:10px 11px;resize:vertical}
.ds-actions{display:flex;gap:8px;flex-wrap:wrap}
.ds-toolbar{display:grid;grid-template-columns:minmax(180px,230px) auto;gap:10px;align-items:center}
.ds-book-box{display:grid;gap:9px;padding:13px 14px;border:1px solid #dbeafe;border-radius:12px;background:#f8fbff}
.ds-book-help{color:#64748b;font-size:11px;line-height:1.45}
.ds-book-level-list{display:grid;gap:9px}
.ds-book-level-row{display:grid;grid-template-columns:minmax(190px,1fr) minmax(190px,270px);gap:10px;align-items:center}
.ds-book-option{display:inline-flex;align-items:center;gap:7px;min-height:40px;padding:8px 11px;border:1px solid #dbe2ea;border-radius:10px;background:#fff;color:#334155;font-size:12px;font-weight:800}
.ds-book-option input{margin:0}
.ds-pair{display:inline-flex;align-items:center;margin-top:6px;margin-right:6px;padding:4px 8px;border-radius:999px;background:#eff6ff;color:#1d4ed8;font-size:10px;font-weight:800}
.ds-message{padding:11px 13px;border-radius:11px;font-weight:750}
.ds-message.success{border:1px solid #bbf7d0;background:#ecfdf3;color:#166534}
.ds-message.error{border:1px solid #fecaca;background:#fef2f2;color:#991b1b}
.ds-list{display:grid;gap:9px}
.ds-set-row,.ds-turn{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:center;padding:13px;border:1px solid #e5e7eb;border-radius:13px}
.ds-title{font-weight:900;color:#0f172a}.ds-muted{margin-top:4px;color:#64748b;font-size:12px}
.ds-turn-main{display:grid;gap:6px}.ds-bubble{padding:9px 11px;border-radius:12px;background:#eff6ff;color:#1d4ed8;font-weight:800}
.ds-answer{padding:9px 11px;border-radius:12px;background:#ecfdf3;color:#166534;font-weight:800}
.ds-small{font-size:11px;color:#64748b}
.ds-image-tools{display:grid;gap:8px}
.ds-image-preview{display:none;width:110px;height:110px;object-fit:contain;border:1px solid #dbe2ea;border-radius:14px;background:#f8fafc;padding:5px}
.ds-image-preview.show{display:block}
.ds-picker{position:fixed;z-index:9999;inset:0;display:none;align-items:center;justify-content:center;padding:18px;background:rgba(15,23,42,.42)}
.ds-picker.show{display:flex}
.ds-picker-card{width:min(920px,100%);max-height:86vh;display:flex;flex-direction:column;overflow:hidden;border-radius:18px;background:#fff;box-shadow:0 24px 70px rgba(15,23,42,.25)}
.ds-picker-head{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:15px 16px;border-bottom:1px solid #e5e7eb}
.ds-picker-head h3{margin:0}
.ds-picker-close{width:38px;height:38px;border:0;border-radius:50%;background:#f1f5f9;font-size:22px;cursor:pointer}
.ds-picker-filters{display:grid;grid-template-columns:1fr 220px;gap:10px;padding:12px 16px;border-bottom:1px solid #e5e7eb}
.ds-word-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;padding:14px 16px 18px;overflow:auto}
.ds-word-card{display:grid;gap:7px;padding:8px;border:1px solid #e2e8f0;border-radius:13px;background:#fff;text-align:center;cursor:pointer}
.ds-word-card:hover{border-color:#93c5fd;background:#f8fbff}
.ds-word-card img{width:100%;aspect-ratio:1/1;object-fit:contain;border-radius:9px;background:#f8fafc}
.ds-word-card strong{font-size:13px;color:#0f172a}.ds-word-card small{font-size:10px;color:#64748b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ds-picker-empty{grid-column:1/-1;padding:28px;text-align:center;color:#64748b}
@media(max-width:760px){.ds-book-level-row{grid-template-columns:1fr}.ds-toolbar{grid-template-columns:1fr}.ds-word-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.ds-picker-filters{grid-template-columns:1fr}.ds-grid{grid-template-columns:1fr}.ds-field-full{grid-column:auto}.ds-set-row,.ds-turn{grid-template-columns:1fr}.ds-head{flex-direction:column}}
@media(max-width:480px){.ds-word-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
</style>

<div class="ds-page">
    <div class="ds-head">
        <div>
            <h2><?= $set ? 'Edit Dialogue Set' : 'Dialogue Sets' ?></h2>
            <div class="ds-muted">Create short question-and-answer turns for Dialogue activities.</div>
        </div>
        <div class="ds-actions">
            <?php if ($returnActivityId > 0): ?>
                <a class="button button-secondary" href="../activity-settings/index.php?activity_id=<?= $returnActivityId ?>">← Activity Settings</a>
            <?php endif; ?>
            <?php if (!$set): ?>
                <a class="button button-primary" href="index.php?create=1<?= $currentLevelId > 0 ? '&level_id=' . $currentLevelId : '' ?><?= $returnActivityId > 0 ? '&return_activity_id=' . $returnActivityId : '' ?>">+ Create Dialogue Set</a>
            <?php endif; ?>
            <?php if ($set): ?>
                <a class="button button-secondary" href="index.php<?= $currentLevelId > 0 ? '?level_id=' . $currentLevelId : '' ?>">← List</a>
                <a class="button button-secondary" href="index.php?id=<?= $setId ?>&preview=1<?= $returnActivityId > 0 ? '&return_activity_id=' . $returnActivityId : '' ?>">Student View</a>
                <?php if ($canManageCurrentSet && (int)($_GET['preview'] ?? 0) !== 1): ?>
                    <button class="button button-primary" type="submit" form="dialogueSetForm">Save Changes</button>
                <?php endif; ?>
            <?php endif; ?>
        </div>
    </div>

    <?php if ($message !== ''): ?>
        <div class="ds-message <?= $messageType === 'error' ? 'error' : 'success' ?>"><?= htmlspecialchars($message, ENT_QUOTES, 'UTF-8') ?></div>
    <?php endif; ?>

    <?php if (!$set && (int)($_GET['create'] ?? 0) === 1): ?>
        <section class="ds-card">
            <h3 style="margin-top:0">New Dialogue Set</h3>
            <form method="post" class="ds-grid js-ds-set-form">
                <input type="hidden" name="action" value="save_set">
                <input type="hidden" name="return_activity_id" value="<?= $returnActivityId ?>">
                <label class="ds-field">
                    <span>Set name *</span>
                    <input class="ds-input" name="title" required placeholder="Welcome - Ask & Answer">
                </label>
                <label class="ds-field">
                    <span>Status</span>
                    <select class="ds-select" name="status"><option value="active">Active</option><option value="inactive">Inactive</option></select>
                </label>
                <label class="ds-field ds-field-full">
                    <span>Description</span>
                    <textarea class="ds-textarea" name="description" placeholder="Short greeting dialogue"></textarea>
                </label>
                <div class="ds-field ds-field-full ds-book-box">
                    <span>Sách sử dụng Set này + Lớp / Level *</span>
                    <div class="ds-book-help">Mỗi sách được chọn bắt buộc phải có Level riêng thuộc chính sách đó.</div>
                    <div class="ds-book-level-list">
                        <?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="ds-book-level-row">
                                <label class="ds-book-option">
                                    <input type="checkbox" class="js-ds-book-toggle" name="book_ids[]" value="<?= $bookId ?>" data-book-id="<?= $bookId ?>" <?= $isLinkedBook ? 'checked' : '' ?>>
                                    <span>📘 <?= htmlspecialchars((string)$book['name'], ENT_QUOTES, 'UTF-8') ?></span>
                                </label>
                                <select class="ds-select js-ds-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): ?>
                                        <option value="<?= (int)$level['id'] ?>" <?= $selectedLevelForBook === (int)$level['id'] ? 'selected' : '' ?>><?= htmlspecialchars((string)$level['name'], ENT_QUOTES, 'UTF-8') ?></option>
                                    <?php endforeach; ?>
                                </select>
                            </div>
                        <?php endforeach; ?>
                    </div>
                    <div class="ds-book-help">Một Dialogue Set có thể dùng cho nhiều sách nhưng không được có Book nào thiếu Level.</div>
                </div>
                <div class="ds-actions ds-field-full"><button class="button button-primary" type="submit">Create Dialogue Set</button></div>
            </form>
        </section>
        <div class="ds-actions"><a class="button button-secondary" href="index.php<?= $currentLevelId > 0 ? '?level_id=' . $currentLevelId : '' ?>">← List</a></div>
    <?php endif; ?>

    <?php if (!$set && (int)($_GET['create'] ?? 0) !== 1): ?>
        <section class="ds-card">
            <form method="get" class="ds-toolbar" style="margin-bottom:14px">
                <?php if ($returnActivityId > 0): ?><input type="hidden" name="return_activity_id" value="<?= $returnActivityId ?>"><?php endif; ?>
                <select class="ds-select" name="level_id" onchange="this.form.submit()">
                    <?php foreach ($levels as $level): ?>
                        <option value="<?= (int)$level['id'] ?>" <?= $currentLevelId === (int)$level['id'] ? 'selected' : '' ?>><?= htmlspecialchars((string)$level['name'], ENT_QUOTES, 'UTF-8') ?></option>
                    <?php endforeach; ?>
                </select>
                <span class="ds-muted" style="margin:0">Lọc theo Book đang chọn ở thanh trên + Level.</span>
            </form>
            <h3 style="margin-top:0">Saved Sets</h3>
            <div class="ds-list">
            <?php if ($sets === []): ?>
                <div class="ds-muted">No Dialogue Sets yet.</div>
            <?php else: ?>
                <?php foreach ($sets as $row): ?>
                    <div class="ds-set-row">
                        <div>
                            <div class="ds-title"><?= htmlspecialchars((string)$row['title'], ENT_QUOTES, 'UTF-8') ?></div>
                            <div class="ds-muted"><?= (int)$row['item_count'] ?> turns • <?= htmlspecialchars((string)$row['status'], ENT_QUOTES, 'UTF-8') ?></div>
                            <?php if ((string)$row['book_level_pairs'] !== ''): ?>
                                <div><?php foreach (explode(' · ', (string)$row['book_level_pairs']) as $pair): ?><span class="ds-pair">📘 <?= htmlspecialchars(trim($pair), ENT_QUOTES, 'UTF-8') ?></span><?php endforeach; ?></div>
                            <?php else: ?>
                                <div><span class="ds-pair" style="background:#fff7ed;color:#c2410c">⚠ Chưa gắn Book / Level</span></div>
                            <?php endif; ?>
                        </div>
                        <div class="ds-actions">
                            <?php $canManageRow = $isAdmin || ($row['created_by_teacher_id'] !== null && (int)$row['created_by_teacher_id'] === $currentUserId); ?>
                            <?php if ($canManageRow): ?>
                                <a class="button button-primary" href="index.php?id=<?= (int)$row['id'] ?><?= $returnActivityId > 0 ? '&return_activity_id=' . $returnActivityId : '' ?>">Edit</a>
                            <?php endif; ?>
                            <a class="button button-secondary" href="index.php?id=<?= (int)$row['id'] ?>&preview=1<?= $returnActivityId > 0 ? '&return_activity_id=' . $returnActivityId : '' ?>">Student View</a>
                            <?php if ($canManageRow): ?>
                                <form method="post" onsubmit="return confirm('Delete this Dialogue Set and all turns?');" style="display:inline">
                                    <input type="hidden" name="action" value="delete_set">
                                    <input type="hidden" name="id" value="<?= (int)$row['id'] ?>">
                                    <button class="button button-secondary" type="submit" style="color:#b91c1c">Delete</button>
                                </form>
                            <?php endif; ?>
                        </div>
                    </div>
                <?php endforeach; ?>
            <?php endif; ?>
            </div>
        </section>
    <?php endif; ?>

    <?php if ($set): ?>
        <?php if ((int)($_GET['preview'] ?? 0) === 1): ?>
        <section class="ds-card">
            <div class="ds-head">
                <div>
                    <span class="ds-kicker">Preview</span>
                    <h3 style="margin:4px 0 0"><?= htmlspecialchars((string)$set['title'], ENT_QUOTES, 'UTF-8') ?></h3>
                </div>
                <a class="button button-secondary" href="index.php?id=<?= $setId ?><?= $returnActivityId > 0 ? '&return_activity_id=' . $returnActivityId : '' ?>">Close Preview</a>
            </div>
            <div class="ds-list" style="margin-top:14px">
                <?php if ($items === []): ?>
                    <div class="ds-muted">No dialogue turns yet.</div>
                <?php else: ?>
                    <?php foreach ($items as $index => $item): ?>
                        <div class="ds-turn">
                            <div class="ds-turn-main">
                                <div class="ds-small">Turn <?= $index + 1 ?> • <?= htmlspecialchars((string)$item['speaker_name'], ENT_QUOTES, 'UTF-8') ?></div>
                                <?php if (trim((string)$item['image_path']) !== ''): ?>
                                    <img src="<?= htmlspecialchars(dsImageUrl((string)$item['image_path']), ENT_QUOTES, 'UTF-8') ?>" alt="" style="width:90px;height:90px;object-fit:contain;border-radius:12px;background:#f8fafc">
                                <?php endif; ?>
                                <div class="ds-bubble"><?= htmlspecialchars((string)$item['prompt_text'], ENT_QUOTES, 'UTF-8') ?></div>
                                <div class="ds-answer"><?php $r=[(string)$item['correct_response']]; $x=json_decode((string)($item['accepted_responses'] ?? ''),true); if(is_array($x))$r=array_merge($r,$x); ?><?= htmlspecialchars(implode('  /  ', array_filter($r)), ENT_QUOTES, 'UTF-8') ?></div>
                            </div>
                        </div>
                    <?php endforeach; ?>
                <?php endif; ?>
            </div>
        </section>
        <?php endif; ?>

        <?php if ($canManageCurrentSet): ?>
        <section class="ds-card">
            <form method="post" id="dialogueSetForm" class="ds-grid js-ds-set-form">
                <input type="hidden" name="action" value="save_set">
                <input type="hidden" name="id" value="<?= $setId ?>">
                <input type="hidden" name="return_activity_id" value="<?= $returnActivityId ?>">
                <label class="ds-field">
                    <span>Set name *</span>
                    <input class="ds-input" name="title" required value="<?= htmlspecialchars((string)$set['title'], ENT_QUOTES, 'UTF-8') ?>">
                </label>
                <label class="ds-field">
                    <span>Status</span>
                    <select class="ds-select" name="status">
                        <option value="active" <?= (string)$set['status'] === 'active' ? 'selected' : '' ?>>Active</option>
                        <option value="inactive" <?= (string)$set['status'] === 'inactive' ? 'selected' : '' ?>>Inactive</option>
                    </select>
                </label>
                <label class="ds-field ds-field-full">
                    <span>Description</span>
                    <textarea class="ds-textarea" name="description"><?= htmlspecialchars((string)$set['description'], ENT_QUOTES, 'UTF-8') ?></textarea>
                </label>
                <div class="ds-field ds-field-full ds-book-box">
                    <span>Sách sử dụng Set này + Lớp / Level *</span>
                    <div class="ds-book-help">Mỗi sách được chọn bắt buộc phải có Level riêng thuộc chính sách đó.</div>
                    <div class="ds-book-level-list">
                        <?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="ds-book-level-row">
                                <label class="ds-book-option">
                                    <input type="checkbox" class="js-ds-book-toggle" name="book_ids[]" value="<?= $bookId ?>" data-book-id="<?= $bookId ?>" <?= $isLinkedBook ? 'checked' : '' ?>>
                                    <span>📘 <?= htmlspecialchars((string)$book['name'], ENT_QUOTES, 'UTF-8') ?></span>
                                </label>
                                <select class="ds-select js-ds-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): ?>
                                        <option value="<?= (int)$level['id'] ?>" <?= $selectedLevelForBook === (int)$level['id'] ? 'selected' : '' ?>><?= htmlspecialchars((string)$level['name'], ENT_QUOTES, 'UTF-8') ?></option>
                                    <?php endforeach; ?>
                                </select>
                            </div>
                        <?php endforeach; ?>
                    </div>
                    <div class="ds-book-help">Một Dialogue Set có thể dùng cho nhiều sách nhưng không được có Book nào thiếu Level.</div>
                </div>

            </form>
        </section>

        <section class="ds-card">
            <h3 style="margin-top:0"><?= $editItem ? 'Edit Turn' : 'Add Turn' ?></h3>
            <form method="post" class="ds-grid">
                <input type="hidden" name="action" value="save_item">
                <input type="hidden" name="id" value="<?= $setId ?>">
                <input type="hidden" name="item_id" value="<?= (int)($editItem['id'] ?? 0) ?>">
                <input type="hidden" name="return_activity_id" value="<?= $returnActivityId ?>">

                <label class="ds-field">
                    <span>Speaker</span>
                    <input class="ds-input" name="speaker_name" value="<?= htmlspecialchars((string)($editItem['speaker_name'] ?? 'A'), ENT_QUOTES, 'UTF-8') ?>" placeholder="A">
                </label>
                <label class="ds-field">
                    <span>Image (optional)</span>
                    <div class="ds-image-tools">
                        <input
                            class="ds-input"
                            id="dialogueImagePath"
                            name="image_path"
                            value="<?= htmlspecialchars((string)($editItem['image_path'] ?? ''), ENT_QUOTES, 'UTF-8') ?>"
                            placeholder="uploads/... or choose from Word Library"
                        >
                        <input
                            type="hidden"
                            id="dialogueImageWordId"
                            name="image_word_id"
                            value="<?= (int)($editItem['image_word_id'] ?? 0) ?>"
                        >
                        <div class="ds-actions">
                            <button class="button button-secondary" id="chooseWordImageButton" type="button">Choose from Word Library</button>
                            <button class="button button-secondary" id="clearDialogueImageButton" type="button">Clear</button>
                        </div>
                        <img
                            id="dialogueImagePreview"
                            class="ds-image-preview<?= trim((string)($editItem['image_path'] ?? '')) !== '' ? ' show' : '' ?>"
                            src="<?= htmlspecialchars(dsImageUrl((string)($editItem['image_path'] ?? '')), ENT_QUOTES, 'UTF-8') ?>"
                            alt="Selected image"
                        >
                    </div>
                </label>
                <label class="ds-field ds-field-full">
                    <span>Question / Prompt *</span>
                    <textarea class="ds-textarea" name="prompt_text" required placeholder="What is your name?"><?= htmlspecialchars((string)($editItem['prompt_text'] ?? ''), ENT_QUOTES, 'UTF-8') ?></textarea>
                </label>
                <?php
                $editAccepted = [];
                if ($editItem) {
                    $editAccepted[] = (string)($editItem['correct_response'] ?? '');
                    $extra = json_decode((string)($editItem['accepted_responses'] ?? ''), true);
                    if (is_array($extra)) $editAccepted = array_merge($editAccepted, $extra);
                }
                if ($editAccepted === []) $editAccepted = ['', ''];
                if (count($editAccepted) < 2) $editAccepted[] = '';
                ?>
                <div class="ds-field ds-field-full">
                    <span>Correct responses *</span>
                    <div id="correctResponses" style="display:grid;gap:8px">
                        <?php foreach ($editAccepted as $i => $response): ?>
                            <input class="ds-input" name="correct_responses[]" <?= $i === 0 ? 'required' : '' ?> value="<?= htmlspecialchars((string)$response, ENT_QUOTES, 'UTF-8') ?>" placeholder="<?= $i === 0 ? "I'm Mike." : 'My name is Mike.' ?>">
                        <?php endforeach; ?>
                    </div>
                    <div class="ds-actions" style="margin-top:8px"><button class="button button-secondary" id="addCorrectResponse" type="button">+ Add response</button></div>
                    <div class="ds-muted">All responses are equally correct. Ask & Answer should score against every response and use the highest score.</div>
                </div>
                <?php
                $savedDistractors = [
                    trim((string)($editItem['distractor_1'] ?? '')),
                    trim((string)($editItem['distractor_2'] ?? '')),
                    trim((string)($editItem['distractor_3'] ?? '')),
                ];
                $hasSavedDistractors = count(array_filter($savedDistractors, static fn(string $v): bool => $v !== '')) > 0;
                ?>
                <div class="ds-field ds-field-full">
                    <span>Wrong choices</span>
                    <div class="ds-actions" style="margin-top:4px">
                        <label class="ds-book-option" style="min-height:auto">
                            <input type="radio" name="distractor_mode" value="auto" <?= !$hasSavedDistractors ? 'checked' : '' ?>>
                            <span>Auto generate</span>
                        </label>
                        <label class="ds-book-option" style="min-height:auto">
                            <input type="radio" name="distractor_mode" value="manual" <?= $hasSavedDistractors ? 'checked' : '' ?>>
                            <span>Manual</span>
                        </label>
                    </div>
                    <div id="manualDistractorFields" style="display:<?= $hasSavedDistractors ? 'grid' : 'none' ?>;gap:8px;margin-top:8px">
                        <?php for ($di = 0; $di < 3; $di++): ?>
                            <input class="ds-input" name="manual_distractors[]" value="<?= htmlspecialchars($savedDistractors[$di], ENT_QUOTES, 'UTF-8') ?>" placeholder="Wrong choice <?= $di + 1 ?>">
                        <?php endfor; ?>
                    </div>
                    <div class="ds-muted" id="distractorHelp"><?= $hasSavedDistractors ? 'Manual wrong choices will be kept when you save.' : 'Generated automatically when you save the turn.' ?></div>
                </div>
                <label class="ds-field"><span>Prompt audio path (optional)</span><input class="ds-input" name="prompt_audio" value="<?= htmlspecialchars((string)($editItem['prompt_audio'] ?? ''), ENT_QUOTES, 'UTF-8') ?>"></label>
                <label class="ds-field"><span>Response audio path (optional)</span><input class="ds-input" name="response_audio" value="<?= htmlspecialchars((string)($editItem['response_audio'] ?? ''), ENT_QUOTES, 'UTF-8') ?>"></label>

                <div class="ds-actions ds-field-full">
                    <button class="button button-primary" type="submit"><?= $editItem ? 'Save Turn' : 'Add Turn' ?></button>
                    <?php if ($editItem): ?>
                        <a class="button button-secondary" href="index.php?id=<?= $setId ?><?= $returnActivityId > 0 ? '&return_activity_id=' . $returnActivityId : '' ?>">Cancel Edit</a>
                    <?php endif; ?>
                </div>
            </form>
        </section>

        <section class="ds-card">
            <h3 style="margin-top:0">Dialogue Turns</h3>
            <div class="ds-list">
            <?php if ($items === []): ?>
                <div class="ds-muted">Add the first question-and-answer turn above.</div>
            <?php else: ?>
                <?php foreach ($items as $index => $item): ?>
                    <div class="ds-turn">
                        <div class="ds-turn-main">
                            <div class="ds-small">Turn <?= $index + 1 ?> • <?= htmlspecialchars((string)$item['speaker_name'], ENT_QUOTES, 'UTF-8') ?></div>
                            <div class="ds-bubble"><?= htmlspecialchars((string)$item['prompt_text'], ENT_QUOTES, 'UTF-8') ?></div>
                            <div class="ds-answer">✓ <?php $r=[(string)$item['correct_response']]; $x=json_decode((string)($item['accepted_responses'] ?? ''),true); if(is_array($x))$r=array_merge($r,$x); ?><?= htmlspecialchars(implode('  /  ', array_filter($r)), ENT_QUOTES, 'UTF-8') ?></div>
                        </div>
                        <div class="ds-actions">
                            <form method="post"><input type="hidden" name="action" value="move_item"><input type="hidden" name="id" value="<?= $setId ?>"><input type="hidden" name="item_id" value="<?= (int)$item['id'] ?>"><input type="hidden" name="direction" value="up"><button class="button button-sm button-secondary" type="submit">↑</button></form>
                            <form method="post"><input type="hidden" name="action" value="move_item"><input type="hidden" name="id" value="<?= $setId ?>"><input type="hidden" name="item_id" value="<?= (int)$item['id'] ?>"><input type="hidden" name="direction" value="down"><button class="button button-sm button-secondary" type="submit">↓</button></form>
                            <a class="button button-sm button-secondary" href="index.php?id=<?= $setId ?>&item_id=<?= (int)$item['id'] ?><?= $returnActivityId > 0 ? '&return_activity_id=' . $returnActivityId : '' ?>">Edit</a>
                            <form method="post" onsubmit="return confirm('Delete this dialogue turn?');"><input type="hidden" name="action" value="delete_item"><input type="hidden" name="id" value="<?= $setId ?>"><input type="hidden" name="item_id" value="<?= (int)$item['id'] ?>"><button class="button button-sm button-secondary" type="submit" style="color:#b91c1c">Delete</button></form>
                        </div>
                    </div>
                <?php endforeach; ?>
            <?php endif; ?>
            </div>
        </section>

        <section class="ds-card">
            <div class="ds-actions">
                <?php if ($returnActivityId > 0): ?>
                    <a class="button button-primary" href="../activity-settings/index.php?activity_id=<?= $returnActivityId ?>">Use in Activity Settings</a>
                <?php endif; ?>
                <form method="post" onsubmit="return confirm('Delete this Dialogue Set and all turns?');">
                    <input type="hidden" name="action" value="delete_set">
                    <input type="hidden" name="id" value="<?= $setId ?>">
                    <button class="button button-secondary" type="submit" style="color:#b91c1c">Delete Set</button>
                </form>
            </div>
        </section>
        <?php endif; ?>
    <?php endif; ?>
</div>

<div class="ds-picker" id="wordImagePicker" aria-hidden="true">
    <div class="ds-picker-card" role="dialog" aria-modal="true" aria-labelledby="wordImagePickerTitle">
        <div class="ds-picker-head">
            <div>
                <h3 id="wordImagePickerTitle">Choose from Word Library</h3>
                <div class="ds-muted">Choose a word to reuse its image.</div>
            </div>
            <button class="ds-picker-close" id="closeWordImagePicker" type="button" aria-label="Close">×</button>
        </div>
        <div class="ds-picker-filters">
            <input class="ds-input" id="wordImageSearch" type="search" placeholder="Search word...">
            <select class="ds-select" id="wordImageTopic">
                <option value="">All Topics</option>
                <?php foreach ($wordTopics as $topic): ?>
                    <option value="<?= (int)$topic['id'] ?>"><?= htmlspecialchars((string)$topic['name'], ENT_QUOTES, 'UTF-8') ?></option>
                <?php endforeach; ?>
            </select>
        </div>
        <div class="ds-word-grid" id="wordImageGrid">
            <?php if ($wordLibrary === []): ?>
                <div class="ds-picker-empty">No Word Library images found.</div>
            <?php else: ?>
                <?php foreach ($wordLibrary as $word): ?>
                    <?php
                    $topicIds = array_values(array_filter(array_map('intval', explode(',', (string)($word['topic_ids'] ?? '')))));
                    $imagePath = trim((string)$word['image_path']);
                    ?>
                    <button
                        class="ds-word-card"
                        type="button"
                        data-word="<?= htmlspecialchars(mb_strtolower((string)$word['word']), ENT_QUOTES, 'UTF-8') ?>"
                        data-topic-ids="<?= htmlspecialchars(implode(',', $topicIds), ENT_QUOTES, 'UTF-8') ?>"
                        data-word-id="<?= (int)$word['id'] ?>"
                        data-image="<?= htmlspecialchars($imagePath, ENT_QUOTES, 'UTF-8') ?>"
                        data-image-url="<?= htmlspecialchars(dsImageUrl($imagePath), ENT_QUOTES, 'UTF-8') ?>"
                    >
                        <img src="<?= htmlspecialchars(dsImageUrl($imagePath), ENT_QUOTES, 'UTF-8') ?>" alt="<?= htmlspecialchars((string)$word['word'], ENT_QUOTES, 'UTF-8') ?>">
                        <strong><?= htmlspecialchars((string)$word['word'], ENT_QUOTES, 'UTF-8') ?></strong>
                        <small><?= htmlspecialchars((string)($word['topic_names'] ?? ''), ENT_QUOTES, 'UTF-8') ?></small>
                    </button>
                <?php endforeach; ?>
            <?php endif; ?>
        </div>
    </div>
</div>

<script>
(function(){
'use strict';
document.querySelectorAll('.js-ds-set-form').forEach(function(form){
    const toggles=Array.from(form.querySelectorAll('.js-ds-book-toggle'));
    function sync(toggle){
        const bookId=toggle.dataset.bookId||'';
        const select=form.querySelector('.js-ds-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){sync(toggle);toggle.addEventListener('change',function(){sync(toggle);});});
    form.addEventListener('submit',function(event){
        const selected=toggles.filter(function(toggle){return toggle.checked;});
        if(selected.length===0){event.preventDefault();alert('Hãy chọn ít nhất 1 sách.');return;}
        for(const toggle of selected){
            const select=form.querySelector('.js-ds-book-level[data-book-id="'+(toggle.dataset.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>

<script>
(function () {
    const picker = document.getElementById('wordImagePicker');
    const openButton = document.getElementById('chooseWordImageButton');
    const closeButton = document.getElementById('closeWordImagePicker');
    const clearButton = document.getElementById('clearDialogueImageButton');
    const pathInput = document.getElementById('dialogueImagePath');
    const wordIdInput = document.getElementById('dialogueImageWordId');
    const preview = document.getElementById('dialogueImagePreview');
    const search = document.getElementById('wordImageSearch');
    const topic = document.getElementById('wordImageTopic');
    const cards = Array.from(document.querySelectorAll('.ds-word-card'));
    const addCorrectResponse = document.getElementById('addCorrectResponse');
    const correctResponses = document.getElementById('correctResponses');

    addCorrectResponse?.addEventListener('click', () => {
        if (!correctResponses) return;
        const input = document.createElement('input');
        input.className = 'ds-input';
        input.name = 'correct_responses[]';
        input.placeholder = 'Another correct response';
        correctResponses.appendChild(input);
        input.focus();
    });

    if (!picker || !pathInput) return;

    function showPicker() {
        picker.classList.add('show');
        picker.setAttribute('aria-hidden', 'false');
        if (search) {
            search.value = '';
            filterCards();
            setTimeout(() => search.focus(), 50);
        }
    }

    function hidePicker() {
        picker.classList.remove('show');
        picker.setAttribute('aria-hidden', 'true');
    }

    function imageUrl(path) {
        let value = String(path || '').trim();
        if (value === '') return '';
        if (/^(?:https?:)?\/\//i.test(value) || /^data:/i.test(value) || value.startsWith('/')) return value;
        value = value.replace(/^(?:\.\.\/)+/, '').replace(/^EnglishSpeak\//i, '');
        return '/EnglishSpeak/' + value.replace(/^\/+/, '');
    }

    function updatePreview(path) {
        const value = imageUrl(path);
        if (!preview) return;
        if (value === '') {
            preview.removeAttribute('src');
            preview.classList.remove('show');
            return;
        }
        preview.src = value;
        preview.classList.add('show');
    }

    function filterCards() {
        const q = String(search?.value || '').trim().toLowerCase();
        const topicId = String(topic?.value || '').trim();

        cards.forEach(card => {
            const word = String(card.dataset.word || '');
            const topicIds = String(card.dataset.topicIds || '').split(',').filter(Boolean);
            const matchesSearch = q === '' || word.includes(q);
            const matchesTopic = topicId === '' || topicIds.includes(topicId);
            card.style.display = matchesSearch && matchesTopic ? 'grid' : 'none';
        });
    }

    openButton?.addEventListener('click', showPicker);
    closeButton?.addEventListener('click', hidePicker);
    picker.addEventListener('click', event => {
        if (event.target === picker) hidePicker();
    });
    document.addEventListener('keydown', event => {
        if (event.key === 'Escape' && picker.classList.contains('show')) hidePicker();
    });

    search?.addEventListener('input', filterCards);
    topic?.addEventListener('change', filterCards);

    cards.forEach(card => {
        card.addEventListener('click', () => {
            const path = String(card.dataset.image || '').trim();
            const wordId = String(card.dataset.wordId || '').trim();
            pathInput.value = path;
            if (wordIdInput) wordIdInput.value = wordId;
            updatePreview(path);
            hidePicker();
        });
    });

    clearButton?.addEventListener('click', () => {
        pathInput.value = '';
        if (wordIdInput) wordIdInput.value = '0';
        updatePreview('');
    });

    pathInput.addEventListener('input', () => {
        if (wordIdInput) wordIdInput.value = '0';
        updatePreview(pathInput.value);
    });
})();

(function(){
    const radios = document.querySelectorAll('input[name="distractor_mode"]');
    const fields = document.getElementById('manualDistractorFields');
    const help = document.getElementById('distractorHelp');
    if (!radios.length || !fields) return;
    function syncDistractorMode(){
        const selected = document.querySelector('input[name="distractor_mode"]:checked');
        const manual = selected && selected.value === 'manual';
        fields.style.display = manual ? 'grid' : 'none';
        if (help) help.textContent = manual ? 'Enter up to 3 wrong choices. Manual choices will not be overwritten.' : 'Generated automatically when you save the turn.';
    }
    radios.forEach(r => r.addEventListener('change', syncDistractorMode));
    syncDistractorMode();
})();
</script>

<?php
$content = ob_get_clean();
require __DIR__ . '/../layouts/app.php';
