package handlers

import (
	"net/http"
	"strconv"
	"time"

	"github.com/breakpilot/ai-compliance-sdk/internal/academy"
	"github.com/breakpilot/ai-compliance-sdk/internal/rbac"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// AcademyHandlers handles academy HTTP requests
type AcademyHandlers struct {
	store *academy.Store
}

// NewAcademyHandlers creates new academy handlers
func NewAcademyHandlers(store *academy.Store) *AcademyHandlers {
	return &AcademyHandlers{store: store}
}

// ============================================================================
// Course Management
// ============================================================================

// CreateCourse creates a new compliance training course
// POST /sdk/v1/academy/courses
func (h *AcademyHandlers) CreateCourse(c *gin.Context) {
	var req academy.CreateCourseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	tenantID := rbac.GetTenantID(c)

	course := &academy.Course{
		TenantID:         tenantID,
		Title:            req.Title,
		Description:      req.Description,
		Category:         req.Category,
		DurationMinutes:  req.DurationMinutes,
		RequiredForRoles: req.RequiredForRoles,
		IsActive:         true,
	}

	if course.RequiredForRoles == nil {
		course.RequiredForRoles = []string{}
	}

	if err := h.store.CreateCourse(c.Request.Context(), course); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Create lessons if provided
	for i := range req.Lessons {
		lesson := &academy.Lesson{
			CourseID:        course.ID,
			Title:           req.Lessons[i].Title,
			Description:     req.Lessons[i].Description,
			LessonType:      req.Lessons[i].LessonType,
			ContentURL:      req.Lessons[i].ContentURL,
			DurationMinutes: req.Lessons[i].DurationMinutes,
			OrderIndex:      req.Lessons[i].OrderIndex,
			QuizQuestions:   req.Lessons[i].QuizQuestions,
		}
		if err := h.store.CreateLesson(c.Request.Context(), lesson); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		course.Lessons = append(course.Lessons, *lesson)
	}

	if course.Lessons == nil {
		course.Lessons = []academy.Lesson{}
	}

	c.JSON(http.StatusCreated, gin.H{"course": course})
}

// GetCourse retrieves a course with its lessons
// GET /sdk/v1/academy/courses/:id
func (h *AcademyHandlers) GetCourse(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid course ID"})
		return
	}

	course, err := h.store.GetCourse(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if course == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "course not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"course": course})
}

// ListCourses lists courses for the current tenant
// GET /sdk/v1/academy/courses
func (h *AcademyHandlers) ListCourses(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)

	filters := &academy.CourseFilters{
		Limit: 50,
	}

	if category := c.Query("category"); category != "" {
		filters.Category = academy.CourseCategory(category)
	}
	if search := c.Query("search"); search != "" {
		filters.Search = search
	}
	if activeStr := c.Query("is_active"); activeStr != "" {
		active := activeStr == "true"
		filters.IsActive = &active
	}
	if limitStr := c.Query("limit"); limitStr != "" {
		if limit, err := strconv.Atoi(limitStr); err == nil && limit > 0 {
			filters.Limit = limit
		}
	}
	if offsetStr := c.Query("offset"); offsetStr != "" {
		if offset, err := strconv.Atoi(offsetStr); err == nil && offset >= 0 {
			filters.Offset = offset
		}
	}

	courses, total, err := h.store.ListCourses(c.Request.Context(), tenantID, filters)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, academy.CourseListResponse{
		Courses: courses,
		Total:   total,
	})
}

// UpdateCourse updates a course
// PUT /sdk/v1/academy/courses/:id
func (h *AcademyHandlers) UpdateCourse(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid course ID"})
		return
	}

	course, err := h.store.GetCourse(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if course == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "course not found"})
		return
	}

	var req academy.UpdateCourseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if req.Title != nil {
		course.Title = *req.Title
	}
	if req.Description != nil {
		course.Description = *req.Description
	}
	if req.Category != nil {
		course.Category = *req.Category
	}
	if req.DurationMinutes != nil {
		course.DurationMinutes = *req.DurationMinutes
	}
	if req.RequiredForRoles != nil {
		course.RequiredForRoles = req.RequiredForRoles
	}
	if req.IsActive != nil {
		course.IsActive = *req.IsActive
	}

	if err := h.store.UpdateCourse(c.Request.Context(), course); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"course": course})
}

