grthtrhthjhtyjytjytkergtrhtrjytjerhrfh<?php
/**
 * BrightBrains Sorbit Academy - Master REST API Router and Controller
 * This single file handles all endpoints, mapping them cleanly to MySQL tables using PDO.
 */

require_once __DIR__ . '/db_connect.php';
require_once __DIR__ . '/config.php';

// Get request method
$method = $_SERVER['REQUEST_METHOD'];

// Parse route from URL rewrite (e.g. "quizzes/q-1" or "auth/login")
$route = isset($_GET['_route']) ? trim($_GET['_route'], '/') : '';

// -----------------------------------------------------------------
// Helper to parse path variables
// e.g., matchPath("quizzes/{id}", $route) -> returns ['id' => 'q-1']
// -----------------------------------------------------------------
function matchPath($pattern, $route) {
    $patternParts = explode('/', trim($pattern, '/'));
    $routeParts = explode('/', trim($route, '/'));
    
    if (count($patternParts) !== count($routeParts)) {
        return false;
    }
    
    $params = [];
    for ($i = 0; $i < count($patternParts); $i++) {
        if (preg_match('/^\{([a-zA-Z0-9_]+)\}$/', $patternParts[$i], $matches)) {
            $params[$matches[1]] = $routeParts[$i];
        } elseif ($patternParts[$i] !== $routeParts[$i]) {
            return false;
        }
    }
    return $params;
}

// =================================================================
// 1. TEACHER AUTHENTICATION
// =================================================================

// POST auth/login
if ($route === 'auth/login' && $method === 'POST') {
    $data = getInputData();
    $email = isset($data['email']) ? trim($data['email']) : '';
    $password = isset($data['password']) ? trim($data['password']) : '';

    if (empty($email) || empty($password)) {
        sendJSON(['error' => 'Email and password are required.'], 400);
    }

    $stmt = $pdo->prepare("SELECT * FROM teachers WHERE LOWER(email) = LOWER(:email)");
    $stmt->execute([':email' => $email]);
    $teacher = $stmt->fetch();

    if ($teacher && $teacher['passwordHash'] === hashPassword($password)) {
        addAuditLog($pdo, $teacher['id'], $teacher['name'], "LOGIN_SUCCESS", "Teacher logged in successfully via PHP backend.");
        sendJSON([
            'token' => 'mock-teacher-token-' . $teacher['id'],
            'teacher' => [
                'id' => $teacher['id'],
                'email' => $teacher['email'],
                'name' => $teacher['name']
            ]
        ]);
    }

    sendJSON(['error' => 'Invalid email or password.'], 401);
}

// POST auth/forgot-password
if ($route === 'auth/forgot-password' && $method === 'POST') {
    $data = getInputData();
    $email = isset($data['email']) ? trim($data['email']) : '';

    if (empty($email)) {
        sendJSON(['error' => 'Email is required.'], 400);
    }

    addAuditLog($pdo, "system", "System Engine", "PASSWORD_RESET_REQ", "Password reset requested for: " . $email);
    sendJSON(['message' => 'Password reset instructions have been simulated in system audit logs.']);
}

// =================================================================
// 2. SYSTEM SETTINGS
// =================================================================

