package handlers

import (
	"errors"
	"log"
	"sno/internal/middleware"
	"sno/internal/models"
	"sno/internal/service"
	"strconv"

	"github.com/gofiber/fiber/v2"
	"github.com/jackc/pgx/v5"
)

// QuizHandler handles HTTP requests for quizzes.
type QuizHandler struct {
	quizService  service.QuizService
	userService  service.UserService
}

// NewQuizHandler creates a new instance of a quiz handler.
func NewQuizHandler(quizService service.QuizService, userService service.UserService) *QuizHandler {
	return &QuizHandler{quizService: quizService, userService: userService}
}

// GetAllQuizzes handles the request to get all active quizzes.
// @Summary Get all active quizzes
// @Description Returns a list of all active quizzes
// @Tags quizzes
// @Accept json
// @Produce json
// @Success 200 {object} object{success=bool,message=string,data=[]models.Quiz}
// @Failure 500 {object} object{success=bool,message=string}
// @Router /api/quizzes [get]
// @Security ApiKeyAuth
func (h *QuizHandler) GetAllQuizzes(c *fiber.Ctx) error {
	quizzes, err := h.quizService.ListActiveQuizzes(c.Context())
	if err != nil {
		log.Printf("ERROR: Failed to retrieve quizzes: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(Response{
			Success: false,
			Message: "Failed to retrieve quizzes",
		})
	}

	return c.Status(fiber.StatusOK).JSON(Response{
		Success: true,
		Message: "Quizzes retrieved successfully",
		Data:    quizzes,
	})
}

// CreateQuiz handles the request to create a new quiz.
// @Summary Create a new quiz
// @Description Creates a new quiz (admin/operator only)
// @Tags quizzes
// @Accept json
// @Produce json
// @Param quiz body models.Quiz true "Quiz object"
// @Success 201 {object} object{success=bool,message=string,data=models.Quiz}
// @Failure 400 {object} object{success=bool,message=string}
// @Failure 500 {object} object{success=bool,message=string}
// @Router /api/admin/quizzes [post]
// @Security ApiKeyAuth
func (h *QuizHandler) CreateQuiz(c *fiber.Ctx) error {
	var quiz models.Quiz

	if err := c.BodyParser(&quiz); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(Response{
			Success: false,
			Message: "Cannot parse JSON",
		})
	}

	createdQuiz, err := h.quizService.CreateQuiz(c.Context(), &quiz)
	if err != nil {
		log.Printf("ERROR: Failed to create quiz: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(Response{
			Success: false,
			Message: "Failed to create quiz",
		})
	}

	return c.Status(fiber.StatusCreated).JSON(Response{
		Success: true,
		Message: "Quiz created successfully",
		Data:    createdQuiz,
	})
}

// GetQuizByID handles the request to get a single quiz by its ID.
// @Summary Get quiz by ID
// @Description Returns a single quiz with all its questions
// @Tags quizzes
// @Accept json
// @Produce json
// @Param id path int true "Quiz ID"
// @Success 200 {object} object{success=bool,message=string,data=models.Quiz}
// @Failure 400 {object} object{success=bool,message=string}
// @Failure 404 {object} object{success=bool,message=string}
// @Failure 500 {object} object{success=bool,message=string}
// @Router /api/quizzes/{id} [get]
// @Security ApiKeyAuth
func (h *QuizHandler) GetQuizByID(c *fiber.Ctx) error {
	id, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(Response{
			Success: false,
			Message: "Invalid quiz ID",
		})
	}

	quiz, err := h.quizService.GetQuizByID(c.Context(), id)
	if err != nil {
		if errors.Is(err, pgx.ErrNoRows) {
			return c.Status(fiber.StatusNotFound).JSON(Response{
				Success: false,
				Message: "Quiz not found",
			})
		}
		log.Printf("ERROR: Failed to get quiz by ID: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(Response{
			Success: false,
			Message: "Failed to retrieve quiz",
		})
	}

	return c.Status(fiber.StatusOK).JSON(Response{
		Success: true,
		Message: "Quiz retrieved successfully",
		Data:    quiz,
	})
}

