import { Request, Response } from 'express';
import * as questionImportService from '../services/questionImportService';
import Question from '../models/question';
import { sendResponse, handleError } from '../utils/apiResponse';

const EDITABLE_FIELDS = [
  'question_text', 'option_a', 'option_b', 'option_c', 'option_d',
  'correct_option', 'difficulty', 'category', 'tags', 'points',
] as const;

// @desc    Get all questions (paginated)
// @route   GET /api/questions?page=1&limit=20
export const getQuestions = async (req: Request, res: Response): Promise<void> => {
  try {
    const page = Math.max(1, parseInt(req.query.page as string) || 1);
    const limit = Math.min(100, Math.max(1, parseInt(req.query.limit as string) || 20));
    const skip = (page - 1) * limit;

    const [questions, total] = await Promise.all([
      Question.find().select('-sequence').sort({ createdAt: -1, _id: 1 }).skip(skip).limit(limit),
      Question.countDocuments(),
    ]);

    const pagination = {
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
      hasNextPage: page < Math.ceil(total / limit),
      hasPrevPage: page > 1,
    };

    sendResponse(res, 200, 'Questions fetched', { questions }, pagination);
  } catch (error) { handleError(res, error); }
};

// @desc    Create a single question
// @route   POST /api/questions
export const createQuestion = async (req: Request, res: Response): Promise<void> => {
  try {
    const { question_text, option_a, option_b, option_c, option_d, correct_option, difficulty, category, tags, points } = req.body;
    if (!question_text || !option_a || !option_b || !option_c || !option_d || !correct_option) {
      sendResponse(res, 400, 'question_text, option_a, option_b, option_c, option_d, and correct_option are required');
      return;
    }
    if (![option_a, option_b, option_c, option_d].includes(correct_option.trim())) {
      sendResponse(res, 400, 'correct_option must match one of the four options');
      return;
    }
    const existing = await Question.findOne({ question_text: question_text.trim() });
    if (existing) {
      sendResponse(res, 400, 'A question with this text already exists');
      return;
    }
    const question = await Question.create({
      question_text, option_a, option_b, option_c, option_d, correct_option,
      ...(difficulty && { difficulty: difficulty.trim().toLowerCase() }),
      ...(category && { category }),
      ...(tags && { tags }),
      ...(points && { points }),
    });
    sendResponse(res, 201, 'Question created', { question });
  } catch (error) { handleError(res, error); }
};

// @desc    Get single question by ID
// @route   GET /api/questions/:id
export const getQuestion = async (req: Request, res: Response): Promise<void> => {
  try {
    const question = await Question.findById(req.params.id as string).select('-sequence');
    if (!question) { sendResponse(res, 404, 'Question not found'); return; }
    sendResponse(res, 200, 'Question fetched', { question });
  } catch (error) { handleError(res, error); }
};

// @desc    Update question by ID
// @route   PUT /api/questions/:id
export const updateQuestion = async (req: Request, res: Response): Promise<void> => {
  try {
    const body = req.body as Record<string, unknown>;
    const update: Record<string, unknown> = {};
    EDITABLE_FIELDS.forEach((f) => { if (body[f] !== undefined && body[f] !== '') update[f] = body[f]; });
    if (typeof update.difficulty === 'string') update.difficulty = update.difficulty.trim().toLowerCase();

    const question = await Question.findById(req.params.id as string);
    if (!question) { sendResponse(res, 404, 'Question not found'); return; }

    const options = {
      option_a: (update.option_a ?? question.option_a) as string,
      option_b: (update.option_b ?? question.option_b) as string,
      option_c: (update.option_c ?? question.option_c) as string,
      option_d: (update.option_d ?? question.option_d) as string,
    };
    const correct = (update.correct_option ?? question.correct_option) as string;

    if (!Object.values(options).includes(correct)) {
      sendResponse(res, 400, 'correct_option must match one of the four options');
      return;
    }

    const updated = await Question.findByIdAndUpdate(req.params.id as string, update, { new: true, runValidators: true });
    sendResponse(res, 200, 'Question updated', { question: updated });
  } catch (error) { handleError(res, error); }
};

// @desc    Delete question by ID
// @route   DELETE /api/questions/:id
export const deleteQuestion = async (req: Request, res: Response): Promise<void> => {
  try {
    const question = await Question.findByIdAndDelete(req.params.id as string);
    if (!question) { sendResponse(res, 404, 'Question not found'); return; }
    sendResponse(res, 200, 'Question deleted successfully');
  } catch (error) { handleError(res, error); }
};

// @desc    Upload and import MCQ questions from CSV
// @route   POST /api/questions/import
export const importQuestions = async (req: Request, res: Response): Promise<void> => {
  try {
    if (!req.file) { sendResponse(res, 400, 'No file uploaded'); return; }
    const result = await questionImportService.importQuestions(req.file.buffer);
    sendResponse(res, 200, 'Questions imported', result);
  } catch (error) { handleError(res, error); }
};