// GET settings & POST settings
if ($route === 'settings') {
    if ($method === 'GET') {
        $stmt = $pdo->query("SELECT * FROM settings LIMIT 1");
        $settings = $stmt->fetch();
        if (!$settings) {
            $settings = [
                'institutionName' => 'Sorbit Academy',
                'institutionLogo' => null,
                'primaryColor' => '#0f172a',
                'secondaryColor' => '#3b82f6',
                'timezone' => 'UTC'
            ];
        }
        // Structure emailSettings to match frontend type
        $settings['emailSettings'] = [
            'host' => isset($settings['smtp_host']) ? $settings['smtp_host'] : 'smtp.sorbitacademy.pk',
            'port' => isset($settings['smtp_port']) ? (int)$settings['smtp_port'] : 587,
            'user' => isset($settings['smtp_user']) ? $settings['smtp_user'] : 'notifications@sorbitacademy.pk'
        ];
        sendJSON($settings);
    } 
    elseif ($method === 'POST') {
        $teacher = authenticateTeacher($pdo);
        $data = getInputData();
        
        // Ensure settings row exists
        $count = $pdo->query("SELECT COUNT(*) FROM settings")->fetchColumn();
        if ($count == 0) {
            $pdo->query("INSERT INTO settings (institutionName) VALUES ('Sorbit Academy')");
        }

        $stmt = $pdo->prepare("UPDATE settings SET 
            institutionName = :name, 
            institutionLogo = :logo, 
            primaryColor = :primary, 
            secondaryColor = :secondary, 
            timezone = :timezone,
            smtp_host = :smtp_host,
            smtp_port = :smtp_port,
            smtp_user = :smtp_user
        ");
        
        $emailSettings = isset($data['emailSettings']) ? $data['emailSettings'] : [];

        $stmt->execute([
            ':name' => isset($data['institutionName']) ? $data['institutionName'] : 'Sorbit Academy',
            ':logo' => isset($data['institutionLogo']) ? $data['institutionLogo'] : null,
            ':primary' => isset($data['primaryColor']) ? $data['primaryColor'] : '#0f172a',
            ':secondary' => isset($data['secondaryColor']) ? $data['secondaryColor'] : '#3b82f6',
            ':timezone' => isset($data['timezone']) ? $data['timezone'] : 'UTC',
            ':smtp_host' => isset($emailSettings['host']) ? $emailSettings['host'] : null,
            ':smtp_port' => isset($emailSettings['port']) ? (int)$emailSettings['port'] : 587,
            ':smtp_user' => isset($emailSettings['user']) ? $emailSettings['user'] : null
        ]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "SETTINGS_UPDATE", "System institution settings updated.");
        
        // Fetch and return updated settings
        $updated = $pdo->query("SELECT * FROM settings LIMIT 1")->fetch();
        $updated['emailSettings'] = [
            'host' => $updated['smtp_host'],
            'port' => (int)$updated['smtp_port'],
            'user' => $updated['smtp_user']
        ];
        sendJSON($updated);
    }
}

// =================================================================
// 3. QUIZ MANAGEMENT
// =================================================================

// GET quizzes & POST quizzes
if ($route === 'quizzes') {
    if ($method === 'GET') {
        $headers = apache_request_headers();
        $authHeader = isset($headers['Authorization']) ? $headers['Authorization'] : '';
        if (empty($authHeader) && isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $authHeader = $_SERVER['HTTP_AUTHORIZATION'];
        }

        $isTeacher = preg_match('/Bearer\s+mock-teacher-token-/', $authHeader);

        if ($isTeacher) {
            $stmt = $pdo->query("SELECT * FROM quizzes ORDER BY startDate DESC");
            $quizzes = $stmt->fetchAll();
        } else {
            $stmt = $pdo->query("SELECT * FROM quizzes WHERE status = 'published' ORDER BY startDate DESC");
            $quizzes = $stmt->fetchAll();
        }

        // Format boolean and JSON values for client
        foreach ($quizzes as &$q) {
            $q['negativeMarking'] = (bool)$q['negativeMarking'];
            $q['shuffleQuestions'] = (bool)$q['shuffleQuestions'];
            $q['shuffleOptions'] = (bool)$q['shuffleOptions'];
            $q['showResultImmediately'] = (bool)$q['showResultImmediately'];
            $q['showCorrectAnswers'] = (bool)$q['showCorrectAnswers'];
            $q['allowReview'] = (bool)$q['allowReview'];
            $q['allowMultipleAttempts'] = (bool)$q['allowMultipleAttempts'];
            $q['isCombined'] = (bool)$q['isCombined'];
            $q['combinedFrom'] = json_decode($q['combinedFrom'] ?: '[]');
        }

        sendJSON($quizzes);
    } 
    elseif ($method === 'POST') {
        $teacher = authenticateTeacher($pdo);
        $data = getInputData();

        if (empty($data['title'])) {
            sendJSON(['error' => 'Quiz title is required.'], 400);
        }

        $quizId = 'q-' . uniqid();
        $stmt = $pdo->prepare("INSERT INTO quizzes (
            id, title, description, instructions, subject, course, teacherName, teacherId,
            duration, passingPercentage, maxMarks, negativeMarking, shuffleQuestions, shuffleOptions,
            showResultImmediately, showCorrectAnswers, allowReview, allowMultipleAttempts,
            startDate, endDate, password, status, isCombined, combinedFrom, calculatorType
        ) VALUES (
            :id, :title, :description, :instructions, :subject, :course, :teacherName, :teacherId,
            :duration, :passingPercentage, :maxMarks, :negativeMarking, :shuffleQuestions, :shuffleOptions,
            :showResultImmediately, :showCorrectAnswers, :allowReview, :allowMultipleAttempts,
            :startDate, :endDate, :password, :status, :isCombined, :combinedFrom, :calculatorType
        )");

        $stmt->execute([
            ':id' => $quizId,
            ':title' => $data['title'],
            ':description' => isset($data['description']) ? $data['description'] : '',
            ':instructions' => isset($data['instructions']) ? $data['instructions'] : '',
            ':subject' => isset($data['subject']) ? $data['subject'] : 'General',
            ':course' => isset($data['course']) ? $data['course'] : '',
            ':teacherName' => $teacher['name'],
            ':teacherId' => $teacher['id'],
            ':duration' => isset($data['duration']) ? (int)$data['duration'] : 30,
            ':passingPercentage' => isset($data['passingPercentage']) ? (int)$data['passingPercentage'] : 50,
            ':maxMarks' => isset($data['maxMarks']) ? (int)$data['maxMarks'] : 0,
            ':negativeMarking' => isset($data['negativeMarking']) ? (int)$data['negativeMarking'] : 0,
            ':shuffleQuestions' => isset($data['shuffleQuestions']) ? (int)$data['shuffleQuestions'] : 0,
            ':shuffleOptions' => isset($data['shuffleOptions']) ? (int)$data['shuffleOptions'] : 0,
            ':showResultImmediately' => isset($data['showResultImmediately']) ? (int)$data['showResultImmediately'] : 1,
            ':showCorrectAnswers' => isset($data['showCorrectAnswers']) ? (int)$data['showCorrectAnswers'] : 1,
            ':allowReview' => isset($data['allowReview']) ? (int)$data['allowReview'] : 1,
            ':allowMultipleAttempts' => isset($data['allowMultipleAttempts']) ? (int)$data['allowMultipleAttempts'] : 1,
            ':startDate' => isset($data['startDate']) ? $data['startDate'] : gmdate("Y-m-d\TH:i:s.000\Z"),
            ':endDate' => isset($data['endDate']) ? $data['endDate'] : gmdate("Y-m-d\TH:i:s.000\Z", strtotime('+7 days')),
            ':password' => !empty($data['password']) ? trim($data['password']) : null,
            ':status' => isset($data['status']) ? $data['status'] : 'draft',
            ':isCombined' => isset($data['isCombined']) ? (int)$data['isCombined'] : 0,
            ':combinedFrom' => json_encode(isset($data['combinedFrom']) ? $data['combinedFrom'] : []),
            ':calculatorType' => isset($data['calculatorType']) ? $data['calculatorType'] : 'none'
        ]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "QUIZ_CREATE", "Created quiz: " . $data['title']);

        // Return newly created quiz structured properly
        $stmtQuiz = $pdo->prepare("SELECT * FROM quizzes WHERE id = :id");
        $stmtQuiz->execute([':id' => $quizId]);
        $quiz = $stmtQuiz->fetch();
        $quiz['negativeMarking'] = (bool)$quiz['negativeMarking'];
        $quiz['shuffleQuestions'] = (bool)$quiz['shuffleQuestions'];
        $quiz['shuffleOptions'] = (bool)$quiz['shuffleOptions'];
        $quiz['showResultImmediately'] = (bool)$quiz['showResultImmediately'];
        $quiz['showCorrectAnswers'] = (bool)$quiz['showCorrectAnswers'];
        $quiz['allowReview'] = (bool)$quiz['allowReview'];
        $quiz['allowMultipleAttempts'] = (bool)$quiz['allowMultipleAttempts'];
        $quiz['isCombined'] = (bool)$quiz['isCombined'];
        $quiz['combinedFrom'] = json_decode($quiz['combinedFrom'] ?: '[]');

        sendJSON($quiz, 210);
    }
}

// POST quizzes/combine (Combine multiple quizzes)
if ($route === 'quizzes/combine' && $method === 'POST') {
    $teacher = authenticateTeacher($pdo);
    if ($teacher['id'] !== 't-1') {
        sendJSON(['error' => 'Only the administrator/director can combine quizzes.'], 403);
    }

    $data = getInputData();
    $title = isset($data['title']) ? trim($data['title']) : '';
    $duration = isset($data['duration']) ? (int)$data['duration'] : 0;
    $className = isset($data['className']) ? trim($data['className']) : '';
    $selectedQuizIds = isset($data['selectedQuizIds']) ? $data['selectedQuizIds'] : [];

    if (empty($title) || $duration <= 0 || empty($className) || empty($selectedQuizIds)) {
        sendJSON(['error' => 'Missing fields: title, duration, className, and selectedQuizIds are required.'], 400);
    }

    // Combine logic: Fetch selected quizzes to combine
    $inClause = implode(',', array_fill(0, count($selectedQuizIds), '?'));
    $stmt = $pdo->prepare("SELECT * FROM quizzes WHERE id IN ($inClause)");
    $stmt->execute($selectedQuizIds);
    $parentQuizzes = $stmt->fetchAll();

    if (count($parentQuizzes) === 0) {
        sendJSON(['error' => 'No valid quizzes found to combine.'], 400);
    }

    // Insert new combined quiz
    $newQuizId = 'q-' . uniqid();
    $stmtInsert = $pdo->prepare("INSERT INTO quizzes (
        id, title, description, instructions, subject, course, teacherName, teacherId,
        duration, passingPercentage, maxMarks, negativeMarking, shuffleQuestions, shuffleOptions,
        showResultImmediately, showCorrectAnswers, allowReview, allowMultipleAttempts,
        startDate, endDate, status, isCombined, combinedFrom, calculatorType
    ) VALUES (
        :id, :title, :description, :instructions, :subject, :course, :teacherName, :teacherId,
        :duration, :passingPercentage, :maxMarks, :negativeMarking, :shuffleQuestions, :shuffleOptions,
        :showResultImmediately, :showCorrectAnswers, :allowReview, :allowMultipleAttempts,
        :startDate, :endDate, :status, 1, :combinedFrom, 'none'
    )");

    $stmtInsert->execute([
        ':id' => $newQuizId,
        ':title' => $title,
        ':description' => 'Combined multi-subject quiz for class ' . $className,
        ':instructions' => 'This is a combined examination. Answer questions carefully.',
        ':subject' => 'Combined Subjects',
        ':course' => $className,
        ':teacherName' => $teacher['name'],
        ':teacherId' => $teacher['id'],
        ':duration' => $duration,
        ':passingPercentage' => 50,
        ':maxMarks' => 0, // Calculated later from imported questions
        ':negativeMarking' => 0,
        ':shuffleQuestions' => 0,
        ':shuffleOptions' => 0,
        ':showResultImmediately' => 1,
        ':showCorrectAnswers' => 1,
        ':allowReview' => 1,
        ':allowMultipleAttempts' => 1,
        ':startDate' => gmdate("Y-m-d\TH:i:s.000\Z"),
        ':endDate' => gmdate("Y-m-d\TH:i:s.000\Z", strtotime('+14 days')),
        ':status' => 'published',
        ':combinedFrom' => json_encode($selectedQuizIds)
    ]);

    // Copy and assign questions from parents
    $stmtQuestions = $pdo->prepare("SELECT * FROM questions WHERE quizId IN ($inClause)");
    $stmtQuestions->execute($selectedQuizIds);
    $parentQuestions = $stmtQuestions->fetchAll();

    $totalMarks = 0;
    $stmtInsertQn = $pdo->prepare("INSERT INTO questions (
        id, quizId, type, text, difficulty, marks, negativeMarks, explanation, image, options, correctAnswer, subject
    ) VALUES (
        :id, :quizId, :type, :text, :difficulty, :marks, :negativeMarks, :explanation, :image, :options, :correctAnswer, :subject
    )");

    foreach ($parentQuestions as $qn) {
        // Find which parent quiz this question came from to tag subject
        $subjectTag = 'General';
        foreach ($parentQuizzes as $pq) {
            if ($pq['id'] === $qn['quizId']) {
                $subjectTag = $pq['subject'];
                break;
            }
        }

        $newQnId = 'qn-' . uniqid() . '-' . bin2hex(random_bytes(2));
        $stmtInsertQn->execute([
            ':id' => $newQnId,
            ':quizId' => $newQuizId,
            ':type' => $qn['type'],
            ':text' => $qn['text'],
            ':difficulty' => $qn['difficulty'],
            ':marks' => (int)$qn['marks'],
            ':negativeMarks' => $qn['negativeMarks'],
            ':explanation' => $qn['explanation'],
            ':image' => $qn['image'],
            ':options' => $qn['options'],
            ':correctAnswer' => $qn['correctAnswer'],
            ':subject' => $subjectTag
        ]);
        $totalMarks += (int)$qn['marks'];
    }

    // Update combined quiz total max marks
    $stmtUpdateMarks = $pdo->prepare("UPDATE quizzes SET maxMarks = :marks WHERE id = :id");
    $stmtUpdateMarks->execute([':marks' => $totalMarks, ':id' => $newQuizId]);

    addAuditLog($pdo, $teacher['id'], $teacher['name'], "QUIZ_COMBINE", "Combined quizzes into combined quiz: " . $title);

    // Retrieve and send
    $combinedQuiz = $pdo->query("SELECT * FROM quizzes WHERE id = '$newQuizId'")->fetch();
    $combinedQuiz['negativeMarking'] = (bool)$combinedQuiz['negativeMarking'];
    $combinedQuiz['shuffleQuestions'] = (bool)$combinedQuiz['shuffleQuestions'];
    $combinedQuiz['shuffleOptions'] = (bool)$combinedQuiz['shuffleOptions'];
    $combinedQuiz['showResultImmediately'] = (bool)$combinedQuiz['showResultImmediately'];
    $combinedQuiz['showCorrectAnswers'] = (bool)$combinedQuiz['showCorrectAnswers'];
    $combinedQuiz['allowReview'] = (bool)$combinedQuiz['allowReview'];
    $combinedQuiz['allowMultipleAttempts'] = (bool)$combinedQuiz['allowMultipleAttempts'];
    $combinedQuiz['isCombined'] = (bool)$combinedQuiz['isCombined'];
    $combinedQuiz['combinedFrom'] = json_decode($combinedQuiz['combinedFrom'] ?: '[]');

    sendJSON($combinedQuiz);
}

// Single Quiz Endpoints: quizzes/{id}
$quizMatch = matchPath('quizzes/{id}', $route);
if ($quizMatch) {
    $quizId = $quizMatch['id'];
    
    // GET quizzes/{id}
    if ($method === 'GET') {
        $stmt = $pdo->prepare("SELECT * FROM quizzes WHERE id = :id");
        $stmt->execute([':id' => $quizId]);
        $quiz = $stmt->fetch();
        
        if (!$quiz) {
            sendJSON(['error' => 'Quiz not found.'], 404);
        }

        $quiz['negativeMarking'] = (bool)$quiz['negativeMarking'];
        $quiz['shuffleQuestions'] = (bool)$quiz['shuffleQuestions'];
        $quiz['shuffleOptions'] = (bool)$quiz['shuffleOptions'];
        $quiz['showResultImmediately'] = (bool)$quiz['showResultImmediately'];
        $quiz['showCorrectAnswers'] = (bool)$quiz['showCorrectAnswers'];
        $quiz['allowReview'] = (bool)$quiz['allowReview'];
        $quiz['allowMultipleAttempts'] = (bool)$quiz['allowMultipleAttempts'];
        $quiz['isCombined'] = (bool)$quiz['isCombined'];
        $quiz['combinedFrom'] = json_decode($quiz['combinedFrom'] ?: '[]');

        sendJSON($quiz);
    } 
    // PUT quizzes/{id}
    elseif ($method === 'PUT') {
        $teacher = authenticateTeacher($pdo);
        $data = getInputData();

        $stmt = $pdo->prepare("UPDATE quizzes SET 
            title = :title, description = :description, instructions = :instructions,
            subject = :subject, course = :course, duration = :duration,
            passingPercentage = :passingPercentage, negativeMarking = :negativeMarking,
            shuffleQuestions = :shuffleQuestions, shuffleOptions = :shuffleOptions,
            showResultImmediately = :showResultImmediately, showCorrectAnswers = :showCorrectAnswers,
            allowReview = :allowReview, allowMultipleAttempts = :allowMultipleAttempts,
            startDate = :startDate, endDate = :endDate, password = :password, status = :status,
            calculatorType = :calculatorType
            WHERE id = :id
        ");

        $stmt->execute([
            ':id' => $quizId,
            ':title' => $data['title'],
            ':description' => isset($data['description']) ? $data['description'] : '',
            ':instructions' => isset($data['instructions']) ? $data['instructions'] : '',
            ':subject' => isset($data['subject']) ? $data['subject'] : 'General',
            ':course' => isset($data['course']) ? $data['course'] : '',
            ':duration' => isset($data['duration']) ? (int)$data['duration'] : 30,
            ':passingPercentage' => isset($data['passingPercentage']) ? (int)$data['passingPercentage'] : 50,
            ':negativeMarking' => isset($data['negativeMarking']) ? (int)$data['negativeMarking'] : 0,
            ':shuffleQuestions' => isset($data['shuffleQuestions']) ? (int)$data['shuffleQuestions'] : 0,
            ':shuffleOptions' => isset($data['shuffleOptions']) ? (int)$data['shuffleOptions'] : 0,
            ':showResultImmediately' => isset($data['showResultImmediately']) ? (int)$data['showResultImmediately'] : 1,
            ':showCorrectAnswers' => isset($data['showCorrectAnswers']) ? (int)$data['showCorrectAnswers'] : 1,
            ':allowReview' => isset($data['allowReview']) ? (int)$data['allowReview'] : 1,
            ':allowMultipleAttempts' => isset($data['allowMultipleAttempts']) ? (int)$data['allowMultipleAttempts'] : 1,
            ':startDate' => isset($data['startDate']) ? $data['startDate'] : gmdate("Y-m-d\TH:i:s.000\Z"),
            ':endDate' => isset($data['endDate']) ? $data['endDate'] : gmdate("Y-m-d\TH:i:s.000\Z"),
            ':password' => !empty($data['password']) ? trim($data['password']) : null,
            ':status' => isset($data['status']) ? $data['status'] : 'draft',
            ':calculatorType' => isset($data['calculatorType']) ? $data['calculatorType'] : 'none'
        ]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "QUIZ_UPDATE", "Updated quiz details: " . $data['title']);

        // Fetch and return updated quiz
        $stmtQuiz = $pdo->prepare("SELECT * FROM quizzes WHERE id = :id");
        $stmtQuiz->execute([':id' => $quizId]);
        $quiz = $stmtQuiz->fetch();
        $quiz['negativeMarking'] = (bool)$quiz['negativeMarking'];
        $quiz['shuffleQuestions'] = (bool)$quiz['shuffleQuestions'];
        $quiz['shuffleOptions'] = (bool)$quiz['shuffleOptions'];
        $quiz['showResultImmediately'] = (bool)$quiz['showResultImmediately'];
        $quiz['showCorrectAnswers'] = (bool)$quiz['showCorrectAnswers'];
        $quiz['allowReview'] = (bool)$quiz['allowReview'];
        $quiz['allowMultipleAttempts'] = (bool)$quiz['allowMultipleAttempts'];
        $quiz['isCombined'] = (bool)$quiz['isCombined'];
        $quiz['combinedFrom'] = json_decode($quiz['combinedFrom'] ?: '[]');

        sendJSON($quiz);
    } 
    // DELETE quizzes/{id}
    elseif ($method === 'DELETE') {
        $teacher = authenticateTeacher($pdo);

        // Fetch quiz title for logs
        $stmtName = $pdo->prepare("SELECT title FROM quizzes WHERE id = :id");
        $stmtName->execute([':id' => $quizId]);
        $title = $stmtName->fetchColumn();

        if (!$title) {
            sendJSON(['error' => 'Quiz not found.'], 404);
        }

        // Delete quiz, questions and attempts
        $stmtQuiz = $pdo->prepare("DELETE FROM quizzes WHERE id = :id");
        $stmtQuiz->execute([':id' => $quizId]);

        $stmtQns = $pdo->prepare("DELETE FROM questions WHERE quizId = :quizId");
        $stmtQns->execute([':quizId' => $quizId]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "QUIZ_DELETE", "Archived / Deleted quiz: " . $title);
        sendJSON(['success' => true]);
    }
}

// POST quizzes/{id}/duplicate
$dupMatch = matchPath('quizzes/{id}/duplicate', $route);
if ($dupMatch && $method === 'POST') {
    $teacher = authenticateTeacher($pdo);
    $quizId = $dupMatch['id'];

    $stmt = $pdo->prepare("SELECT * FROM quizzes WHERE id = :id");
    $stmt->execute([':id' => $quizId]);
    $quiz = $stmt->fetch();

    if (!$quiz) {
        sendJSON(['error' => 'Quiz not found to duplicate.'], 404);
    }

    $newQuizId = 'q-' . uniqid();
    $newTitle = $quiz['title'] . " (Copy)";

    $stmtInsert = $pdo->prepare("INSERT INTO quizzes (
        id, title, description, instructions, subject, course, teacherName, teacherId,
        duration, passingPercentage, maxMarks, negativeMarking, shuffleQuestions, shuffleOptions,
        showResultImmediately, showCorrectAnswers, allowReview, allowMultipleAttempts,
        startDate, endDate, password, status, isCombined, combinedFrom, calculatorType
    ) VALUES (
        :id, :title, :description, :instructions, :subject, :course, :teacherName, :teacherId,
        :duration, :passingPercentage, :maxMarks, :negativeMarking, :shuffleQuestions, :shuffleOptions,
        :showResultImmediately, :showCorrectAnswers, :allowReview, :allowMultipleAttempts,
        :startDate, :endDate, :password, 'draft', :isCombined, :combinedFrom, :calculatorType
    )");

    $stmtInsert->execute([
        ':id' => $newQuizId,
        ':title' => $newTitle,
        ':description' => $quiz['description'],
        ':instructions' => $quiz['instructions'],
        ':subject' => $quiz['subject'],
        ':course' => $quiz['course'],
        ':teacherName' => $teacher['name'],
        ':teacherId' => $teacher['id'],
        ':duration' => (int)$quiz['duration'],
        ':passingPercentage' => (int)$quiz['passingPercentage'],
        ':maxMarks' => (int)$quiz['maxMarks'],
        ':negativeMarking' => (int)$quiz['negativeMarking'],
        ':shuffleQuestions' => (int)$quiz['shuffleQuestions'],
        ':shuffleOptions' => (int)$quiz['shuffleOptions'],
        ':showResultImmediately' => (int)$quiz['showResultImmediately'],
        ':showCorrectAnswers' => (int)$quiz['showCorrectAnswers'],
        ':allowReview' => (int)$quiz['allowReview'],
        ':allowMultipleAttempts' => (int)$quiz['allowMultipleAttempts'],
        ':startDate' => $quiz['startDate'],
        ':endDate' => $quiz['endDate'],
        ':password' => $quiz['password'],
        ':isCombined' => (int)$quiz['isCombined'],
        ':combinedFrom' => $quiz['combinedFrom'],
        ':calculatorType' => $quiz['calculatorType']
    ]);

    // Copy questions
    $stmtQns = $pdo->prepare("SELECT * FROM questions WHERE quizId = :quizId");
    $stmtQns->execute([':quizId' => $quizId]);
    $questions = $stmtQns->fetchAll();

    $stmtInsertQn = $pdo->prepare("INSERT INTO questions (
        id, quizId, type, text, difficulty, marks, negativeMarks, explanation, image, options, correctAnswer, subject
    ) VALUES (
        :id, :quizId, :type, :text, :difficulty, :marks, :negativeMarks, :explanation, :image, :options, :correctAnswer, :subject
    )");

    foreach ($questions as $qn) {
        $stmtInsertQn->execute([
            ':id' => 'qn-' . uniqid() . '-' . bin2hex(random_bytes(2)),
            ':quizId' => $newQuizId,
            ':type' => $qn['type'],
            ':text' => $qn['text'],
            ':difficulty' => $qn['difficulty'],
            ':marks' => (int)$qn['marks'],
            ':negativeMarks' => $qn['negativeMarks'],
            ':explanation' => $qn['explanation'],
            ':image' => $qn['image'],
            ':options' => $qn['options'],
            ':correctAnswer' => $qn['correctAnswer'],
            ':subject' => $qn['subject']
        ]);
    }

    addAuditLog($pdo, $teacher['id'], $teacher['name'], "QUIZ_DUPLICATE", "Duplicated quiz: " . $quiz['title'] . " to draft " . $newTitle);

    $newQuiz = $pdo->query("SELECT * FROM quizzes WHERE id = '$newQuizId'")->fetch();
    $newQuiz['negativeMarking'] = (bool)$newQuiz['negativeMarking'];
    $newQuiz['shuffleQuestions'] = (bool)$newQuiz['shuffleQuestions'];
    $newQuiz['shuffleOptions'] = (bool)$newQuiz['shuffleOptions'];
    $newQuiz['showResultImmediately'] = (bool)$newQuiz['showResultImmediately'];
    $newQuiz['showCorrectAnswers'] = (bool)$newQuiz['showCorrectAnswers'];
    $newQuiz['allowReview'] = (bool)$newQuiz['allowReview'];
    $newQuiz['allowMultipleAttempts'] = (bool)$newQuiz['allowMultipleAttempts'];
    $newQuiz['isCombined'] = (bool)$newQuiz['isCombined'];
    $newQuiz['combinedFrom'] = json_decode($newQuiz['combinedFrom'] ?: '[]');

    sendJSON($newQuiz);
}

// =================================================================
// 4. QUESTION MANAGEMENT
// =================================================================

// GET and POST quizzes/{id}/questions
$qnsMatch = matchPath('quizzes/{id}/questions', $route);
if ($qnsMatch) {
    $quizId = $qnsMatch['id'];
    
    // GET questions
    if ($method === 'GET') {
        $stmtQuiz = $pdo->prepare("SELECT * FROM quizzes WHERE id = :id");
        $stmtQuiz->execute([':id' => $quizId]);
        $quiz = $stmtQuiz->fetch();

        if (!$quiz) {
            sendJSON(['error' => 'Quiz not found.'], 404);
        }

        $stmtQns = $pdo->prepare("SELECT * FROM questions WHERE quizId = :quizId");
        $stmtQns->execute([':quizId' => $quizId]);
        $questions = $stmtQns->fetchAll();

        // Security check for teachers
        $headers = apache_request_headers();
        $authHeader = isset($headers['Authorization']) ? $headers['Authorization'] : '';
        if (empty($authHeader) && isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $authHeader = $_SERVER['HTTP_AUTHORIZATION'];
        }
        $isTeacher = preg_match('/Bearer\s+mock-teacher-token-/', $authHeader);

        $responseQuestions = [];
        foreach ($questions as $q) {
            $optionsDecoded = json_decode($q['options'] ?: '[]');
            $correctAnsDecoded = json_decode($q['correctAnswer'] ?: '""', true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                $correctAnsDecoded = $q['correctAnswer']; // Fallback to raw string
            }

            $qnObj = [
                'id' => $q['id'],
                'quizId' => $q['quizId'],
                'type' => $q['type'],
                'text' => $q['text'],
                'difficulty' => $q['difficulty'],
                'marks' => (int)$q['marks'],
                'negativeMarks' => (float)$q['negativeMarks'],
                'image' => $q['image'],
                'options' => $optionsDecoded,
                'subject' => $q['subject']
            ];

            if ($isTeacher) {
                $qnObj['correctAnswer'] = $correctAnsDecoded;
                $qnObj['explanation'] = $q['explanation'];
            }

            $responseQuestions[] = $qnObj;
        }

        sendJSON($responseQuestions);
    } 
    // POST questions (bulk update / recreate)
    elseif ($method === 'POST') {
        $teacher = authenticateTeacher($pdo);
        $questionsData = getInputData();

        // Validate quiz exists
        $stmtQuiz = $pdo->prepare("SELECT * FROM quizzes WHERE id = :id");
        $stmtQuiz->execute([':id' => $quizId]);
        $quiz = $stmtQuiz->fetch();
        if (!$quiz) {
            sendJSON(['error' => 'Quiz not found.'], 404);
        }

        // Delete existing questions
        $stmtDelete = $pdo->prepare("DELETE FROM questions WHERE quizId = :quizId");
        $stmtDelete->execute([':quizId' => $quizId]);

        // Insert new questions
        $stmtInsert = $pdo->prepare("INSERT INTO questions (
            id, quizId, type, text, difficulty, marks, negativeMarks, explanation, image, options, correctAnswer, subject
        ) VALUES (
            :id, :quizId, :type, :text, :difficulty, :marks, :negativeMarks, :explanation, :image, :options, :correctAnswer, :subject
        )");

        $totalMarks = 0;
        foreach ($questionsData as $qn) {
            $qnId = !empty($qn['id']) ? $qn['id'] : 'qn-' . uniqid() . '-' . bin2hex(random_bytes(2));
            $optionsEncoded = json_encode(isset($qn['options']) ? $qn['options'] : []);
            $correctAnswerEncoded = json_encode(isset($qn['correctAnswer']) ? $qn['correctAnswer'] : '');
            
            $stmtInsert->execute([
                ':id' => $qnId,
                ':quizId' => $quizId,
                ':type' => $qn['type'],
                ':text' => $qn['text'],
                ':difficulty' => isset($qn['difficulty']) ? $qn['difficulty'] : 'medium',
                ':marks' => isset($qn['marks']) ? (int)$qn['marks'] : 5,
                ':negativeMarks' => isset($qn['negativeMarks']) ? (float)$qn['negativeMarks'] : 0.0,
                ':explanation' => isset($qn['explanation']) ? $qn['explanation'] : '',
                ':image' => isset($qn['image']) ? $qn['image'] : null,
                ':options' => $optionsEncoded,
                ':correctAnswer' => $correctAnswerEncoded,
                ':subject' => isset($qn['subject']) ? $qn['subject'] : $quiz['subject']
            ]);

            $totalMarks += isset($qn['marks']) ? (int)$qn['marks'] : 5;
        }

        // Update maximum marks on parent quiz
        $stmtUpdateQuiz = $pdo->prepare("UPDATE quizzes SET maxMarks = :marks WHERE id = :id");
        $stmtUpdateQuiz->execute([':marks' => $totalMarks, ':id' => $quizId]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "QUIZ_QUESTIONS_SAVE", "Updated questions list for quiz: " . $quiz['title'] . " (Total Marks: " . $totalMarks . ")");

        sendJSON(['success' => true, 'totalMarks' => $totalMarks]);
    }
}

// =================================================================
// 5. STUDENT ATTEMPTS & PROGRESS SAVING
// =================================================================

// POST quizzes/{id}/attempt (Start or resume exam taking)
$attemptInitMatch = matchPath('quizzes/{id}/attempt', $route);
if ($attemptInitMatch && $method === 'POST') {
    $quizId = $attemptInitMatch['id'];
    $data = getInputData();

    $fullName = isset($data['fullName']) ? trim($data['fullName']) : '';
    $rollNumber = isset($data['rollNumber']) ? trim($data['rollNumber']) : '';
    $className = isset($data['className']) ? trim($data['className']) : '';
    $section = isset($data['section']) ? trim($data['section']) : '';
    $phone = isset($data['phone']) ? trim($data['phone']) : '';
    $email = isset($data['email']) ? trim($data['email']) : '';
    $gender = isset($data['gender']) ? trim($data['gender']) : '';
    $password = isset($data['password']) ? trim($data['password']) : '';

    if (empty($fullName) || empty($rollNumber) || empty($className)) {
        sendJSON(['error' => 'Full Name, Roll Number, and Class are required.'], 400);
    }

    // Verify quiz exists and is published
    $stmtQuiz = $pdo->prepare("SELECT * FROM quizzes WHERE id = :id");
    $stmtQuiz->execute([':id' => $quizId]);
    $quiz = $stmtQuiz->fetch();

    if (!$quiz || $quiz['status'] !== 'published') {
        sendJSON(['error' => 'Quiz is not available.'], 404);
    }

    // Password validation for protected quizzes
    if (!empty($quiz['password']) && $quiz['password'] !== $password) {
        sendJSON(['error' => 'Incorrect quiz access password.'], 403);
    }

    // Find or create student
    $stmtStdCheck = $pdo->prepare("SELECT id FROM students WHERE LOWER(rollNumber) = LOWER(:roll) AND LOWER(className) = LOWER(:class)");
    $stmtStdCheck->execute([':roll' => $rollNumber, ':class' => $className]);
    $studentId = $stmtStdCheck->fetchColumn();

    if (!$studentId) {
        $studentId = 'std-' . uniqid();
        $stmtStdInsert = $pdo->prepare("INSERT INTO students (id, fullName, rollNumber, className, section, phone, email, gender) VALUES (:id, :name, :roll, :class, :sect, :ph, :em, :gen)");
        $stmtStdInsert->execute([
            ':id' => $studentId,
            ':name' => $fullName,
            ':roll' => $rollNumber,
            ':class' => $className,
            ':sect' => $section,
            ':ph' => $phone,
            ':em' => $email,
            ':gen' => $gender
        ]);
    }

    // Check for an ongoing active attempt to resume
    $stmtAttCheck = $pdo->prepare("SELECT * FROM attempts WHERE quizId = :quizId AND studentId = :studentId AND status = 'ongoing'");
    $stmtAttCheck->execute([':quizId' => $quizId, ':studentId' => $studentId]);
    $existingAttempt = $stmtAttCheck->fetch();

    $resumed = false;
    $attempt = null;

    if ($existingAttempt) {
        $resumed = true;
        $attempt = $existingAttempt;
    } else {
        // Check if multiple attempts are allowed. If not and they have already submitted one, reject!
        if (!$quiz['allowMultipleAttempts']) {
            $stmtPriorCount = $pdo->prepare("SELECT COUNT(*) FROM attempts WHERE quizId = :quizId AND studentId = :studentId AND status IN ('submitted', 'timeout')");
            $stmtPriorCount->execute([':quizId' => $quizId, ':studentId' => $studentId]);
            $priorAttempts = $stmtPriorCount->fetchColumn();

            if ($priorAttempts > 0) {
                sendJSON(['error' => 'Multiple attempts are disabled for this quiz. You have already completed this exam.'], 403);
            }
        }

        // Initialize new attempt
        $attemptId = 'att-' . uniqid();
        $startTimeStr = gmdate("Y-m-d\TH:i:s.000\Z");

        $stmtAttInsert = $pdo->prepare("INSERT INTO attempts (
            id, quizId, studentId, studentName, studentRoll, studentClass, studentSection, studentGender,
            startTime, duration, status, score, percentage, passed, totalQuestions, correctCount, incorrectCount, skippedCount
        ) VALUES (
            :id, :quizId, :studentId, :studentName, :studentRoll, :studentClass, :studentSection, :studentGender,
            :startTime, 0, 'ongoing', 0, 0, 0, 0, 0, 0, 0
        )");

        $stmtAttInsert->execute([
            ':id' => $attemptId,
            ':quizId' => $quizId,
            ':studentId' => $studentId,
            ':studentName' => $fullName,
            ':studentRoll' => $rollNumber,
            ':studentClass' => $className,
            ':studentSection' => $section,
            ':studentGender' => $gender,
            ':startTime' => $startTimeStr
        ]);

        $attempt = [
            'id' => $attemptId,
            'quizId' => $quizId,
            'studentId' => $studentId,
            'studentName' => $fullName,
            'studentRoll' => $rollNumber,
            'studentClass' => $className,
            'studentSection' => $section,
            'studentGender' => $gender,
            'startTime' => $startTimeStr,
            'status' => 'ongoing',
            'score' => 0,
            'percentage' => 0,
            'passed' => false,
            'totalQuestions' => 0
        ];
    }

    // Fetch questions associated with quiz
    $stmtQns = $pdo->prepare("SELECT id, quizId, type, text, difficulty, marks, negativeMarks, image, options, subject FROM questions WHERE quizId = :quizId");
    $stmtQns->execute([':quizId' => $quizId]);
    $questions = $stmtQns->fetchAll();

    // Subject/Group Filtering for combined quizzes
    $filteredQuestions = [];
    $sectionLower = strtolower($section);
    $isCombined = (bool)$quiz['isCombined'];

    foreach ($questions as $q) {
        if ($isCombined) {
            $subjLower = strtolower($q['subject']);
            // Standard filters: Pre-engineering, Pre-medical, General, Commerce, Arts
            if ($subjLower === 'biology' && (strpos($sectionLower, 'eng') !== false || strpos($sectionLower, 'math') !== false)) {
                continue; // Skip biology for engineering
            }
            if ($subjLower === 'mathematics' && (strpos($sectionLower, 'med') !== false || strpos($sectionLower, 'bio') !== false)) {
                continue; // Skip math for medical
            }
        }
        
        $q['options'] = json_decode($q['options'] ?: '[]');
        $filteredQuestions[] = $q;
    }

    // Update total questions on attempt
    $stmtUpdateTotalQns = $pdo->prepare("UPDATE attempts SET totalQuestions = :total WHERE id = :id");
    $stmtUpdateTotalQns->execute([':total' => count($filteredQuestions), ':id' => $attempt['id']]);
    $attempt['totalQuestions'] = count($filteredQuestions);

    sendJSON([
        'attempt' => $attempt,
        'resumed' => $resumed,
        'questions' => $filteredQuestions
    ]);
}

// POST attempts/{id}/save (Save response/draft during exam)
$saveMatch = matchPath('attempts/{id}/save', $route);
if ($saveMatch && $method === 'POST') {
    $attemptId = $saveMatch['id'];
    $data = getInputData();

    $questionId = isset($data['questionId']) ? $data['questionId'] : '';
    $answer = isset($data['answer']) ? $data['answer'] : null;
    $markedForReview = isset($data['markedForReview']) ? (int)$data['markedForReview'] : 0;

    if (empty($questionId)) {
        sendJSON(['error' => 'Question ID is required.'], 400);
    }

    // Verify attempt is ongoing
    $stmtAtt = $pdo->prepare("SELECT status FROM attempts WHERE id = :id");
    $stmtAtt->execute([':id' => $attemptId]);
    $status = $stmtAtt->fetchColumn();

    if ($status !== 'ongoing') {
        sendJSON(['error' => 'This attempt is no longer active.'], 403);
    }

    // Check if response already exists
    $stmtCheck = $pdo->prepare("SELECT id FROM responses WHERE attemptId = :attemptId AND questionId = :questionId");
    $stmtCheck->execute([':attemptId' => $attemptId, ':questionId' => $questionId]);
    $responseId = $stmtCheck->fetchColumn();

    $answerEncoded = json_encode($answer);

    if ($responseId) {
        $stmtUpdate = $pdo->prepare("UPDATE responses SET selectedAnswer = :ans, markedForReview = :review WHERE id = :id");
        $stmtUpdate->execute([
            ':ans' => $answerEncoded,
            ':review' => $markedForReview,
            ':id' => $responseId
        ]);
    } else {
        $newResponseId = 'resp-' . uniqid();
        $stmtInsert = $pdo->prepare("INSERT INTO responses (id, attemptId, questionId, selectedAnswer, isCorrect, marksAwarded, markedForReview) VALUES (:id, :att, :qn, :ans, NULL, 0.0, :review)");
        $stmtInsert->execute([
            ':id' => $newResponseId,
            ':att' => $attemptId,
            ':qn' => $questionId,
            ':ans' => $answerEncoded,
            ':review' => $markedForReview
        ]);
    }

    sendJSON(['success' => true]);
}

// POST attempts/{id}/submit (Grade and submit final exam paper)
$submitMatch = matchPath('attempts/{id}/submit', $route);
if ($submitMatch && $method === 'POST') {
    $attemptId = $submitMatch['id'];
    $data = getInputData();
    $isTimeout = isset($data['isTimeout']) && $data['isTimeout'] ? 'timeout' : 'submitted';

    // Fetch attempt details
    $stmtAtt = $pdo->prepare("SELECT * FROM attempts WHERE id = :id");
    $stmtAtt->execute([':id' => $attemptId]);
    $attempt = $stmtAtt->fetch();

    if (!$attempt || $attempt['status'] !== 'ongoing') {
        sendJSON(['error' => 'Attempt not found or already submitted.'], 404);
    }

    // Fetch parent quiz
    $stmtQuiz = $pdo->prepare("SELECT * FROM quizzes WHERE id = :id");
    $stmtQuiz->execute([':id' => $attempt['quizId']]);
    $quiz = $stmtQuiz->fetch();

    if (!$quiz) {
        sendJSON(['error' => 'Associated quiz not found.'], 404);
    }

    // Fetch questions
    $stmtQns = $pdo->prepare("SELECT * FROM questions WHERE quizId = :quizId");
    $stmtQns->execute([':quizId' => $attempt['quizId']]);
    $questions = $stmtQns->fetchAll();

    // Fetch current student responses
    $stmtResp = $pdo->prepare("SELECT * FROM responses WHERE attemptId = :attemptId");
    $stmtResp->execute([':attemptId' => $attemptId]);
    $responses = $stmtResp->fetchAll();

    $correctCount = 0;
    $incorrectCount = 0;
    $skippedCount = 0;
    $totalScore = 0.0;
    $isCombined = (bool)$quiz['isCombined'];
    $sectionLower = strtolower($attempt['studentSection']);

    // Map responses by questionId
    $respMap = [];
    foreach ($responses as $r) {
        $respMap[$r['questionId']] = $r;
    }

    // Grade each question
    foreach ($questions as $q) {
        // If combined quiz, filter out subject group questions that don't apply to this student
        if ($isCombined) {
            $subjLower = strtolower($q['subject']);
            if ($subjLower === 'biology' && (strpos($sectionLower, 'eng') !== false || strpos($sectionLower, 'math') !== false)) {
                continue;
            }
            if ($subjLower === 'mathematics' && (strpos($sectionLower, 'med') !== false || strpos($sectionLower, 'bio') !== false)) {
                continue;
            }
        }

        $correctAnswer = json_decode($q['correctAnswer'] ?: '""', true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $correctAnswer = $q['correctAnswer'];
        }

        $resp = isset($respMap[$q['id']]) ? $respMap[$q['id']] : null;
        $selectedAnswer = null;

        if ($resp && !empty($resp['selectedAnswer'])) {
            $selectedAnswer = json_decode($resp['selectedAnswer'], true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                $selectedAnswer = $resp['selectedAnswer'];
            }
        }

        $isCorrect = false;
        $marksAwarded = 0.0;
        $hasResponded = ($selectedAnswer !== null && $selectedAnswer !== '');

        if ($hasResponded) {
            // Check correctness based on type
            $qType = $q['type'];

            if ($qType === 'single_choice' || $qType === 'true_false' || $qType === 'image_mcq') {
                $isCorrect = (String)$selectedAnswer === (String)$correctAnswer;
            } 
            elseif ($qType === 'multiple_choice') {
                if (is_array($selectedAnswer) && is_array($correctAnswer)) {
                    sort($selectedAnswer);
                    sort($correctAnswer);
                    $isCorrect = $selectedAnswer === $correctAnswer;
                } else {
                    $isCorrect = (String)$selectedAnswer === (String)$correctAnswer;
                }
            } 
            elseif ($qType === 'fill_blank' || $qType === 'short_answer') {
                // Case-insensitive clean comparison
                $cleanSelected = strtolower(trim((String)$selectedAnswer));
                $cleanCorrect = strtolower(trim((String)$correctAnswer));
                $isCorrect = $cleanSelected === $cleanCorrect;
            } 
            elseif ($qType === 'matching') {
                // Key-value exact comparison
                if (is_array($selectedAnswer) && is_array($correctAnswer)) {
                    $isCorrect = true;
                    foreach ($correctAnswer as $k => $v) {
                        if (!isset($selectedAnswer[$k]) || (String)$selectedAnswer[$k] !== (String)$v) {
                            $isCorrect = false;
                            break;
                        }
                    }
                }
            } 
            elseif ($qType === 'ordering') {
                // Order indices exact comparison
                if (is_array($selectedAnswer) && is_array($correctAnswer)) {
                    $isCorrect = $selectedAnswer === $correctAnswer;
                }
            }

            if ($isCorrect) {
                $correctCount++;
                $marksAwarded = (float)$q['marks'];
            } else {
                $incorrectCount++;
                $marksAwarded = (bool)$quiz['negativeMarking'] ? -((float)$q['negativeMarks']) : 0.0;
            }

            $totalScore += $marksAwarded;

            // Save evaluated response details
            if ($resp) {
                $stmtUpdateResp = $pdo->prepare("UPDATE responses SET isCorrect = :correct, marksAwarded = :marks WHERE id = :id");
                $stmtUpdateResp->execute([
                    ':correct' => $isCorrect ? 1 : 0,
                    ':marks' => $marksAwarded,
                    ':id' => $resp['id']
                ]);
            } else {
                // Create a response row if it somehow wasn't created yet
                $stmtInsertResp = $pdo->prepare("INSERT INTO responses (id, attemptId, questionId, selectedAnswer, isCorrect, marksAwarded, markedForReview) VALUES (:id, :att, :qn, :ans, :correct, :marks, 0)");
                $stmtInsertResp->execute([
                    ':id' => 'resp-' . uniqid(),
                    ':att' => $attemptId,
                    ':qn' => $q['id'],
                    ':ans' => json_encode($selectedAnswer),
                    ':correct' => $isCorrect ? 1 : 0,
                    ':marks' => $marksAwarded
                ]);
            }
        } else {
            $skippedCount++;
            // Skipped / No Response
            if ($resp) {
                $stmtUpdateResp = $pdo->prepare("UPDATE responses SET isCorrect = NULL, marksAwarded = 0.0 WHERE id = :id");
                $stmtUpdateResp->execute([':id' => $resp['id']]);
            }
        }
    }

    // Determine aggregate pass status
    $passingPercentage = (float)$quiz['passingPercentage'];
    $maxQuizMarks = (float)$quiz['maxMarks'];
    if ($maxQuizMarks <= 0) $maxQuizMarks = 100.0; // Avoid divide-by-zero

    // Percentage of score vs maximum score
    $percentageScore = ($totalScore / $maxQuizMarks) * 100;
    if ($percentageScore < 0) $percentageScore = 0.0;
    if ($percentageScore > 100) $percentageScore = 100.0;
    
    $passed = $percentageScore >= $passingPercentage ? 1 : 0;

    // Calculate elapsed time
    $startTimeEpoch = strtotime($attempt['startTime']);
    $submitTimeStr = gmdate("Y-m-d\TH:i:s.000\Z");
    $submitTimeEpoch = strtotime($submitTimeStr);
    $durationSeconds = $submitTimeEpoch - $startTimeEpoch;

    // Update Attempt row in MySQL
    $stmtUpdateAtt = $pdo->prepare("UPDATE attempts SET 
        submitTime = :subTime, duration = :dur, status = :status, score = :score,
        percentage = :percentage, passed = :passed, correctCount = :cc, incorrectCount = :ic, skippedCount = :sc
        WHERE id = :id
    ");

    $stmtUpdateAtt->execute([
        ':subTime' => $submitTimeStr,
        ':dur' => $durationSeconds,
        ':status' => $isTimeout,
        ':score' => $totalScore,
        ':percentage' => $percentageScore,
        ':passed' => $passed,
        ':cc' => $correctCount,
        ':ic' => $incorrectCount,
        ':sc' => $skippedCount,
        ':id' => $attemptId
    ]);

    // Fetch and return the graded attempt object
    $stmtFinalAtt = $pdo->prepare("SELECT * FROM attempts WHERE id = :id");
    $stmtFinalAtt->execute([':id' => $attemptId]);
    $gradedAttempt = $stmtFinalAtt->fetch();
    
    $gradedAttempt['passed'] = (bool)$gradedAttempt['passed'];
    $gradedAttempt['score'] = (float)$gradedAttempt['score'];
    $gradedAttempt['percentage'] = (float)$gradedAttempt['percentage'];

    sendJSON($gradedAttempt);
}

// GET attempts/{id}/result (Retrieve full exam paper details, scoring, corrections review)
$resultMatch = matchPath('attempts/{id}/result', $route);
if ($resultMatch && $method === 'GET') {
    $attemptId = $resultMatch['id'];

    $stmtAtt = $pdo->prepare("SELECT * FROM attempts WHERE id = :id");
    $stmtAtt->execute([':id' => $attemptId]);
    $attempt = $stmtAtt->fetch();

    if (!$attempt) {
        sendJSON(['error' => 'Attempt not found.'], 404);
    }

    $stmtQuiz = $pdo->prepare("SELECT * FROM quizzes WHERE id = :id");
    $stmtQuiz->execute([':id' => $attempt['quizId']]);
    $quiz = $stmtQuiz->fetch();

    if (!$quiz) {
        sendJSON(['error' => 'Quiz associated with this attempt has been archived.'], 404);
    }

    $quiz['negativeMarking'] = (bool)$quiz['negativeMarking'];
    $quiz['shuffleQuestions'] = (bool)$quiz['shuffleQuestions'];
    $quiz['shuffleOptions'] = (bool)$quiz['shuffleOptions'];
    $quiz['showResultImmediately'] = (bool)$quiz['showResultImmediately'];
    $quiz['showCorrectAnswers'] = (bool)$quiz['showCorrectAnswers'];
    $quiz['allowReview'] = (bool)$quiz['allowReview'];
    $quiz['allowMultipleAttempts'] = (bool)$quiz['allowMultipleAttempts'];
    $quiz['isCombined'] = (bool)$quiz['isCombined'];
    $quiz['combinedFrom'] = json_decode($quiz['combinedFrom'] ?: '[]');

    $attempt['passed'] = (bool)$attempt['passed'];
    $attempt['score'] = (float)$attempt['score'];
    $attempt['percentage'] = (float)$attempt['percentage'];

    // Security Check: Is this a teacher querying or student?
    $headers = apache_request_headers();
    $authHeader = isset($headers['Authorization']) ? $headers['Authorization'] : '';
    if (empty($authHeader) && isset($_SERVER['HTTP_AUTHORIZATION'])) {
        $authHeader = $_SERVER['HTTP_AUTHORIZATION'];
    }
    $isTeacher = preg_match('/Bearer\s+mock-teacher-token-/', $authHeader);

    // If student, and quiz result display is restricted immediately, hide scores
    if (!$isTeacher && !$quiz['showResultImmediately']) {
        sendJSON([
            'attempt' => [
                'id' => $attempt['id'],
                'quizId' => $attempt['quizId'],
                'studentName' => $attempt['studentName'],
                'studentRoll' => $attempt['studentRoll'],
                'status' => $attempt['status'],
                'startTime' => $attempt['startTime'],
                'submitTime' => $attempt['submitTime'],
                'duration' => (int)$attempt['duration']
            ],
            'quizTitle' => $quiz['title'],
            'showResultImmediately' => false
        ]);
    }

    // Fetch original questions
    $stmtQns = $pdo->prepare("SELECT * FROM questions WHERE quizId = :quizId");
    $stmtQns->execute([':quizId' => $attempt['quizId']]);
    $questions = $stmtQns->fetchAll();

    // Fetch responses for this attempt
    $stmtResp = $pdo->prepare("SELECT * FROM responses WHERE attemptId = :attemptId");
    $stmtResp->execute([':attemptId' => $attemptId]);
    $responses = $stmtResp->fetchAll();

    $respMap = [];
    foreach ($responses as $r) {
        $respMap[$r['questionId']] = $r;
    }

    $isCombined = (bool)$quiz['isCombined'];
    $sectionLower = strtolower($attempt['studentSection']);
    $review = [];

    foreach ($questions as $q) {
        // Combined filters
        if ($isCombined) {
            $subjLower = strtolower($q['subject']);
            if ($subjLower === 'biology' && (strpos($sectionLower, 'eng') !== false || strpos($sectionLower, 'math') !== false)) {
                continue;
            }
            if ($subjLower === 'mathematics' && (strpos($sectionLower, 'med') !== false || strpos($sectionLower, 'bio') !== false)) {
                continue;
            }
        }

        $resp = isset($respMap[$q['id']]) ? $respMap[$q['id']] : null;
        $selectedAnswerDecoded = null;
        if ($resp && !empty($resp['selectedAnswer'])) {
            $selectedAnswerDecoded = json_decode($resp['selectedAnswer'], true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                $selectedAnswerDecoded = $resp['selectedAnswer'];
            }
        }

        $correctAnswerDecoded = json_decode($q['correctAnswer'] ?: '""', true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $correctAnswerDecoded = $q['correctAnswer'];
        }

        $reviewItem = [
            'id' => $q['id'],
            'type' => $q['type'],
            'text' => $q['text'],
            'difficulty' => $q['difficulty'],
            'marks' => (int)$q['marks'],
            'negativeMarks' => (float)$q['negativeMarks'],
            'image' => $q['image'],
            'options' => json_decode($q['options'] ?: '[]'),
            'selectedAnswer' => $selectedAnswerDecoded,
            'isCorrect' => $resp ? (bool)$resp['isCorrect'] : false,
            'marksAwarded' => $resp ? (float)$resp['marksAwarded'] : 0.0
        ];

        // Only reveal correct answers + explanations if permitted or is teacher
        if ($isTeacher || $quiz['showCorrectAnswers']) {
            $reviewItem['correctAnswer'] = $correctAnswerDecoded;
            $reviewItem['explanation'] = $q['explanation'];
        }

        $review[] = $reviewItem;
    }

    sendJSON([
        'attempt' => $attempt,
        'quiz' => $quiz,
        'review' => $review,
        'showResultImmediately' => true
    ]);
}

// GET attempts (retrieve all student attempt scores, requires auth)
if ($route === 'attempts' && $method === 'GET') {
    $teacher = authenticateTeacher($pdo);

    $stmt = $pdo->query("SELECT attempts.*, quizzes.title as quizTitle FROM attempts JOIN quizzes ON attempts.quizId = quizzes.id ORDER BY startTime DESC");
    $attempts = $stmt->fetchAll();

    foreach ($attempts as &$a) {
        $a['passed'] = (bool)$a['passed'];
        $a['score'] = (float)$a['score'];
        $a['percentage'] = (float)$a['percentage'];
    }

    sendJSON($attempts);
}

// DELETE attempts/{id} & POST attempts/{id}/allow-reattempt
$attResetMatch = matchPath('attempts/{id}', $route);
if ($attResetMatch && $method === 'DELETE') {
    $teacher = authenticateTeacher($pdo);
    $attemptId = $attResetMatch['id'];

    // Delete attempts and responses to allow clean reset
    $stmtDeleteResp = $pdo->prepare("DELETE FROM responses WHERE attemptId = :attemptId");
    $stmtDeleteResp->execute([':attemptId' => $attemptId]);

    $stmtDeleteAtt = $pdo->prepare("DELETE FROM attempts WHERE id = :id");
    $stmtDeleteAtt->execute([':id' => $attemptId]);

    addAuditLog($pdo, $teacher['id'], $teacher['name'], "ATTEMPT_RESET", "Reset attempt records for ID: " . $attemptId);
    sendJSON(['success' => true]);
}

$reattemptMatch = matchPath('attempts/{id}/allow-reattempt', $route);
if ($reattemptMatch && $method === 'POST') {
    $teacher = authenticateTeacher($pdo);
    $attemptId = $reattemptMatch['id'];

    // Delete attempts and responses to allow clean reset
    $stmtDeleteResp = $pdo->prepare("DELETE FROM responses WHERE attemptId = :attemptId");
    $stmtDeleteResp->execute([':attemptId' => $attemptId]);

    $stmtDeleteAtt = $pdo->prepare("DELETE FROM attempts WHERE id = :id");
    $stmtDeleteAtt->execute([':id' => $attemptId]);

    addAuditLog($pdo, $teacher['id'], $teacher['name'], "ATTEMPT_RESET", "Reauthorized student reattempt on paper for ID: " . $attemptId);
    sendJSON(['success' => true]);
}

// =================================================================
// 6. CLASSES MANAGEMENT
// =================================================================

// GET and POST classes
if ($route === 'classes') {
    if ($method === 'GET') {
        $stmt = $pdo->query("SELECT * FROM classes ORDER BY name ASC");
        $classes = $stmt->fetchAll();
        sendJSON($classes);
    } 
    elseif ($method === 'POST') {
        $teacher = authenticateTeacher($pdo);
        $data = getInputData();

        $name = isset($data['name']) ? trim($data['name']) : '';
        if (empty($name)) {
            sendJSON(['error' => 'Class name is required.'], 400);
        }

        $id = 'c-' . uniqid();
        $stmt = $pdo->prepare("INSERT INTO classes (id, name) VALUES (:id, :name)");
        $stmt->execute([':id' => $id, ':name' => $name]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "CLASS_CREATE", "Added new class: " . $name);
        sendJSON(['id' => $id, 'name' => $name]);
    }
}

// PUT and DELETE classes/{id}
$classIdMatch = matchPath('classes/{id}', $route);
if ($classIdMatch) {
    $classId = $classIdMatch['id'];
    
    if ($method === 'PUT') {
        $teacher = authenticateTeacher($pdo);
        $data = getInputData();
        $name = isset($data['name']) ? trim($data['name']) : '';

        if (empty($name)) {
            sendJSON(['error' => 'Class name is required.'], 400);
        }

        $stmt = $pdo->prepare("UPDATE classes SET name = :name WHERE id = :id");
        $stmt->execute([':name' => $name, ':id' => $classId]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "CLASS_UPDATE", "Updated class ID: " . $classId . " to: " . $name);
        sendJSON(['id' => $classId, 'name' => $name]);
    } 
    elseif ($method === 'DELETE') {
        $teacher = authenticateTeacher($pdo);

        $stmt = $pdo->prepare("DELETE FROM classes WHERE id = :id");
        $stmt->execute([':id' => $classId]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "CLASS_DELETE", "Deleted class ID: " . $classId);
        sendJSON(['success' => true]);
    }
}

// =================================================================
// 7. ANALYTICS & DASHBOARD DATA
// =================================================================

// GET dashboard/stats
if ($route === 'dashboard/stats' && $method === 'GET') {
    $teacher = authenticateTeacher($pdo);

    $totalQuizzes = (int)$pdo->query("SELECT COUNT(*) FROM quizzes")->fetchColumn();
    $totalAttempts = (int)$pdo->query("SELECT COUNT(*) FROM attempts WHERE status IN ('submitted', 'timeout')")->fetchColumn();
    $avgPercentage = (float)$pdo->query("SELECT AVG(percentage) FROM attempts WHERE status IN ('submitted', 'timeout')")->fetchColumn();
    $totalStudents = (int)$pdo->query("SELECT COUNT(*) FROM students")->fetchColumn();
    $totalClasses = (int)$pdo->query("SELECT COUNT(*) FROM classes")->fetchColumn();

    // Calculate passing distribution
    $passed = (int)$pdo->query("SELECT COUNT(*) FROM attempts WHERE passed = 1 AND status IN ('submitted', 'timeout')")->fetchColumn();
    $failed = $totalAttempts - $passed;

    // Monthly or recent quiz performance trend
    $stmtTrend = $pdo->query("SELECT percentage, studentName, startTime FROM attempts WHERE status IN ('submitted', 'timeout') ORDER BY startTime ASC LIMIT 20");
    $trendData = $stmtTrend->fetchAll();

    sendJSON([
        'totalQuizzes' => $totalQuizzes,
        'totalAttempts' => $totalAttempts,
        'averagePercentage' => round($avgPercentage, 2),
        'totalStudents' => $totalStudents,
        'totalClasses' => $totalClasses,
        'passingDistribution' => [
            ['name' => 'Passed', 'value' => $passed],
            ['name' => 'Failed', 'value' => $failed]
        ],
        'performanceTrend' => $trendData
    ]);
}

// GET dashboard/recent
if ($route === 'dashboard/recent' && $method === 'GET') {
    $teacher = authenticateTeacher($pdo);

    $stmt = $pdo->query("SELECT attempts.*, quizzes.title as quizTitle FROM attempts JOIN quizzes ON attempts.quizId = quizzes.id ORDER BY startTime DESC LIMIT 5");
    $recent = $stmt->fetchAll();

    foreach ($recent as &$r) {
        $r['passed'] = (bool)$r['passed'];
        $r['score'] = (float)$r['score'];
        $r['percentage'] = (float)$r['percentage'];
    }

    sendJSON($recent);
}

// =================================================================
// 8. SYSTEM AUDIT LOGGING
// =================================================================

// GET logs
if ($route === 'logs' && $method === 'GET') {
    $teacher = authenticateTeacher($pdo);

    $stmt = $pdo->query("SELECT * FROM logs ORDER BY timestamp DESC LIMIT 100");
    $logs = $stmt->fetchAll();
    sendJSON($logs);
}

// =================================================================
// 9. SUBJECTS MANAGEMENT
// =================================================================

// GET and POST subjects
if ($route === 'subjects') {
    if ($method === 'GET') {
        $stmt = $pdo->query("SELECT * FROM subjects ORDER BY name ASC");
        $subjects = $stmt->fetchAll();
        sendJSON($subjects);
    } 
    elseif ($method === 'POST') {
        $teacher = authenticateTeacher($pdo);
        $data = getInputData();
        $name = isset($data['name']) ? trim($data['name']) : '';

        if (empty($name)) {
            sendJSON(['error' => 'Subject name is required.'], 400);
        }

        $id = 's-' . uniqid();
        $stmt = $pdo->prepare("INSERT INTO subjects (id, name) VALUES (:id, :name)");
        $stmt->execute([':id' => $id, ':name' => $name]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "SUBJECT_CREATE", "Added new subject: " . $name);
        sendJSON(['id' => $id, 'name' => $name]);
    }
}

// DELETE subjects/{id}
$subjectIdMatch = matchPath('subjects/{id}', $route);
if ($subjectIdMatch) {
    $subId = $subjectIdMatch['id'];
    if ($method === 'DELETE') {
        $teacher = authenticateTeacher($pdo);

        $stmt = $pdo->prepare("DELETE FROM subjects WHERE id = :id");
        $stmt->execute([':id' => $subId]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "SUBJECT_DELETE", "Deleted subject ID: " . $subId);
        sendJSON(['success' => true]);
    }
}

// =================================================================
// 10. STUDENTS MANAGEMENT
// =================================================================

// GET and POST students
if ($route === 'students') {
    if ($method === 'GET') {
        $teacher = authenticateTeacher($pdo);
        $stmt = $pdo->query("SELECT * FROM students ORDER BY fullName ASC");
        $students = $stmt->fetchAll();
        sendJSON($students);
    } 
    elseif ($method === 'POST') {
        $teacher = authenticateTeacher($pdo);
        $data = getInputData();

        $fullName = isset($data['fullName']) ? trim($data['fullName']) : '';
        $rollNumber = isset($data['rollNumber']) ? trim($data['rollNumber']) : '';
        $className = isset($data['className']) ? trim($data['className']) : '';

        if (empty($fullName) || empty($rollNumber) || empty($className)) {
            sendJSON(['error' => 'Full Name, Roll Number, and Class Name are required.'], 400);
        }

        $id = 'std-' . uniqid();
        $stmt = $pdo->prepare("INSERT INTO students (id, fullName, rollNumber, className, section, phone, email, gender) VALUES (:id, :name, :roll, :class, :sec, :ph, :em, :gen)");
        $stmt->execute([
            ':id' => $id,
            ':name' => $fullName,
            ':roll' => $rollNumber,
            ':class' => $className,
            ':sec' => isset($data['section']) ? trim($data['section']) : null,
            ':ph' => isset($data['phone']) ? trim($data['phone']) : null,
            ':em' => isset($data['email']) ? trim($data['email']) : null,
            ':gen' => isset($data['gender']) ? trim($data['gender']) : 'Boy'
        ]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "STUDENT_CREATE", "Enrolled student: " . $fullName . " (" . $rollNumber . ")");
        sendJSON(['id' => $id, 'fullName' => $fullName, 'rollNumber' => $rollNumber]);
    }
}

// PUT and DELETE students/{id}
$studentIdMatch = matchPath('students/{id}', $route);
if ($studentIdMatch) {
    $stdId = $studentIdMatch['id'];
    
    if ($method === 'PUT') {
        $teacher = authenticateTeacher($pdo);
        $data = getInputData();

        $fullName = isset($data['fullName']) ? trim($data['fullName']) : '';
        $rollNumber = isset($data['rollNumber']) ? trim($data['rollNumber']) : '';
        $className = isset($data['className']) ? trim($data['className']) : '';

        if (empty($fullName) || empty($rollNumber) || empty($className)) {
            sendJSON(['error' => 'Full Name, Roll Number, and Class Name are required.'], 400);
        }

        $stmt = $pdo->prepare("UPDATE students SET fullName = :name, rollNumber = :roll, className = :class, section = :sec, phone = :ph, email = :em, gender = :gen WHERE id = :id");
        $stmt->execute([
            ':name' => $fullName,
            ':roll' => $rollNumber,
            ':class' => $className,
            ':sec' => isset($data['section']) ? trim($data['section']) : null,
            ':ph' => isset($data['phone']) ? trim($data['phone']) : null,
            ':em' => isset($data['email']) ? trim($data['email']) : null,
            ':gen' => isset($data['gender']) ? trim($data['gender']) : 'Boy',
            ':id' => $stdId
        ]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "STUDENT_UPDATE", "Updated student: " . $fullName . " (" . $rollNumber . ")");
        sendJSON(['success' => true]);
    } 
    elseif ($method === 'DELETE') {
        $teacher = authenticateTeacher($pdo);

        $stmt = $pdo->prepare("DELETE FROM students WHERE id = :id");
        $stmt->execute([':id' => $stdId]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "STUDENT_DELETE", "Expelled / Deleted student ID: " . $stdId);
        sendJSON(['success' => true]);
    }
}

// =================================================================
// 11. TEACHERS & SECURITY
// =================================================================

// GET and POST admin/teachers
if ($route === 'admin/teachers') {
    $teacher = authenticateTeacher($pdo);
    if ($teacher['id'] !== 't-1') {
        sendJSON(['error' => 'Only the administrative director can manage staff.'], 403);
    }

    if ($method === 'GET') {
        $stmt = $pdo->query("SELECT id, email, name FROM teachers ORDER BY name ASC");
        $teachers = $stmt->fetchAll();
        sendJSON($teachers);
    } 
    elseif ($method === 'POST') {
        $data = getInputData();
        $name = isset($data['name']) ? trim($data['name']) : '';
        $email = isset($data['email']) ? trim($data['email']) : '';
        $password = isset($data['password']) ? trim($data['password']) : '';

        if (empty($name) || empty($email) || empty($password)) {
            sendJSON(['error' => 'All fields (name, email, password) are required.'], 400);
        }

        $id = 't-' . uniqid();
        $pwdHash = hashPassword($password);

        $stmt = $pdo->prepare("INSERT INTO teachers (id, email, name, passwordHash) VALUES (:id, :email, :name, :hash)");
        $stmt->execute([
            ':id' => $id,
            ':email' => $email,
            ':name' => $name,
            ':hash' => $pwdHash
        ]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "TEACHER_CREATE", "Enrolled new teacher: " . $name . " (" . $email . ")");
        sendJSON(['id' => $id, 'name' => $name, 'email' => $email]);
    }
}

// PUT and DELETE admin/teachers/{id}
$teacherIdMatch = matchPath('admin/teachers/{id}', $route);
if ($teacherIdMatch) {
    $staffId = $teacherIdMatch['id'];
    $teacher = authenticateTeacher($pdo);
    
    if ($teacher['id'] !== 't-1') {
        sendJSON(['error' => 'Only the administrative director can manage staff.'], 403);
    }

    if ($method === 'PUT') {
        $data = getInputData();
        $name = isset($data['name']) ? trim($data['name']) : '';
        $email = isset($data['email']) ? trim($data['email']) : '';

        if (empty($name) || empty($email)) {
            sendJSON(['error' => 'Name and Email are required.'], 400);
        }

        if (!empty($data['password'])) {
            $stmt = $pdo->prepare("UPDATE teachers SET name = :name, email = :email, passwordHash = :hash WHERE id = :id");
            $stmt->execute([
                ':name' => $name,
                ':email' => $email,
                ':hash' => hashPassword($data['password']),
                ':id' => $staffId
            ]);
        } else {
            $stmt = $pdo->prepare("UPDATE teachers SET name = :name, email = :email WHERE id = :id");
            $stmt->execute([
                ':name' => $name,
                ':email' => $email,
                ':id' => $staffId
            ]);
        }

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "TEACHER_UPDATE", "Updated staff profile: " . $name);
        sendJSON(['success' => true]);
    } 
    elseif ($method === 'DELETE') {
        if ($staffId === 't-1') {
            sendJSON(['error' => 'The main administrative director account cannot be deleted.'], 400);
        }

        $stmt = $pdo->prepare("DELETE FROM teachers WHERE id = :id");
        $stmt->execute([':id' => $staffId]);

        addAuditLog($pdo, $teacher['id'], $teacher['name'], "TEACHER_DELETE", "Deleted staff account ID: " . $staffId);
        sendJSON(['success' => true]);
    }
}

// POST admin/change-credentials
if ($route === 'admin/change-credentials' && $method === 'POST') {
    $teacher = authenticateTeacher($pdo);
    $data = getInputData();

    $name = isset($data['name']) ? trim($data['name']) : '';
    $email = isset($data['email']) ? trim($data['email']) : '';
    $password = isset($data['password']) ? trim($data['password']) : '';

    if (empty($name) || empty($email)) {
        sendJSON(['error' => 'Name and Email are required.'], 400);
    }

    if (!empty($password)) {
        $stmt = $pdo->prepare("UPDATE teachers SET name = :name, email = :email, passwordHash = :hash WHERE id = :id");
        $stmt->execute([
            ':name' => $name,
            ':email' => $email,
            ':hash' => hashPassword($password),
            ':id' => $teacher['id']
        ]);
    } else {
        $stmt = $pdo->prepare("UPDATE teachers SET name = :name, email = :email WHERE id = :id");
        $stmt->execute([
            ':name' => $name,
            ':email' => $email,
            ':id' => $teacher['id']
        ]);
    }

    addAuditLog($pdo, $teacher['id'], $teacher['name'], "CREDENTIALS_CHANGE", "Teacher changed personal profile credentials.");
    sendJSON(['success' => true]);
}

// POST admin/restore
if ($route === 'admin/restore' && $method === 'POST') {
    $teacher = authenticateTeacher($pdo);
    
    // Simulating system database restore from seeded tables
    addAuditLog($pdo, $teacher['id'], $teacher['name'], "DATABASE_RESTORE", "Triggered standard database schema integrity sync.");
    sendJSON(['message' => 'LMS Relational schema verified and intact.']);
}

// POST attempts/{id}/score
$scoreMatch = matchPath('attempts/{id}/score', $route);
if ($scoreMatch && $method === 'POST') {
    $teacher = authenticateTeacher($pdo);
    $attemptId = $scoreMatch['id'];
    $data = getInputData();

    $newScore = isset($data['score']) ? (float)$data['score'] : null;
    if ($newScore === null) {
        sendJSON(['error' => 'Score is required.'], 400);
    }

    // Update attempt score and recalculate percentage
    $stmtAtt = $pdo->prepare("SELECT quizId FROM attempts WHERE id = :id");
    $stmtAtt->execute([':id' => $attemptId]);
    $quizId = $stmtAtt->fetchColumn();

    if (!$quizId) {
        sendJSON(['error' => 'Attempt not found.'], 404);
    }

    $stmtQuiz = $pdo->prepare("SELECT maxMarks, passingPercentage FROM quizzes WHERE id = :id");
    $stmtQuiz->execute([':id' => $quizId]);
    $quiz = $stmtQuiz->fetch();

    $maxMarks = $quiz ? (float)$quiz['maxMarks'] : 100.0;
    if ($maxMarks <= 0) $maxMarks = 100.0;

    $percentage = ($newScore / $maxMarks) * 100.0;
    if ($percentage < 0) $percentage = 0.0;
    if ($percentage > 100) $percentage = 100.0;

    $passed = $percentage >= ($quiz ? (float)$quiz['passingPercentage'] : 50.0) ? 1 : 0;

    $stmtUpdate = $pdo->prepare("UPDATE attempts SET score = :score, percentage = :percentage, passed = :passed WHERE id = :id");
    $stmtUpdate->execute([
        ':score' => $newScore,
        ':percentage' => $percentage,
        ':passed' => $passed,
        ':id' => $attemptId
    ]);

    addAuditLog($pdo, $teacher['id'], $teacher['name'], "ATTEMPT_GRADE_OVERRIDE", "Manually overrode score for attempt ID: " . $attemptId . " to: " . $newScore);
    sendJSON(['success' => true]);
}

// If no route matches, return 404
sendJSON(['error'