// SubmitQuiz handles the submission of quiz answers.
// @Summary Submit quiz answers
// @Description Submits quiz answers and calculates score/stars earned
// @Tags quizzes
// @Accept json
// @Produce json
// @Param id path int true "Quiz ID"
// @Param submission body models.SubmissionRequest true "Quiz submission"
// @Success 200 {object} object{success=bool,message=string,data=object}
// @Failure 400 {object} object{success=bool,message=string}
// @Failure 500 {object} object{success=bool,message=string}
// @Router /api/quizzes/{id}/submit [post]
// @Security ApiKeyAuth
func (h *QuizHandler) SubmitQuiz(c *fiber.Ctx) error {
	quizID, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(Response{
			Success: false,
			Message: "Invalid quiz ID",
		})
	}

	var submission models.SubmissionRequest
	if err := c.BodyParser(&submission); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(Response{
			Success: false,
			Message: "Cannot parse submission JSON",
		})
	}

	// Get user data from auth middleware
	userData := middleware.GetTelegramUser(c)
	if userData == nil {
		return c.Status(fiber.StatusUnauthorized).JSON(Response{
			Success: false,
			Message: "User not authenticated",
		})
	}

	// Ensure user exists in database
	_, err = h.userService.GetOrCreateUser(c.Context(), userData.ID, userData.FirstName, userData.LastName, userData.Username, userData.PhotoURL)
	if err != nil {
		log.Printf("ERROR: Failed to get or create user: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(Response{
			Success: false,
			Message: "Failed to create user profile",
		})
	}

	result, err := h.quizService.SubmitQuiz(c.Context(), userData.ID, quizID, submission)
	if err != nil {
		log.Printf("ERROR: Failed to submit quiz: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(Response{
			Success: false,
			Message: err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(Response{
		Success: true,
		Message: "Quiz submitted successfully",
		Data:    result,
	})
}

// CanRepeat handles the request to check if a user can repeat a quiz.
// @Summary Check if quiz can be repeated
// @Description Checks if user can repeat a quiz and when it will be available
// @Tags quizzes
// @Accept json
// @Produce json
// @Param id path int true "Quiz ID"
// @Success 200 {object} object{success=bool,message=string,data=models.CanRepeatResponse}
// @Failure 400 {object} object{success=bool,message=string}
// @Failure 500 {object} object{success=bool,message=string}
// @Router /api/quizzes/{id}/can-repeat [get]
// @Security ApiKeyAuth
func (h *QuizHandler) CanRepeat(c *fiber.Ctx) error {
	quizID, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(Response{
			Success: false,
			Message: "Invalid quiz ID",
		})
	}

	// Get user data from auth middleware
	userData := middleware.GetTelegramUser(c)
	if userData == nil {
		return c.Status(fiber.StatusUnauthorized).JSON(Response{
			Success: false,
			Message: "User not authenticated",
		})
	}

	canRepeatResponse, err := h.quizService.CanUserRepeatQuiz(c.Context(), userData.ID, quizID)
	if err != nil {
		log.Printf("ERROR: Failed to check if quiz can be repeated: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(Response{
			Success: false,
			Message: "Failed to check quiz status",
		})
	}

	return c.Status(fiber.StatusOK).JSON(Response{
		Success: true,
		Message: "Quiz status retrieved successfully",
		Data:    canRepeatResponse,
	})
}

// UpdateQuiz handles the request to update an existing quiz.
// @Summary Update a quiz
// @Description Updates an existing quiz (admin only)
// @Tags quizzes
// @Accept json
// @Produce json
// @Param id path int true "Quiz ID"
// @Param quiz body models.Quiz true "Updated quiz object"
// @Success 200 {object} object{success=bool,message=string,data=models.Quiz}
// @Failure 400 {object} object{success=bool,message=string}
// @Failure 500 {object} object{success=bool,message=string}
// @Router /api/admin/quizzes/{id} [put]
// @Security ApiKeyAuth
func (h *QuizHandler) UpdateQuiz(c *fiber.Ctx) error {
	id, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(Response{
			Success: false,
			Message: "Invalid quiz ID",
		})
	}

	var quiz models.Quiz
	if err := c.BodyParser(&quiz); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(Response{
			Success: false,
			Message: "Cannot parse JSON",
		})
	}

	updatedQuiz, err := h.quizService.UpdateQuiz(c.Context(), id, &quiz)
	if err != nil {
		log.Printf("ERROR: Failed to update quiz: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(Response{
			Success: false,
			Message: err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(Response{
		Success: true,
		Message: "Quiz updated successfully",
		Data:    updatedQuiz,
	})
}

// DeleteQuiz handles the request to delete a quiz.
// @Summary Delete a quiz
// @Description Deletes a quiz (admin only)
// @Tags quizzes
// @Accept json
// @Produce json
// @Param id path int true "Quiz ID"
// @Success 200 {object} object{success=bool,message=string}
// @Failure 400 {object} object{success=bool,message=string}
// @Failure 500 {object} object{success=bool,message=string}
// @Router /api/admin/quizzes/{id} [delete]
// @Security ApiKeyAuth
func (h *QuizHandler) DeleteQuiz(c *fiber.Ctx) error {
	id, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(Response{
			Success: false,
			Message: "Invalid quiz ID",
		})
	}

	err = h.quizService.DeleteQuiz(c.Context(), id)
	if err != nil {
		log.Printf("ERROR: Failed to delete quiz: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(Response{
			Success: false,
			Message: err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(Response{
		Success: true,
		Message: "Quiz deleted successfully",
	})
}
