import { Request, Response } from "express";
import * as quizService from "../services/quizService";
import { notifyQuizPublished } from "../services/notificationService";
import { sendResponse, handleError } from "../utils/apiResponse";

// @desc    Create a quiz
// @route   POST /api/quizzes
export const createQuiz = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { title, questions, start_datetime, end_datetime, status } =
      req.body as {
        title?: string;
        questions?: string[];
        start_datetime?: string;
        end_datetime?: string;
        status?: string;
      };
    if (!title || !questions || !start_datetime || !end_datetime) {
      sendResponse(
        res,
        400,
        "title, questions, start_datetime and end_datetime are required",
      );
      return;
    }
    const quiz = await quizService.createQuiz({
      title,
      questions,
      start_datetime,
      end_datetime,
      status,
    });
    req.app.get("io").emit("new_quiz", {
      _id: quiz._id,
      title: quiz.title,
      start_datetime: quiz.start_datetime,
      end_datetime: quiz.end_datetime,
    });
    if (quiz.status === "active") {
      await notifyQuizPublished(quiz._id.toString(), quiz.title);
    }
    sendResponse(res, 201, "Quiz created successfully", { quiz });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get all quizzes (optional ?status= filter)
// @route   GET /api/quizzes
export const getAllQuizzes = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const page = Math.max(1, parseInt(req.query.page as string) || 1);
    const limit = Math.min(
      50,
      Math.max(1, parseInt(req.query.limit as string) || 10),
    );
    const { quizzes, pagination } = await quizService.getAllQuizzes(
      req.query.status as string | undefined,
      page,
      limit,
    );
    sendResponse(res, 200, "Quizzes fetched", { quizzes }, pagination);
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get single quiz by ID
// @route   GET /api/quizzes/:id
export const getQuiz = async (req: Request, res: Response): Promise<void> => {
  try {
    const quiz = await quizService.getQuizById(req.params.id as string);
    sendResponse(res, 200, "Quiz fetched", { quiz });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Update quiz
// @route   PUT /api/quizzes/:id
export const updateQuiz = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const quiz = await quizService.updateQuiz(
      req.params.id as string,
      req.body as Parameters<typeof quizService.updateQuiz>[1],
    );
    sendResponse(res, 200, "Quiz updated", { quiz });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Delete quiz
// @route   DELETE /api/quizzes/:id
export const deleteQuiz = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    await quizService.deleteQuiz(req.params.id as string);
    sendResponse(res, 200, "Quiz deleted successfully");
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get all currently open active quizzes (user)
// @route   GET /api/quizzes/active?filter=live|upcoming|all
export const getActiveQuizzes = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const filter = (req.query.filter as string) || "all";
    if (!["live", "upcoming", "all"].includes(filter)) {
      sendResponse(res, 400, "Invalid filter. Use live, upcoming, or all");
      return;
    }
    const quizzes = await quizService.getActiveQuizzes(
      req.user!.id,
      filter as "live" | "upcoming" | "all",
    );
    sendResponse(res, 200, "Quizzes fetched", {
      count: quizzes.length,
      quizzes,
    });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get a single quiz to solve — no correct_option exposed (user)
// @route   GET /api/quizzes/:id/take
export const getQuizForUser = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const page = Math.max(1, parseInt(req.query.page as string) || 1);
    const limit = Math.min(
      50,
      Math.max(1, parseInt(req.query.limit as string) || 10),
    );
    const { pagination, ...rest } = await quizService.getQuizForUser(
      req.params.id as string,
      req.user!.id,
      page,
      limit,
    );
    sendResponse(res, 200, "Quiz fetched", rest, pagination);
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Attempt a quiz — shuffled questions & options (user)
// @route   GET /api/quizzes/:id/attempt
export const attemptQuiz = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const pageQuery = req.query.page as string | undefined;
    const limitQuery = req.query.limit as string | undefined;

    let page = 1;
    let limit = 10;

    if (pageQuery !== undefined) {
      page = Number(pageQuery);
      if (!Number.isInteger(page) || page < 1) {
        sendResponse(res, 400, "Invalid page. page must be an integer >= 1");
        return;
      }
    }

    if (limitQuery !== undefined) {
      limit = Number(limitQuery);
      if (!Number.isInteger(limit) || limit < 1 || limit > 50) {
        sendResponse(
          res,
          400,
          "Invalid limit. limit must be an integer between 1 and 50",
        );
        return;
      }
    }

    const { pagination, ...rest } = await quizService.attemptQuiz(
      req.params.id as string,
      req.user!.id,
      page,
      limit,
    );
    sendResponse(res, 200, "Quiz attempt fetched", rest, pagination);
  } catch (error) {
    handleError(res, error);
  }
};
