<?php
declare(strict_types=1);

/**
 * EnglishSpeak
 * File: teacher/flashcards/ajax/reorder.php
 *
 * Compatible with:
 * 1. JSON body:
 *    {"set_id": 2, "word_ids": [5, 8, 3]}
 *
 * 2. FormData / POST:
 *    set_id=2
 *    word_ids[]=5
 *    word_ids[]=8
 *    word_ids[]=3
 */

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 reorderJson(
    bool $success,
    string $message = '',
    array $extra = [],
    int $status = 200
): never {
    http_response_code($status);

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

    exit;
}

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

/*
 * Read JSON first.
 * If no valid JSON exists, fall back to normal POST/FormData.
 */
$rawBody = file_get_contents('php://input');
$jsonData = json_decode((string)$rawBody, true);

if (is_array($jsonData)) {
    $input = $jsonData;
} else {
    $input = $_POST;
}

$setId = filter_var(
    $input['set_id'] ?? null,
    FILTER_VALIDATE_INT
);

$wordIds = $input['word_ids'] ?? $input['order'] ?? [];

/*
 * Some JavaScript sends the array as a JSON string in FormData:
 * word_ids = "[5,8,3]"
 */
if (is_string($wordIds)) {
    $decodedIds = json_decode($wordIds, true);

    if (is_array($decodedIds)) {
        $wordIds = $decodedIds;
    } else {
        // Also accept comma-separated values: "5,8,3"
        $wordIds = array_filter(
            array_map('trim', explode(',', $wordIds)),
            static fn(string $value): bool => $value !== ''
        );
    }
}

if (!$setId || !is_array($wordIds)) {
    reorderJson(
        false,
        'Invalid reorder data.',
        [],
        422
    );
}

// Normalize positive integer IDs and remove duplicates while keeping order.
$normalizedIds = [];
$seen = [];

foreach ($wordIds as $wordId) {
    $validId = filter_var($wordId, FILTER_VALIDATE_INT);

    if (!$validId || isset($seen[$validId])) {
        continue;
    }

    $seen[$validId] = true;
    $normalizedIds[] = (int)$validId;
}

$pdo = getDbConnection();

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

try {
    $pdo->beginTransaction();

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

    $currentStmt = $pdo->prepare(
        'SELECT word_id
         FROM flashcard_set_words
         WHERE set_id = ?
         ORDER BY order_no ASC, id ASC
         FOR UPDATE'
    );
    $currentStmt->execute([$setId]);

    $currentIds = array_map(
        'intval',
        $currentStmt->fetchAll(PDO::FETCH_COLUMN)
    );

    // Submitted order must contain exactly all words currently in this Set.
    $submittedSorted = $normalizedIds;
    $currentSorted = $currentIds;

    sort($submittedSorted);
    sort($currentSorted);

    if ($submittedSorted !== $currentSorted) {
        throw new DomainException(
            'The submitted word order does not match this Flashcard Set.'
        );
    }

    $updateStmt = $pdo->prepare(
        'UPDATE flashcard_set_words
         SET order_no = ?
         WHERE set_id = ?
           AND word_id = ?'
    );

    foreach ($normalizedIds as $index => $wordId) {
        $updateStmt->execute([
            $index + 1,
            $setId,
            $wordId,
        ]);
    }

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

    reorderJson(
        true,
        'Word order saved successfully.',
        [
            'word_count' => count($normalizedIds),
            'word_ids' => $normalizedIds,
        ]
    );
} catch (DomainException $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }

    reorderJson(
        false,
        $e->getMessage(),
        [],
        422
    );
} catch (Throwable $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }

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

    reorderJson(
        false,
        'Unable to save the word order.',
        [],
        500
    );
}
