<?php
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../../config/auth.php';
require_once __DIR__ . '/../../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':
            handleGetQuestions($db, $userId, $role);
            break;
        case 'POST':
            handleCreateQuestion($db, $userId, $role);
            break;
        case 'PUT':
            handleUpdateQuestion($db, $userId, $role);
            break;
        case 'DELETE':
            handleDeleteQuestion($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 handleGetQuestions(PDO $db, int $userId, string $role): void
{
    $search = $_GET['search'] ?? '';
    $type = $_GET['type'] ?? '';
    $difficulty = $_GET['difficulty'] ?? '';
    $category = $_GET['category'] ?? '';
    $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[] = '(q.instructor_id = ? OR q.is_shared = TRUE)';
        $params[] = $userId;
    } elseif ($role === 'student') {
        $where[] = 'q.status = ?';
        $params[] = 'approved';
    }

    if ($search !== '') {
        $where[] = '(q.title LIKE ? OR q.content LIKE ?)';
        $params[] = "%$search%";
        $params[] = "%$search%";
    }
    if ($type !== '') {
        $where[] = 'q.question_type = ?';
        $params[] = $type;
    }
    if ($difficulty !== '') {
        $where[] = 'q.difficulty = ?';
        $params[] = $difficulty;
    }
    if ($category !== '') {
        $where[] = 'q.category_id = ?';
        $params[] = $category;
    }
    if ($status !== '') {
        $where[] = 'q.status = ?';
        $params[] = $status;
    }
    if ($course !== '') {
        $where[] = 'q.course_id = ?';
        $params[] = $course;
    }

    $whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
    $stmt = $db->prepare("
        SELECT q.id, q.title, q.content, q.question_type, q.difficulty, q.points, q.time_limit,
               q.category_id, q.course_id, q.instructor_id, q.tags, q.explanation, q.hints,
               q.metadata, q.status, q.review_status, q.usage_count, q.success_rate, q.is_shared,
               q.created_at, q.updated_at, qc.name as category_name, c.title as course_title,
               GROUP_CONCAT(DISTINCT qt.name) as tag_names
        FROM questions q
        LEFT JOIN question_categories qc ON qc.id = q.category_id
        LEFT JOIN courses c ON c.id = q.course_id
        LEFT JOIN question_tag_assignments qta ON qta.question_id = q.id
        LEFT JOIN question_tags qt ON qt.id = qta.tag_id
        $whereSql
        GROUP BY q.id
        ORDER BY q.created_at DESC
        LIMIT $limit OFFSET $offset
    ");
    $stmt->execute($params);
    $questions = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($questions as &$question) {
        $question['tags'] = decodeJson($question['tags']);
        $question['hints'] = decodeJson($question['hints']);
        $question['metadata'] = decodeJson($question['metadata']);
        $question['tags'] = $question['tag_names'] ? array_merge($question['tags'], array_filter(explode(',', $question['tag_names']))) : $question['tags'];
        unset($question['tag_names']);

        if (in_array($question['question_type'], ['mcq_single','mcq_multiple','true_false','matching'], true)) {
            $stmt = $db->prepare("SELECT * FROM question_options WHERE question_id = ? ORDER BY sort_order, id");
            $stmt->execute([$question['id']]);
            $question['options'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
        } else {
            $question['options'] = [];
        }
    }
    unset($question);

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

function handleCreateQuestion(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['content']) || empty($data['question_type'])) {
        throw new Exception('Content and question_type are required');
    }

    $questionType = $data['question_type'];
    if (!in_array($questionType, ['mcq_single','mcq_multiple','true_false','essay','short_answer','matching','code','fill_blanks'], true)) {
        throw new Exception('Invalid question type');
    }

    $options = prepareQuestionOptions($questionType, $data);

    $db->beginTransaction();
    try {
        $correctAnswer = $options['correct_answer'] ?? null;
        $stmt = $db->prepare("
            INSERT INTO questions (
                title, content, question_type, difficulty, points, time_limit,
                category_id, course_id, instructor_id, tags, explanation,
                hints, metadata, status, review_status, is_shared,
                correct_answer, created_at, updated_at
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
        ");
        $stmt->execute([
            $data['title'],
            $data['content'],
            $questionType,
            $data['difficulty'] ?? 'medium',
            floatval($data['points'] ?? 1),
            isset($data['time_limit']) ? (int) $data['time_limit'] : null,
            isset($data['category_id']) ? (int) $data['category_id'] : null,
            isset($data['course_id']) ? (int) $data['course_id'] : null,
            $userId,
            json_encode($data['tags'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            $data['explanation'] ?? '',
            json_encode($data['hints'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            json_encode($data['metadata'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            $data['status'] ?? 'draft',
            $data['review_status'] ?? 'not_submitted',
            !empty($data['is_shared']) ? 1 : 0,
            $correctAnswer
        ]);
        $questionId = (int) $db->lastInsertId();

        insertQuestionOptions($db, $questionId, $options);
        upsertQuestionTags($db, $questionId, $data['tags'] ?? []);

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

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

function handleUpdateQuestion(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('Question ID is required');
    }

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

    $questionType = $data['question_type'] ?? $question['question_type'];
    $options = prepareQuestionOptions($questionType, $data);

    $db->beginTransaction();
    try {
        $stmt = $db->prepare("
            UPDATE questions
            SET title = ?, content = ?, question_type = ?, difficulty = ?, points = ?,
                time_limit = ?, category_id = ?, course_id = ?, tags = ?, explanation = ?,
                hints = ?, metadata = ?, status = ?, review_status = ?, is_shared = ?,
                correct_answer = ?, updated_at = NOW()
            WHERE id = ?
        ");
        $stmt->execute([
            $data['title'] ?? $question['title'],
            $data['content'] ?? $question['content'],
            $questionType,
            $data['difficulty'] ?? $question['difficulty'],
            isset($data['points']) ? floatval($data['points']) : floatval($question['points']),
            array_key_exists('time_limit', $data) ? (int) $data['time_limit'] : $question['time_limit'],
            array_key_exists('category_id', $data) ? (int) $data['category_id'] : $question['category_id'],
            array_key_exists('course_id', $data) ? (int) $data['course_id'] : $question['course_id'],
            json_encode($data['tags'] ?? decodeJson($question['tags']), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            $data['explanation'] ?? $question['explanation'],
            json_encode($data['hints'] ?? decodeJson($question['hints']), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            json_encode($data['metadata'] ?? decodeJson($question['metadata']), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            $data['status'] ?? $question['status'],
            $data['review_status'] ?? $question['review_status'],
            isset($data['is_shared']) ? (int) $data['is_shared'] : (int) $question['is_shared'],
            $options['correct_answer'] ?? $question['correct_answer'],
            $questionId
        ]);

        if (array_key_exists('options', $data) || in_array($questionType, ['mcq_single','mcq_multiple','true_false','matching'], true)) {
            $db->prepare("DELETE FROM question_options WHERE question_id = ?")->execute([$questionId]);
            insertQuestionOptions($db, $questionId, $options);
        }

        if (array_key_exists('tags', $data)) {
            $db->prepare("DELETE FROM question_tag_assignments WHERE question_id = ?")->execute([$questionId]);
            upsertQuestionTags($db, $questionId, $data['tags'] ?? []);
        }

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

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

function handleDeleteQuestion(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('Question ID is required');
    }

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

    $stmt = $db->prepare("SELECT COUNT(*) FROM exam_questions WHERE question_id = ?");
    $stmt->execute([$questionId]);
    if ((int) $stmt->fetchColumn() > 0) {
        throw new Exception('Cannot delete a question that is already used in an exam');
    }

    $db->beginTransaction();
    try {
        $db->prepare("DELETE FROM question_options WHERE question_id = ?")->execute([$questionId]);
        $db->prepare("DELETE FROM question_tag_assignments WHERE question_id = ?")->execute([$questionId]);
        $db->prepare("DELETE FROM questions WHERE id = ?")->execute([$questionId]);
        $db->commit();
    } catch (Throwable $e) {
        $db->rollBack();
        throw $e;
    }

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

function prepareQuestionOptions(string $questionType, array $data): array
{
    if (!in_array($questionType, ['mcq_single','mcq_multiple','true_false','matching'], true)) {
        return [];
    }

    $options = $data['options'] ?? [];
    if ($questionType === 'true_false') {
        $correct = (string) ($data['correct_option'] ?? 'true');
        return [
            ['text' => 'True', 'is_correct' => in_array(strtolower($correct), ['true','1','yes','0'], true)],
            ['text' => 'False', 'is_correct' => in_array(strtolower($correct), ['false','0','no','1'], true)]
        ];
    }

    if (empty($options) && !empty($data['option_text'])) {
        $options = array_map(static fn($text) => ['text' => $text], $data['option_text']);
    }

    $correctOptions = [];
    if ($questionType === 'mcq_single') {
        $correctOptions = [isset($data['correct_option']) ? (string) $data['correct_option'] : '0'];
    } elseif ($questionType === 'mcq_multiple') {
        $correctOptions = array_map('strval', $data['correct_options'] ?? []);
    }

    $prepared = [];
    foreach ($options as $index => $option) {
        $prepared[] = [
            'text' => $option['text'] ?? $option['option_text'] ?? '',
            'is_correct' => in_array((string) ($option['is_correct'] ?? $index), $correctOptions, true) || !empty($option['is_correct']),
            'option_value' => $option['option_value'] ?? null,
            'match_value' => $option['match_value'] ?? null
        ];
    }

    if ($questionType === 'matching' && empty($prepared)) {
        foreach (($data['matching_pairs'] ?? []) as $left => $right) {
            $prepared[] = ['text' => $left, 'option_value' => $left, 'match_value' => $right, 'is_correct' => true];
        }
    }

    if (empty($prepared)) {
        throw new Exception('At least one option is required');
    }

    $correctAnswer = null;
    if (in_array($questionType, ['mcq_single', 'true_false'], true)) {
        $correctAnswer = array_search(true, array_column($prepared, 'is_correct'), true);
        $correctAnswer = $correctAnswer === false ? null : (string) $correctAnswer;
    } elseif ($questionType === 'mcq_multiple') {
        $correctAnswer = [];
        foreach ($prepared as $index => $option) {
            if (!empty($option['is_correct'])) {
                $correctAnswer[] = (string) $index;
            }
        }
        $correctAnswer = json_encode($correctAnswer, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    } elseif ($questionType === 'matching') {
        $correctAnswer = [];
        foreach ($prepared as $index => $option) {
            $correctAnswer[$option['text']] = $option['match_value'] ?? $option['option_value'] ?? '';
        }
        $correctAnswer = json_encode($correctAnswer, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }

    return array_merge($prepared, ['correct_answer' => $correctAnswer]);
}

function insertQuestionOptions(PDO $db, int $questionId, array $options): void
{
    $stmt = $db->prepare("
        INSERT INTO question_options (question_id, option_text, option_value, match_value, is_correct, sort_order)
        VALUES (?, ?, ?, ?, ?, ?)
    ");
    foreach ($options as $index => $option) {
        $stmt->execute([
            $questionId,
            $option['text'] ?? '',
            $option['option_value'] ?? null,
            $option['match_value'] ?? null,
            !empty($option['is_correct']) ? 1 : 0,
            $index
        ]);
    }
}

function upsertQuestionTags(PDO $db, int $questionId, array $tags): void
{
    foreach ($tags as $tag) {
        if (is_numeric($tag)) {
            $tagId = (int) $tag;
        } else {
            $name = trim((string) $tag);
            if ($name === '') {
                continue;
            }
            $slug = strtolower(preg_replace('/[^a-z0-9]+/', '-', strtolower($name)));
            $slug = trim($slug, '-');
            $stmt = $db->prepare("SELECT id FROM question_tags WHERE slug = ?");
            $stmt->execute([$slug]);
            $tagId = (int) $stmt->fetchColumn();
            if (!$tagId) {
                $db->prepare("INSERT INTO question_tags (name, slug) VALUES (?, ?)")->execute([$name, $slug]);
                $tagId = (int) $db->lastInsertId();
            }
        }
        $db->prepare("INSERT IGNORE INTO question_tag_assignments (question_id, tag_id) VALUES (?, ?)")->execute([$questionId, $tagId]);
    }
}

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 : [];
}
