<?php
declare(strict_types=1);

/**
 * EnglishSpeak
 * File: teacher/flashcards/ajax/add-word.php
 *
 * Add one existing Word Library item to one reusable Flashcard Set.
 * Keeps the JSON contract used by flashcards.js.
 */

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

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');

function addWordResponse(
    bool $success,
    array $payload = [],
    string $message = '',
    int $statusCode = 200
): never {
    http_response_code($statusCode);

    echo json_encode(
        array_merge(
            [
                'success' => $success,
                'message' => $message,
            ],
            $payload
        ),
        JSON_UNESCAPED_UNICODE
        | JSON_UNESCAPED_SLASHES
        | JSON_INVALID_UTF8_SUBSTITUTE
    );

    exit;
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    addWordResponse(
        false,
        [],
        'Method not allowed.',
        405
    );
}

$setId = filter_input(INPUT_POST, 'set_id', FILTER_VALIDATE_INT);
$wordId = filter_input(INPUT_POST, 'word_id', FILTER_VALIDATE_INT);

if (!$setId || !$wordId) {
    addWordResponse(
        false,
        [],
        'Invalid Flashcard Set or Word.',
        422
    );
}

$pdo = getDbConnection();

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

try {
    $pdo->beginTransaction();

    // Lock the Set so simultaneous requests cannot assign duplicate order numbers.
    $setStmt = $pdo->prepare(
        'SELECT id, created_by_teacher_id
         FROM flashcard_sets
         WHERE id = ?
         LIMIT 1
         FOR UPDATE'
    );
    $setStmt->execute([$setId]);
    $setRow = $setStmt->fetch(PDO::FETCH_ASSOC);

    if (!$setRow) {
        throw new DomainException('Flashcard Set not found.');
    }
    if (!$isAdmin && ($setRow['created_by_teacher_id'] === null || (int)$setRow['created_by_teacher_id'] !== $currentUserId)) {
        throw new DomainException('Bạn không có quyền thay đổi Flashcard Set này.');
    }

    $wordStmt = $pdo->prepare(
        "SELECT
            w.id,
            w.word,
            w.meaning_vi,
            w.phonetic,
            w.image_path,
            w.audio_us_path,
            w.part_of_speech,
            w.difficulty_level,

            (
                SELECT we.example_en
                FROM word_examples we
                WHERE we.word_id = w.id
                  AND we.status = 'active'
                ORDER BY we.sort_order ASC, we.id ASC
                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

         FROM words w
         WHERE w.id = ?
           AND w.status = 'active'
         LIMIT 1
         FOR UPDATE"
    );
    $wordStmt->execute([$wordId]);
    $word = $wordStmt->fetch(PDO::FETCH_ASSOC);

    if (!$word) {
        throw new DomainException('Word not found or inactive.');
    }

    $examplesStmt = $pdo->prepare(
        "SELECT id, example_en, example_vi, sort_order
         FROM word_examples
         WHERE word_id = ?
           AND status = 'active'
         ORDER BY sort_order ASC, id ASC"
    );
    $examplesStmt->execute([$wordId]);
    $wordExamples = $examplesStmt->fetchAll(PDO::FETCH_ASSOC);
    $defaultExampleId = $wordExamples !== [] ? (int)$wordExamples[0]['id'] : null;

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

    $existingStmt = $pdo->prepare(
        'SELECT id, order_no
         FROM flashcard_set_words
         WHERE set_id = ?
           AND word_id = ?
         LIMIT 1
         FOR UPDATE'
    );
    $existingStmt->execute([$setId, $wordId]);
    $existing = $existingStmt->fetch(PDO::FETCH_ASSOC);

    $alreadySelected = (bool)$existing;

    if ($alreadySelected) {
        $orderNo = (int)$existing['order_no'];
    } else {
        $orderStmt = $pdo->prepare(
            'SELECT COALESCE(MAX(order_no), 0) + 1
             FROM flashcard_set_words
             WHERE set_id = ?'
        );
        $orderStmt->execute([$setId]);
        $orderNo = (int)$orderStmt->fetchColumn();

        if ($hasExampleId) {
            $insertStmt = $pdo->prepare(
                'INSERT INTO flashcard_set_words
                    (set_id, word_id, order_no, example_id)
                 VALUES (?, ?, ?, ?)'
            );
            $insertStmt->execute([$setId, $wordId, $orderNo, $defaultExampleId]);
        } else {
            $insertStmt = $pdo->prepare(
                'INSERT INTO flashcard_set_words
                    (set_id, word_id, order_no)
                 VALUES (?, ?, ?)'
            );
            $insertStmt->execute([$setId, $wordId, $orderNo]);
        }
    }

    $countStmt = $pdo->prepare(
        'SELECT COUNT(*)
         FROM flashcard_set_words
         WHERE set_id = ?'
    );
    $countStmt->execute([$setId]);
    $wordCount = (int)$countStmt->fetchColumn();

    $setColumns = $pdo->query(
        'SHOW COLUMNS FROM flashcard_sets'
    )->fetchAll(PDO::FETCH_COLUMN);

    if (in_array('updated_at', $setColumns, true)) {
        $touchStmt = $pdo->prepare(
            'UPDATE flashcard_sets
             SET updated_at = NOW()
             WHERE id = ?'
        );
        $touchStmt->execute([$setId]);
    }

    $pdo->commit();

    addWordResponse(
        true,
        [
            'already_selected' => $alreadySelected,
            'order_no' => $orderNo,
            'word_count' => $wordCount,
            'word' => [
                'id' => (int)$word['id'],
                'word' => (string)$word['word'],
                'meaning' => (string)($word['meaning_vi'] ?? ''),
                'ipa' => (string)($word['phonetic'] ?? ''),
                'image' => !empty($word['image_path'])
                    ? es_url((string)$word['image_path'])
                    : '',
                'audio' => !empty($word['audio_us_path'])
                    ? es_url((string)$word['audio_us_path'])
                    : '',
                'partOfSpeech' => (string)($word['part_of_speech'] ?? ''),
                'level' => !empty($word['difficulty_level'])
                    ? 'Level ' . (int)$word['difficulty_level']
                    : '',
                'example' => (string)($word['example_en'] ?? ''),
                'examples' => array_map(
                    static fn(array $example): array => [
                        'id' => (int)$example['id'],
                        'example_en' => (string)$example['example_en'],
                        'example_vi' => (string)($example['example_vi'] ?? ''),
                    ],
                    $wordExamples
                ),
                'example_id' => $defaultExampleId,
                'topics' => (string)($word['topics'] ?? ''),
            ],
        ],
        $alreadySelected
            ? 'This word is already in the Flashcard Set.'
            : 'Word added successfully.'
    );
} catch (DomainException $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }

    addWordResponse(
        false,
        [],
        $e->getMessage(),
        404
    );
} catch (PDOException $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }

    error_log(
        'EnglishSpeak flashcards/ajax/add-word.php PDO: '
        . $e->getMessage()
    );

    // Covers a possible unique constraint race without exposing SQL details.
    if ((string)$e->getCode() === '23000') {
        addWordResponse(
            false,
            [],
            'This word is already in the Flashcard Set.',
            409
        );
    }

    addWordResponse(
        false,
        [],
        'Unable to add the word.',
        500
    );
} catch (Throwable $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }

    error_log(
        'EnglishSpeak flashcards/ajax/add-word.php: '
        . $e->getMessage()
    );

    addWordResponse(
        false,
        [],
        'Unable to add the word.',
        500
    );
}
