<?php
require_once '../config/database.php';
require_once '../config/auth.php';
require_once '../config/rbac.php';
require_once '../includes/functions.php';

// Set JSON response header
header('Content-Type: application/json');

// Check authentication
if (!isLoggedIn()) {
    http_response_code(401);
    echo json_encode(['success' => false, 'message' => 'Authentication required']);
    exit;
}

$db = getDB();
$userId = $_SESSION['user_id'];
$method = $_SERVER['REQUEST_METHOD'];

try {
    if ($method !== 'POST') {
        throw new Exception('Method not allowed');
    }

    $data = json_decode(file_get_contents('php://input'), true);
    if (!$data) {
        throw new Exception('Invalid JSON data');
    }

    $examId = intval($data['exam_id'] ?? 0);
    $action = $data['action'] ?? '';

    if (!$examId || !$action) {
        throw new Exception('Exam ID and action are required');
    }

    // Verify exam exists and is published
    $stmt = $db->prepare("SELECT * FROM exams WHERE id = ? AND status = 'published'");
    $stmt->execute([$examId]);
    $exam = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$exam) {
        throw new Exception('Exam not found or not available');
    }

    // Check permissions based on user role
    if (hasAnyRole(['student'])) {
        // Student permissions - can only access their own attempts
        $studentId = $userId;

        // Check if student is enrolled in course (if exam is course-specific)
        if ($exam['course_id']) {
            $stmt = $db->prepare("SELECT id FROM course_enrollments WHERE course_id = ? AND student_id = ? AND status IN ('enrolled', 'in_progress')");
            $stmt->execute([$exam['course_id'], $studentId]);
            if (!$stmt->fetch()) {
                throw new Exception('You must be enrolled in this course to take this exam');
            }
        }
    } elseif (hasAnyRole(['instructor', 'admin'])) {
        // Instructor permissions - can access any attempt for their exams
        if ($exam['instructor_id'] !== $userId && !hasAnyRole(['admin'])) {
            throw new Exception('Access denied');
        }
        $studentId = intval($data['student_id'] ?? 0);
        if (!$studentId) {
            throw new Exception('Student ID required for instructor actions');
        }
    } else {
        throw new Exception('Access denied');
    }

    switch ($action) {
        case 'start':
            // Start a new exam attempt
            handleStartAttempt($db, $examId, $studentId, $exam);
            break;

        case 'save':
            // Save progress
            handleSaveProgress($db, $examId, $studentId, $data);
            break;

        case 'submit':
            // Submit exam
            handleSubmitExam($db, $examId, $studentId, $data, $exam);
            break;

        case 'get':
            // Get attempt details
            handleGetAttempt($db, $examId, $studentId);
            break;

        default:
            throw new Exception('Invalid action');
    }

} catch (Exception $e) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}

