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

    $action = $data['action'] ?? '';

    switch ($action) {
        case 'save_grades':
            handleSaveGrades($db, $userId, $data);
            break;

        case 'bulk_grade':
            handleBulkGrade($db, $userId, $data);
            break;

        case 'save_feedback':
            handleSaveFeedback($db, $userId, $data);
            break;

        case 'get_grading_stats':
            handleGetGradingStats($db, $userId);
            break;

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

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

function handleSaveGrades($db, $userId, $data) {
    $attemptId = intval($data['attempt_id'] ?? 0);
    $questionScores = $data['question_scores'] ?? [];
    $questionFeedback = $data['question_feedback'] ?? [];
    $overallFeedback = $data['feedback'] ?? '';

    if (!$attemptId) {
        throw new Exception('Attempt ID is required');
    }

    // Verify access to this attempt
    $stmt = $db->prepare("
        SELECT ea.*, e.instructor_id, e.passing_score
        FROM exam_attempts ea
        JOIN exams e ON ea.exam_id = e.id
        WHERE ea.id = ?
    ");
    $stmt->execute([$attemptId]);
    $attempt = $stmt->fetch(PDO::FETCH_ASSOC);

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

    if ($attempt['instructor_id'] !== $userId && !hasAnyRole(['admin'])) {
        throw new Exception('Access denied');
    }

    $db->beginTransaction();

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

        $totalScore = 0;
        $maxScore = 0;

        // Process each question
        foreach ($questions as $question) {
            $maxScore += $question['points'];
            $questionId = $question['question_id'];

            $earnedPoints = 0;
            $feedback = $questionFeedback[$questionId] ?? '';

            if (isset($questionScores[$questionId])) {
                // Manually graded question
                $earnedPoints = floatval($questionScores[$questionId]);
                $earnedPoints = min($earnedPoints, $question['points']); // Cap at max points
            } else {
                // Auto-grade objective questions
                if (in_array($question['question_type'], ['mcq_single', 'mcq_multiple', 'true_false', 'matching'])) {
                    $studentAnswers = json_decode($attempt['answers'], true) ?: [];
                    $earnedPoints = calculateObjectiveScore($db, $questionId, $studentAnswers[$questionId] ?? null);
                }
            }

            $totalScore += $earnedPoints;

            // Save question-level grade
            $stmt = $db->prepare("
                INSERT INTO exam_question_grades (attempt_id, question_id, points_earned, feedback, graded_by, graded_at)
                VALUES (?, ?, ?, ?, ?, NOW())
                ON DUPLICATE KEY UPDATE
                    points_earned = VALUES(points_earned),
                    feedback = VALUES(feedback),
                    graded_by = VALUES(graded_by),
                    graded_at = NOW()
            ");
            $stmt->execute([$attemptId, $questionId, $earnedPoints, $feedback, $userId]);
        }

        $percentage = $maxScore > 0 ? round(($totalScore / $maxScore) * 100, 2) : 0;
        $passingScore = $attempt['passing_score'] ?? 50;
        $isPassed = $percentage >= $passingScore;

        // Update attempt with overall score and feedback
        $stmt = $db->prepare("
            UPDATE exam_attempts
            SET score = ?, max_score = ?, percentage = ?, is_passed = ?, feedback = ?,
                graded_at = NOW(), graded_by = ?
            WHERE id = ?
        ");
        $stmt->execute([$totalScore, $maxScore, $percentage, $isPassed ? 1 : 0, $overallFeedback, $userId, $attemptId]);

        $db->commit();

        echo json_encode([
            'success' => true,
            'message' => 'Grades saved successfully',
            'data' => [
                'score' => $totalScore,
                'max_score' => $maxScore,
                'percentage' => $percentage,
                'passed' => $isPassed
            ]
        ]);

    } catch (Exception $e) {
        $db->rollBack();
        throw $e;
    }
}

function handleBulkGrade($db, $userId, $data) {
    $attemptIds = $data['attempt_ids'] ?? [];
    $defaultScore = floatval($data['default_score'] ?? 0);

    if (empty($attemptIds)) {
        throw new Exception('No attempts selected');
    }

    $db->beginTransaction();

    try {
        $updated = 0;

        foreach ($attemptIds as $attemptId) {
            // Verify access
            $stmt = $db->prepare("
                SELECT ea.*, e.instructor_id, e.passing_score
                FROM exam_attempts ea
                JOIN exams e ON ea.exam_id = e.id
                WHERE ea.id = ? AND ea.status = 'completed'
            ");
            $stmt->execute([$attemptId]);
            $attempt = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$attempt || ($attempt['instructor_id'] !== $userId && !hasAnyRole(['admin']))) {
                continue; // Skip this attempt
            }

            // Get questions needing manual grading
            $stmt = $db->prepare("
                SELECT SUM(eq.points) as manual_points
                FROM exam_questions eq
                JOIN questions q ON eq.question_id = q.id
                WHERE eq.exam_id = ? AND q.question_type IN ('essay', 'short_answer', 'code', 'fill_blanks')
                AND JSON_EXTRACT(ea.answers, CONCAT('$.', eq.question_id)) IS NOT NULL
            ");
            $stmt->execute([$attempt['exam_id']]);
            $manualPoints = $stmt->fetch(PDO::FETCH_ASSOC)['manual_points'] ?: 0;

            // Calculate score: auto-graded + manual default
            $autoScore = calculateAutoScore($db, $attempt['exam_id'], json_decode($attempt['answers'], true) ?: []);
            $totalScore = $autoScore + min($defaultScore, $manualPoints);

            // Get max score
            $stmt = $db->prepare("SELECT SUM(points) as max_score FROM exam_questions WHERE exam_id = ?");
            $stmt->execute([$attempt['exam_id']]);
            $maxScore = $stmt->fetch(PDO::FETCH_ASSOC)['max_score'];

            $percentage = $maxScore > 0 ? round(($totalScore / $maxScore) * 100, 2) : 0;
            $isPassed = $percentage >= $attempt['passing_score'];

            // Update attempt
            $stmt = $db->prepare("
                UPDATE exam_attempts
                SET score = ?, max_score = ?, percentage = ?, is_passed = ?,
                    graded_at = NOW(), graded_by = ?
                WHERE id = ?
            ");
            $stmt->execute([$totalScore, $maxScore, $percentage, $isPassed ? 1 : 0, $userId, $attemptId]);

            $updated++;
        }

        $db->commit();

        echo json_encode([
            'success' => true,
            'message' => "Bulk graded $updated submissions",
            'updated_count' => $updated
        ]);

    } catch (Exception $e) {
        $db->rollBack();
        throw $e;
    }
}

function handleSaveFeedback($db, $userId, $data) {
    $attemptId = intval($data['attempt_id'] ?? 0);
    $feedback = $data['feedback'] ?? '';

    if (!$attemptId) {
        throw new Exception('Attempt ID is required');
    }

    // Verify access
    $stmt = $db->prepare("
        SELECT e.instructor_id
        FROM exam_attempts ea
        JOIN exams e ON ea.exam_id = e.id
        WHERE ea.id = ?
    ");
    $stmt->execute([$attemptId]);
    $attempt = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$attempt || ($attempt['instructor_id'] !== $userId && !hasAnyRole(['admin']))) {
        throw new Exception('Access denied');
    }

    // Update feedback
    $stmt = $db->prepare("
        UPDATE exam_attempts
        SET feedback = ?, graded_at = NOW(), graded_by = ?
        WHERE id = ?
    ");
    $stmt->execute([$feedback, $userId, $attemptId]);

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

function handleGetGradingStats($db, $userId) {
    // Get grading statistics
    $stmt = $db->prepare("
        SELECT
            COUNT(CASE WHEN ea.status = 'completed' AND (
                EXISTS (
                    SELECT 1 FROM exam_questions eq
                    JOIN questions q ON eq.question_id = q.id
                    WHERE eq.exam_id = e.id AND q.question_type IN ('essay', 'short_answer', 'code', 'fill_blanks')
                    AND JSON_EXTRACT(ea.answers, CONCAT('$.', eq.question_id)) IS NOT NULL
                ) OR ea.score IS NULL
            ) THEN 1 END) as pending_count,
            COUNT(CASE WHEN ea.status = 'completed' AND ea.score IS NOT NULL THEN 1 END) as graded_count,
            COUNT(CASE WHEN ea.status = 'in_progress' THEN 1 END) as in_progress_count,
            AVG(TIMESTAMPDIFF(HOUR, ea.completed_at, NOW())) as avg_hours_pending
        FROM exam_attempts ea
        JOIN exams e ON ea.exam_id = e.id
        WHERE e.instructor_id = ?
    ");
    $stmt->execute([$userId]);
    $stats = $stmt->fetch(PDO::FETCH_ASSOC);

    echo json_encode([
        'success' => true,
        'stats' => [
            'pending' => intval($stats['pending_count']),
            'graded' => intval($stats['graded_count']),
            'in_progress' => intval($stats['in_progress_count']),
            'avg_pending_hours' => round(floatval($stats['avg_hours_pending']), 1)
        ]
    ]);
}

function calculateObjectiveScore($db, $questionId, $studentAnswer) {
    if (!$studentAnswer) return 0;

    // Get question details
    $stmt = $db->prepare("
        SELECT q.question_type, q.points, qo.id, qo.is_correct
        FROM questions q
        LEFT JOIN question_options qo ON q.id = qo.question_id
        WHERE q.id = ?
    ");
    $stmt->execute([$questionId]);
    $questionData = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if (empty($questionData)) return 0;

    $question = [
        'type' => $questionData[0]['question_type'],
        'points' => $questionData[0]['points'],
        'options' => array_filter($questionData, fn($row) => $row['id'] !== null)
    ];

    switch ($question['type']) {
        case 'mcq_single':
        case 'true_false':
            foreach ($question['options'] as $option) {
                if ($option['id'] == $studentAnswer && $option['is_correct']) {
                    return $question['points'];
                }
            }
            return 0;

        case 'mcq_multiple':
            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;
                        }
                    }
                }

                return $totalCorrect > 0 ? ($selectedCorrect / $totalCorrect) * $question['points'] : 0;
            }
            return 0;

        case 'matching':
            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++;
                        }
                    }
                }

                return $totalMatches > 0 ? ($correctMatches / $totalMatches) * $question['points'] : 0;
            }
            return 0;

        default:
            return 0;
    }
}

function calculateAutoScore($db, $examId, $answers) {
    $score = 0;

    // Get all questions
    $stmt = $db->prepare("
        SELECT eq.question_id, eq.points, q.question_type
        FROM exam_questions eq
        JOIN questions q ON eq.question_id = q.id
        WHERE eq.exam_id = ? AND q.question_type NOT IN ('essay', 'short_answer', 'code', 'fill_blanks')
    ");
    $stmt->execute([$examId]);
    $questions = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($questions as $question) {
        $studentAnswer = $answers[$question['question_id']] ?? null;
        $questionScore = calculateObjectiveScore($db, $question['question_id'], $studentAnswer);
        $score += $questionScore;
    }

    return $score;
}
?>