// DeleteCourse deletes a course
// DELETE /sdk/v1/academy/courses/:id
func (h *AcademyHandlers) DeleteCourse(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid course ID"})
		return
	}

	if err := h.store.DeleteCourse(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "course deleted"})
}

// ============================================================================
// Enrollment Management
// ============================================================================

// CreateEnrollment enrolls a user in a course
// POST /sdk/v1/academy/enrollments
func (h *AcademyHandlers) CreateEnrollment(c *gin.Context) {
	var req academy.EnrollUserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	tenantID := rbac.GetTenantID(c)

	// Verify course exists
	course, err := h.store.GetCourse(c.Request.Context(), req.CourseID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if course == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "course not found"})
		return
	}

	enrollment := &academy.Enrollment{
		TenantID:  tenantID,
		CourseID:  req.CourseID,
		UserID:    req.UserID,
		UserName:  req.UserName,
		UserEmail: req.UserEmail,
		Status:    academy.EnrollmentStatusNotStarted,
		Deadline:  req.Deadline,
	}

	if err := h.store.CreateEnrollment(c.Request.Context(), enrollment); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"enrollment": enrollment})
}

// ListEnrollments lists enrollments for the current tenant
// GET /sdk/v1/academy/enrollments
func (h *AcademyHandlers) ListEnrollments(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)

	filters := &academy.EnrollmentFilters{
		Limit: 50,
	}

	if status := c.Query("status"); status != "" {
		filters.Status = academy.EnrollmentStatus(status)
	}
	if courseIDStr := c.Query("course_id"); courseIDStr != "" {
		if courseID, err := uuid.Parse(courseIDStr); err == nil {
			filters.CourseID = &courseID
		}
	}
	if userIDStr := c.Query("user_id"); userIDStr != "" {
		if userID, err := uuid.Parse(userIDStr); err == nil {
			filters.UserID = &userID
		}
	}
	if limitStr := c.Query("limit"); limitStr != "" {
		if limit, err := strconv.Atoi(limitStr); err == nil && limit > 0 {
			filters.Limit = limit
		}
	}
	if offsetStr := c.Query("offset"); offsetStr != "" {
		if offset, err := strconv.Atoi(offsetStr); err == nil && offset >= 0 {
			filters.Offset = offset
		}
	}

	enrollments, total, err := h.store.ListEnrollments(c.Request.Context(), tenantID, filters)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, academy.EnrollmentListResponse{
		Enrollments: enrollments,
		Total:       total,
	})
}

// UpdateProgress updates an enrollment's progress
// PUT /sdk/v1/academy/enrollments/:id/progress
func (h *AcademyHandlers) UpdateProgress(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid enrollment ID"})
		return
	}

	enrollment, err := h.store.GetEnrollment(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if enrollment == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "enrollment not found"})
		return
	}

	var req academy.UpdateProgressRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if req.Progress < 0 || req.Progress > 100 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "progress must be between 0 and 100"})
		return
	}

	if err := h.store.UpdateEnrollmentProgress(c.Request.Context(), id, req.Progress, req.CurrentLesson); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Fetch updated enrollment
	updated, err := h.store.GetEnrollment(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"enrollment": updated})
}

// CompleteEnrollment marks an enrollment as completed
// POST /sdk/v1/academy/enrollments/:id/complete
func (h *AcademyHandlers) CompleteEnrollment(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid enrollment ID"})
		return
	}

	enrollment, err := h.store.GetEnrollment(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if enrollment == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "enrollment not found"})
		return
	}

	if enrollment.Status == academy.EnrollmentStatusCompleted {
		c.JSON(http.StatusBadRequest, gin.H{"error": "enrollment already completed"})
		return
	}

	if err := h.store.CompleteEnrollment(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Fetch updated enrollment
	updated, err := h.store.GetEnrollment(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"enrollment": updated,
		"message":    "enrollment completed",
	})
}