function handleStartAttempt($db, $examId, $studentId, $exam) {
    // Check if student already has an in-progress attempt
    $stmt = $db->prepare("
        SELECT id, attempt_number FROM exam_attempts
        WHERE exam_id = ? AND student_id = ? AND status = 'in_progress'
        ORDER BY started_at DESC LIMIT 1
    ");
    $stmt->execute([$examId, $studentId]);
    $existingAttempt = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($existingAttempt) {
        // Resume existing attempt
        echo json_encode([
            'success' => true,
            'message' => 'Resumed existing attempt',
            'attempt_id' => $existingAttempt['id'],
            'attempt_number' => $existingAttempt['attempt_number']
        ]);
        return;
    }

    // Check attempt limits
    $stmt = $db->prepare("
        SELECT COUNT(*) as attempt_count, MAX(attempt_number) as max_attempt
        FROM exam_attempts
        WHERE exam_id = ? AND student_id = ?
    ");
    $stmt->execute([$examId, $studentId]);
    $attemptInfo = $stmt->fetch(PDO::FETCH_ASSOC);

    $nextAttemptNumber = ($attemptInfo['max_attempt'] ?? 0) + 1;

    if ($exam['max_attempts'] > 0 && $nextAttemptNumber > $exam['max_attempts']) {
        throw new Exception('Maximum attempts exceeded');
    }

    // Create new attempt
    $stmt = $db->prepare("
        INSERT INTO exam_attempts (
            exam_id, student_id, attempt_number, status, started_at, answers, ip_address, browser_info
        ) VALUES (?, ?, ?, 'in_progress', NOW(), '{}', ?, ?)
    ");

    $ipAddress = $_SERVER['REMOTE_ADDR'] ?? '';
    $browserInfo = json_encode([
        'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
        'accept_language' => $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? ''
    ]);

    $stmt->execute([$examId, $studentId, $nextAttemptNumber, $ipAddress, $browserInfo]);
    $attemptId = $db->lastInsertId();

    echo json_encode([
        'success' => true,
        'message' => 'Exam attempt started',
        'attempt_id' => $attemptId,
        'attempt_number' => $nextAttemptNumber
    ]);
}

function handleSaveProgress($db, $examId, $studentId, $data) {
    // Find the in-progress attempt
    $stmt = $db->prepare("
        SELECT id FROM exam_attempts
        WHERE exam_id = ? AND student_id = ? AND status = 'in_progress'
        ORDER BY started_at DESC LIMIT 1
    ");
    $stmt->execute([$examId, $studentId]);
    $attempt = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$attempt) {
        throw new Exception('No active attempt found');
    }

    $answers = json_encode($data['answers'] ?? []);
    $timeSpent = intval($data['time_spent'] ?? 0);

    $stmt = $db->prepare("
        UPDATE exam_attempts
        SET answers = ?, time_spent = ?, last_accessed = NOW()
        WHERE id = ?
    ");
    $stmt->execute([$answers, $timeSpent, $attempt['id']]);

    echo json_encode(['success' => true, 'message' => 'Progress saved']);
}

function handleSubmitExam($db, $examId, $studentId, $data, $exam) {
    // Find the in-progress attempt
    $stmt = $db->prepare("
        SELECT id, answers FROM exam_attempts
        WHERE exam_id = ? AND student_id = ? AND status = 'in_progress'
        ORDER BY started_at DESC LIMIT 1
    ");
    $stmt->execute([$examId, $studentId]);
    $attempt = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$attempt) {
        throw new Exception('No active attempt found');
    }

    $answers = array_merge(
        json_decode($attempt['answers'], true) ?: [],
        $data['answers'] ?? []
    );

    $timeSpent = intval($data['time_spent'] ?? 0);

    // Calculate score
    $scoreData = calculateExamScore($db, $examId, $answers);

    // Update attempt
    $stmt = $db->prepare("
        UPDATE exam_attempts
        SET status = 'completed', completed_at = NOW(), time_spent = ?,
            answers = ?, score = ?, max_score = ?, percentage = ?, is_passed = ?
        WHERE id = ?
    ");

    $stmt->execute([
        $timeSpent,
        json_encode($answers),
        $scoreData['score'],
        $scoreData['max_score'],
        $scoreData['percentage'],
        $scoreData['is_passed'] ? 1 : 0,
        $attempt['id']
    ]);

    // Update question analytics
    updateQuestionAnalytics($db, $examId, $answers);

    echo json_encode([
        'success' => true,
        'message' => 'Exam submitted successfully',
        'score' => $scoreData['score'],
        'max_score' => $scoreData['max_score'],
        'percentage' => $scoreData['percentage'],
        'passed' => $scoreData['is_passed']
    ]);
}

function handleGetAttempt($db, $examId, $studentId) {
    $stmt = $db->prepare("
        SELECT ea.*, e.title as exam_title, e.total_points, e.passing_score
        FROM exam_attempts ea
        JOIN exams e ON ea.exam_id = e.id
        WHERE ea.exam_id = ? AND ea.student_id = ?
        ORDER BY ea.started_at DESC LIMIT 1
    ");
    $stmt->execute([$examId, $studentId]);
    $attempt = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$attempt) {
        throw new Exception('Attempt not found');
    }

    echo json_encode([
        'success' => true,
        'attempt' => $attempt
    ]);
}

function calculateExamScore($db, $examId, $answers) {
    // Get exam questions with correct answers
    $stmt = $db->prepare("
        SELECT eq.question_id, eq.points, q.question_type, qo.id as option_id, qo.is_correct
        FROM exam_questions eq
        JOIN questions q ON eq.question_id = q.id
        LEFT JOIN question_options qo ON q.id = qo.question_id
        WHERE eq.exam_id = ?
        ORDER BY eq.question_id, qo.id
    ");
    $stmt->execute([$examId]);
    $questionData = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // Group by question
    $questions = [];
    foreach ($questionData as $row) {
        $qid = $row['question_id'];
        if (!isset($questions[$qid])) {
            $questions[$qid] = [
                'type' => $row['question_type'],
                'points' => $row['points'],
                'options' => []
            ];
        }
        if ($row['option_id']) {
            $questions[$qid]['options'][] = [
                'id' => $row['option_id'],
                'is_correct' => $row['is_correct']
            ];
        }
    }

    $totalScore = 0;
    $maxScore = 0;

    foreach ($questions as $questionId => $question) {
        $maxScore += $question['points'];
        $studentAnswer = $answers[$questionId] ?? null;

        if (!$studentAnswer) {
            continue; // No answer given
        }

        $points = 0;

        switch ($question['type']) {
            case 'mcq_single':
            case 'true_false':
                // Check if selected option is correct
                foreach ($question['options'] as $option) {
                    if ($option['id'] == $studentAnswer && $option['is_correct']) {
                        $points = $question['points'];
                        break;
                    }
                }
                break;

            case 'mcq_multiple':
                // Check multiple selections
                if (is_array($studentAnswer)) {
                    $correctOptions = array_filter($question['options'], fn($opt) => $opt['is_correct']);
                    $selectedCorrect = 0;
                    $totalCorrect = count($correctOptions);

                    foreach ($studentAnswer as $selectedId) {
                        foreach ($correctOptions as $correctOption) {
                            if ($correctOption['id'] == $selectedId) {
                                $selectedCorrect++;
                                break;
                            }
                        }
                    }

                    // Partial credit: points proportional to correct selections
                    if ($totalCorrect > 0) {
                        $points = ($selectedCorrect / $totalCorrect) * $question['points'];
                    }
                }
                break;

            case 'essay':
            case 'short_answer':
            case 'code':
                // Manual grading required - for now, give 0 points
                // This will be updated when instructor grades
                $points = 0;
                break;

            case 'matching':
                // Check matching answers
                if (is_array($studentAnswer)) {
                    $correctMatches = 0;
                    $totalMatches = 0;

                    foreach ($question['options'] as $option) {
                        if ($option['is_correct']) {
                            $totalMatches++;
                            if (isset($studentAnswer[$option['id']]) &&
                                $studentAnswer[$option['id']] == $option['id']) {
                                $correctMatches++;
                            }
                        }
                    }

                    if ($totalMatches > 0) {
                        $points = ($correctMatches / $totalMatches) * $question['points'];
                    }
                }
                break;

            case 'fill_blanks':
                // Manual grading required
                $points = 0;
                break;
        }

        $totalScore += $points;
    }

    $percentage = $maxScore > 0 ? round(($totalScore / $maxScore) * 100, 2) : 0;

    return [
        'score' => round($totalScore, 2),
        'max_score' => $maxScore,
        'percentage' => $percentage,
        'is_passed' => $percentage >= 50 // Default passing score
    ];
}

function updateQuestionAnalytics($db, $examId, $answers) {
    // Get exam questions
    $stmt = $db->prepare("
        SELECT eq.question_id, q.question_type
        FROM exam_questions eq
        JOIN questions q ON eq.question_id = q.id
        WHERE eq.exam_id = ?
    ");
    $stmt->execute([$examId]);
    $questions = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $date = date('Y-m-d');

    foreach ($questions as $question) {
        $questionId = $question['question_id'];
        $studentAnswer = $answers[$questionId] ?? null;

        // Get correct answers
        $stmt = $db->prepare("
            SELECT COUNT(*) as correct_count FROM question_options
            WHERE question_id = ? AND is_correct = TRUE
        ");
        $stmt->execute([$questionId]);
        $correctCount = $stmt->fetch(PDO::FETCH_ASSOC)['correct_count'];

        $isCorrect = false;

        if ($studentAnswer) {
            switch ($question['question_type']) {
                case 'mcq_single':
                case 'true_false':
                    $stmt = $db->prepare("
                        SELECT is_correct FROM question_options
                        WHERE id = ? AND question_id = ?
                    ");
                    $stmt->execute([$studentAnswer, $questionId]);
                    $result = $stmt->fetch(PDO::FETCH_ASSOC);
                    $isCorrect = $result && $result['is_correct'];
                    break;

                case 'mcq_multiple':
                    if (is_array($studentAnswer)) {
                        $stmt = $db->prepare("
                            SELECT COUNT(*) as correct_selected FROM question_options
                            WHERE id IN (" . str_repeat('?,', count($studentAnswer) - 1) . "?) AND is_correct = TRUE
                        ");
                        $stmt->execute($studentAnswer);
                        $correctSelected = $stmt->fetch(PDO::FETCH_ASSOC)['correct_selected'];
                        $isCorrect = $correctSelected == $correctCount;
                    }
                    break;
            }
        }

        // Update or insert analytics
        $stmt = $db->prepare("
            INSERT INTO question_analytics (
                question_id, exam_id, date, times_used, correct_answers, incorrect_answers
            ) VALUES (?, ?, ?, 1, ?, ?)
            ON DUPLICATE KEY UPDATE
                times_used = times_used + 1,
                correct_answers = correct_answers + ?,
                incorrect_answers = incorrect_answers + ?
        ");

        $correct = $isCorrect ? 1 : 0;
        $incorrect = $isCorrect ? 0 : 1;

        $stmt->execute([
            $questionId, $examId, $date,
            $correct, $incorrect,
            $correct, $incorrect
        ]);
    }
}
?>