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

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

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

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

try {
    switch ($method) {
        case 'GET':
            handleGetExams($db, $userId, $role);
            break;
        case 'POST':
            handleCreateExam($db, $userId, $role);
            break;
        case 'PUT':
            handleUpdateExam($db, $userId, $role);
            break;
        case 'DELETE':
            handleDeleteExam($db, $userId, $role);
            break;
        default:
            http_response_code(405);
            echo json_encode(['success' => false, 'message' => 'Method not allowed']);
    }
} catch (Throwable $e) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}

function handleGetExams(PDO $db, int $userId, string $role): void
{
    $search = $_GET['search'] ?? '';
    $type = $_GET['type'] ?? '';
    $status = $_GET['status'] ?? '';
    $course = $_GET['course'] ?? '';
    $limit = max(1, min(200, (int) ($_GET['limit'] ?? 50)));
    $offset = max(0, (int) ($_GET['offset'] ?? 0));

    $params = [];
    $where = [];

    if ($role === 'instructor') {
        $where[] = 'e.instructor_id = ?';
        $params[] = $userId;
    }

    if ($search !== '') {
        $where[] = '(e.title LIKE ? OR e.description LIKE ?)';
        $params[] = "%$search%";
        $params[] = "%$search%";
    }
    if ($type !== '') {
        $where[] = 'e.exam_type = ?';
        $params[] = $type;
    }
    if ($status !== '') {
        $where[] = 'e.status = ?';
        $params[] = $status;
    }
    if ($course !== '') {
        $where[] = 'e.course_id = ?';
        $params[] = $course;
    }

    $whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
    $stmt = $db->prepare("
        SELECT e.*, c.title as course_title,
               COUNT(eq.id) as question_count,
               COUNT(DISTINCT ea.student_id) as attempt_count,
               SUM(CASE WHEN q.question_type IN ('essay','short_answer','code') THEN 1 ELSE 0 END) as manual_question_count
        FROM exams e
        LEFT JOIN courses c ON c.id = e.course_id
        LEFT JOIN exam_questions eq ON eq.exam_id = e.id
        LEFT JOIN questions q ON q.id = eq.question_id
        LEFT JOIN exam_attempts ea ON ea.exam_id = e.id
        $whereSql
        GROUP BY e.id
        ORDER BY e.created_at DESC
        LIMIT $limit OFFSET $offset
    ");
    $stmt->execute($params);
    $exams = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($exams as &$exam) {
        $exam['proctoring_settings'] = decodeJson($exam['proctoring_settings']);
        $exam['security_settings'] = decodeJson($exam['security_settings']);
        $exam['question_count'] = (int) $exam['question_count'];
        $exam['attempt_count'] = (int) $exam['attempt_count'];
        $exam['manual_question_count'] = (int) ($exam['manual_question_count'] ?? 0);
    }
    unset($exam);

    echo json_encode([
        'success' => true,
        'data' => $exams,
        'meta' => ['limit' => $limit, 'offset' => $offset]
    ]);
}

function handleCreateExam(PDO $db, int $userId, string $role): void
{
    if (!in_array($role, ['instructor','admin'], true)) {
        throw new Exception('Access denied');
    }

    $data = json_decode(file_get_contents('php://input'), true);
    if (!is_array($data)) {
        throw new Exception('Invalid JSON data');
    }
    if (empty($data['title'])) {
        throw new Exception('Exam title is required');
    }
    if (empty($data['question_ids']) || !is_array($data['question_ids'])) {
        throw new Exception('At least one question must be selected');
    }

    $questionIds = array_values($data['question_ids']);
    $questionPoints = $data['question_points'] ?? [];
    $totalPoints = 0.0;
    foreach ($questionIds as $index => $questionId) {
        $totalPoints += floatval($questionPoints[$index] ?? 1);
    }

    $db->beginTransaction();
    try {
        $slug = generateSlug($db, $data['title'], $userId, null);
        $stmt = $db->prepare("
            INSERT INTO exams (
                title, slug, description, course_id, instructor_id, exam_type,
                total_points, passing_score, time_limit, max_attempts,
                shuffle_questions, shuffle_options, show_results, show_answers,
                allow_review, start_date, end_date, is_proctored,
                proctoring_settings, security_settings, instructions,
                status, is_template, price, currency, is_free,
                created_at, updated_at
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
        ");
        $stmt->execute([
            $data['title'],
            $slug,
            $data['description'] ?? '',
            isset($data['course_id']) ? (int) $data['course_id'] : null,
            $userId,
            $data['exam_type'] ?? 'quiz',
            $totalPoints,
            floatval($data['passing_score'] ?? 50),
            isset($data['time_limit']) ? (int) $data['time_limit'] : null,
            (int) ($data['max_attempts'] ?? 1),
            !empty($data['shuffle_questions']) ? 1 : 0,
            !empty($data['shuffle_options']) ? 1 : 0,
            !isset($data['show_results']) || $data['show_results'] ? 1 : 0,
            !empty($data['show_answers']) ? 1 : 0,
            !isset($data['allow_review']) || $data['allow_review'] ? 1 : 0,
            $data['start_date'] ?? null,
            $data['end_date'] ?? null,
            !empty($data['is_proctored']) ? 1 : 0,
            json_encode($data['proctoring_settings'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            json_encode($data['security_settings'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            $data['instructions'] ?? '',
            $data['status'] ?? 'draft',
            !empty($data['is_template']) ? 1 : 0,
            floatval($data['price'] ?? 0),
            $data['currency'] ?? 'USD',
            !empty($data['is_free']) ? 1 : 0
        ]);
        $examId = (int) $db->lastInsertId();

        insertExamQuestions($db, $examId, $questionIds, $questionPoints);
        $db->commit();
    } catch (Throwable $e) {
        $db->rollBack();
        throw $e;
    }

    echo json_encode(['success' => true, 'message' => 'Exam created successfully', 'data' => ['id' => $examId]]);
}

function handleUpdateExam(PDO $db, int $userId, string $role): void
{
    if (!in_array($role, ['instructor','admin'], true)) {
        throw new Exception('Access denied');
    }

    $data = json_decode(file_get_contents('php://input'), true);
    if (!is_array($data) || empty($data['id'])) {
        throw new Exception('Exam ID is required');
    }

    $examId = (int) $data['id'];
    $stmt = $db->prepare("SELECT * FROM exams WHERE id = ?");
    $stmt->execute([$examId]);
    $exam = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$exam) {
        throw new Exception('Exam not found');
    }
    if ($role !== 'admin' && (int) $exam['instructor_id'] !== $userId) {
        throw new Exception('Access denied');
    }

    $questionIds = $data['question_ids'] ?? null;
    $questionPoints = $data['question_points'] ?? [];
    $totalPoints = 0.0;
    if (is_array($questionIds)) {
        foreach ($questionIds as $index => $questionId) {
            $totalPoints += floatval($questionPoints[$index] ?? 1);
        }
    }

    $db->beginTransaction();
    try {
        $stmt = $db->prepare("
            UPDATE exams
            SET title = ?, description = ?, course_id = ?, exam_type = ?,
                total_points = ?, passing_score = ?, time_limit = ?, max_attempts = ?,
                shuffle_questions = ?, shuffle_options = ?, show_results = ?, show_answers = ?,
                allow_review = ?, start_date = ?, end_date = ?, is_proctored = ?,
                proctoring_settings = ?, security_settings = ?, instructions = ?,
                status = ?, is_template = ?, price = ?, currency = ?, is_free = ?,
                updated_at = NOW()
            WHERE id = ?
        ");
        $stmt->execute([
            $data['title'] ?? $exam['title'],
            $data['description'] ?? $exam['description'],
            array_key_exists('course_id', $data) ? (int) $data['course_id'] : $exam['course_id'],
            $data['exam_type'] ?? $exam['exam_type'],
            is_array($questionIds) ? $totalPoints : floatval($exam['total_points']),
            isset($data['passing_score']) ? floatval($data['passing_score']) : floatval($exam['passing_score']),
            array_key_exists('time_limit', $data) ? (int) $data['time_limit'] : $exam['time_limit'],
            isset($data['max_attempts']) ? (int) $data['max_attempts'] : (int) $exam['max_attempts'],
            isset($data['shuffle_questions']) ? (int) $data['shuffle_questions'] : (int) $exam['shuffle_questions'],
            isset($data['shuffle_options']) ? (int) $data['shuffle_options'] : (int) $exam['shuffle_options'],
            isset($data['show_results']) ? (int) $data['show_results'] : (int) $exam['show_results'],
            isset($data['show_answers']) ? (int) $data['show_answers'] : (int) $exam['show_answers'],
            isset($data['allow_review']) ? (int) $data['allow_review'] : (int) $exam['allow_review'],
            array_key_exists('start_date', $data) ? $data['start_date'] : $exam['start_date'],
            array_key_exists('end_date', $data) ? $data['end_date'] : $exam['end_date'],
            isset($data['is_proctored']) ? (int) $data['is_proctored'] : (int) $exam['is_proctored'],
            json_encode($data['proctoring_settings'] ?? decodeJson($exam['proctoring_settings']), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            json_encode($data['security_settings'] ?? decodeJson($exam['security_settings']), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            $data['instructions'] ?? $exam['instructions'],
            $data['status'] ?? $exam['status'],
            isset($data['is_template']) ? (int) $data['is_template'] : (int) $exam['is_template'],
            isset($data['price']) ? floatval($data['price']) : floatval($exam['price']),
            $data['currency'] ?? $exam['currency'],
            isset($data['is_free']) ? (int) $data['is_free'] : (int) $exam['is_free'],
            $examId
        ]);

        if (is_array($questionIds)) {
            $db->prepare("DELETE FROM exam_questions WHERE exam_id = ?")->execute([$examId]);
            insertExamQuestions($db, $examId, array_values($questionIds), $questionPoints);
        }

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

    echo json_encode(['success' => true, 'message' => 'Exam updated successfully', 'data' => ['id' => $examId]]);
}

function handleDeleteExam(PDO $db, int $userId, string $role): void
{
    if (!in_array($role, ['instructor','admin'], true)) {
        throw new Exception('Access denied');
    }

    $data = json_decode(file_get_contents('php://input'), true);
    if (!is_array($data) || empty($data['id'])) {
        throw new Exception('Exam ID is required');
    }

    $examId = (int) $data['id'];
    $stmt = $db->prepare("SELECT instructor_id FROM exams WHERE id = ?");
    $stmt->execute([$examId]);
    $exam = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$exam) {
        throw new Exception('Exam not found');
    }
    if ($role !== 'admin' && (int) $exam['instructor_id'] !== $userId) {
        throw new Exception('Access denied');
    }

    $stmt = $db->prepare("SELECT COUNT(*) FROM exam_attempts WHERE exam_id = ?");
    $stmt->execute([$examId]);
    if ((int) $stmt->fetchColumn() > 0) {
        throw new Exception('Cannot delete an exam that has student attempts');
    }

    $db->beginTransaction();
    try {
        $db->prepare("DELETE FROM exam_questions WHERE exam_id = ?")->execute([$examId]);
        $db->prepare("DELETE FROM exam_access WHERE exam_id = ?")->execute([$examId]);
        $db->prepare("DELETE FROM exams WHERE id = ?")->execute([$examId]);
        $db->commit();
    } catch (Throwable $e) {
        $db->rollBack();
        throw $e;
    }

    echo json_encode(['success' => true, 'message' => 'Exam deleted successfully']);
}

function insertExamQuestions(PDO $db, int $examId, array $questionIds, array $questionPoints): void
{
    $stmt = $db->prepare("
        INSERT INTO exam_questions (exam_id, question_id, sort_order, points)
        VALUES (?, ?, ?, ?)
    ");
    foreach ($questionIds as $index => $questionId) {
        $stmt->execute([
            $examId,
            (int) $questionId,
            $index + 1,
            floatval($questionPoints[$index] ?? 1)
        ]);
    }
}

function generateSlug(PDO $db, string $title, int $userId, ?int $examId): string
{
    $slug = strtolower(trim(preg_replace('/[^A-Za-z0-9\s-]/', '', $title)));
    $slug = preg_replace('/\s+/', '-', $slug);
    $slug = trim($slug, '-') ?: 'exam';
    $original = $slug;
    $counter = 1;

    while (true) {
        $stmt = $db->prepare("SELECT id FROM exams WHERE slug = ? AND instructor_id = ?" . ($examId ? " AND id <> ?" : ""));
        if ($examId) {
            $stmt->execute([$slug, $userId, $examId]);
        } else {
            $stmt->execute([$slug, $userId]);
        }
        if (!$stmt->fetch()) {
            return $slug;
        }
        $slug = $original . '-' . $counter++;
    }
}

function decodeJson($value)
{
    if ($value === null || $value === '') {
        return [];
    }
    if (is_array($value)) {
        return $value;
    }
    $decoded = json_decode($value, true);
    return json_last_error() === JSON_ERROR_NONE ? $decoded : [];
}