// ============================================================================
// Certificate Management
// ============================================================================

// GetCertificate retrieves a certificate
// GET /sdk/v1/academy/certificates/:id
func (h *AcademyHandlers) GetCertificate(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid certificate ID"})
		return
	}

	cert, err := h.store.GetCertificate(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if cert == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "certificate not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"certificate": cert})
}

// GenerateCertificate generates a certificate for a completed enrollment
// POST /sdk/v1/academy/enrollments/:id/certificate
func (h *AcademyHandlers) GenerateCertificate(c *gin.Context) {
	enrollmentID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid enrollment ID"})
		return
	}

	enrollment, err := h.store.GetEnrollment(c.Request.Context(), enrollmentID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if enrollment == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "enrollment not found"})
		return
	}

	if enrollment.Status != academy.EnrollmentStatusCompleted {
		c.JSON(http.StatusBadRequest, gin.H{"error": "enrollment must be completed before generating certificate"})
		return
	}

	// Check if certificate already exists
	existing, err := h.store.GetCertificateByEnrollment(c.Request.Context(), enrollmentID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if existing != nil {
		c.JSON(http.StatusOK, gin.H{"certificate": existing, "message": "certificate already exists"})
		return
	}

	// Get the course for the certificate title
	course, err := h.store.GetCourse(c.Request.Context(), enrollment.CourseID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	courseTitle := "Unknown Course"
	if course != nil {
		courseTitle = course.Title
	}

	// Certificate is valid for 1 year by default
	validUntil := time.Now().UTC().AddDate(1, 0, 0)

	cert := &academy.Certificate{
		EnrollmentID: enrollmentID,
		UserName:     enrollment.UserName,
		CourseTitle:  courseTitle,
		ValidUntil:   &validUntil,
	}

	if err := h.store.CreateCertificate(c.Request.Context(), cert); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"certificate": cert})
}

// ============================================================================
// Quiz Submission
// ============================================================================

// SubmitQuiz submits quiz answers and returns the results
// POST /sdk/v1/academy/enrollments/:id/quiz
func (h *AcademyHandlers) SubmitQuiz(c *gin.Context) {
	enrollmentID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid enrollment ID"})
		return
	}

	var req academy.SubmitQuizRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Verify enrollment exists
	enrollment, err := h.store.GetEnrollment(c.Request.Context(), enrollmentID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if enrollment == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "enrollment not found"})
		return
	}

	// Get the lesson with quiz questions
	lesson, err := h.store.GetLesson(c.Request.Context(), req.LessonID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if lesson == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "lesson not found"})
		return
	}

	if len(lesson.QuizQuestions) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "lesson has no quiz questions"})
		return
	}

	if len(req.Answers) != len(lesson.QuizQuestions) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "number of answers must match number of questions"})
		return
	}

	// Grade the quiz
	correctCount := 0
	var results []academy.QuizResult

	for i, question := range lesson.QuizQuestions {
		correct := req.Answers[i] == question.CorrectIndex
		if correct {
			correctCount++
		}
		results = append(results, academy.QuizResult{
			Question:    question.Question,
			Correct:     correct,
			Explanation: question.Explanation,
		})
	}

	totalQuestions := len(lesson.QuizQuestions)
	score := 0
	if totalQuestions > 0 {
		score = (correctCount * 100) / totalQuestions
	}

	// Pass threshold: 70%
	passed := score >= 70

	response := academy.SubmitQuizResponse{
		Score:          score,
		Passed:         passed,
		CorrectAnswers: correctCount,
		TotalQuestions: totalQuestions,
		Results:        results,
	}

	c.JSON(http.StatusOK, response)
}

// ============================================================================
// Statistics
// ============================================================================

// GetStatistics returns academy statistics for the current tenant
// GET /sdk/v1/academy/statistics
func (h *AcademyHandlers) GetStatistics(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)

	stats, err := h.store.GetStatistics(c.Request.Context(), tenantID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, stats)
}
