package handlers

import (
	"fmt"
	"net/http"

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

// ============================================================================
// 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
	}

	c.JSON(http.StatusOK, academy.SubmitQuizResponse{
		Score:          score,
		Passed:         score >= 70,
		CorrectAnswers: correctCount,
		TotalQuestions: totalQuestions,
		Results:        results,
	})
}

// ============================================================================
// Lesson Update
// ============================================================================

// UpdateLesson updates a lesson's content, title, or quiz questions
// PUT /sdk/v1/academy/lessons/:id
func (h *AcademyHandlers) UpdateLesson(c *gin.Context) {
	lessonID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid lesson ID"})
		return
	}

	lesson, err := h.store.GetLesson(c.Request.Context(), 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
	}

	var req struct {
		Title           *string                 `json:"title"`
		Description     *string                 `json:"description"`
		ContentURL      *string                 `json:"content_url"`
		DurationMinutes *int                    `json:"duration_minutes"`
		QuizQuestions   *[]academy.QuizQuestion `json:"quiz_questions"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if req.Title != nil {
		lesson.Title = *req.Title
	}
	if req.Description != nil {
		lesson.Description = *req.Description
	}
	if req.ContentURL != nil {
		lesson.ContentURL = *req.ContentURL
	}
	if req.DurationMinutes != nil {
		lesson.DurationMinutes = *req.DurationMinutes
	}
	if req.QuizQuestions != nil {
		lesson.QuizQuestions = *req.QuizQuestions
	}

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

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

// TestQuiz evaluates quiz answers without requiring an enrollment
// POST /sdk/v1/academy/lessons/:id/quiz-test
func (h *AcademyHandlers) TestQuiz(c *gin.Context) {
	lessonID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid lesson ID"})
		return
	}

	lesson, err := h.store.GetLesson(c.Request.Context(), 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
	}

	var req struct {
		Answers []int `json:"answers"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

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

	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
	}

	c.JSON(http.StatusOK, academy.SubmitQuizResponse{
		Score:          score,
		Passed:         score >= 70,
		CorrectAnswers: correctCount,
		TotalQuestions: totalQuestions,
		Results:        results,
	})
}

// ============================================================================
// 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)
}

// ============================================================================
// Course Generation from Training Modules
// ============================================================================

// regulationToCategory maps training regulation areas to academy categories
var regulationToCategory = map[training.RegulationArea]academy.CourseCategory{
	training.RegulationDSGVO:     academy.CourseCategoryDSGVOBasics,
	training.RegulationNIS2:      academy.CourseCategoryITSecurity,
	training.RegulationISO27001:  academy.CourseCategoryITSecurity,
	training.RegulationAIAct:     academy.CourseCategoryAILiteracy,
	training.RegulationGeschGehG: academy.CourseCategoryWhistleblowerProtection,
	training.RegulationHinSchG:   academy.CourseCategoryWhistleblowerProtection,
}

// GenerateCourseFromTraining creates an academy course from a training module
// POST /sdk/v1/academy/courses/generate
func (h *AcademyHandlers) GenerateCourseFromTraining(c *gin.Context) {
	if h.trainingStore == nil {
		c.JSON(http.StatusServiceUnavailable, gin.H{"error": "training store not available"})
		return
	}

	var req struct {
		ModuleID string `json:"module_id"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	moduleID, err := uuid.Parse(req.ModuleID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid module_id"})
		return
	}

	tenantID := rbac.GetTenantID(c)

	// 1. Get the training module
	module, err := h.trainingStore.GetModule(c.Request.Context(), moduleID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if module == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "training module not found"})
		return
	}

	// If module already linked to an academy course, return that
	if module.AcademyCourseID != nil {
		existing, err := h.store.GetCourse(c.Request.Context(), *module.AcademyCourseID)
		if err == nil && existing != nil {
			c.JSON(http.StatusOK, gin.H{"course": existing, "message": "course already exists for this module"})
			return
		}
	}

	// 2. Get generated content (if any)
	content, _ := h.trainingStore.GetLatestContent(c.Request.Context(), moduleID)

	// 3. Get quiz questions (if any)
	quizQuestions, _ := h.trainingStore.ListQuizQuestions(c.Request.Context(), moduleID)

	// 4. Determine academy category from regulation area
	category, ok := regulationToCategory[module.RegulationArea]
	if !ok {
		category = academy.CourseCategoryCustom
	}

	// 5. Build lessons from content + quiz
	lessons := buildModuleLessons(*module, content, quizQuestions)

	// 6. Create the academy course
	course := &academy.Course{
		TenantID:         tenantID,
		Title:            module.Title,
		Description:      module.Description,
		Category:         category,
		DurationMinutes:  module.DurationMinutes,
		RequiredForRoles: []string{},
		IsActive:         true,
	}

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

	// 7. Create lessons
	for i := range lessons {
		lessons[i].CourseID = course.ID
		if err := h.store.CreateLesson(c.Request.Context(), &lessons[i]); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create lesson: " + err.Error()})
			return
		}
	}
	course.Lessons = lessons

	// 8. Link training module to academy course
	if err := h.trainingStore.SetAcademyCourseID(c.Request.Context(), moduleID, course.ID); err != nil {
		// Non-fatal: course is created, just not linked
		fmt.Printf("Warning: failed to link training module %s to academy course %s: %v\n", moduleID, course.ID, err)
	}

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

// GenerateAllCourses creates academy courses for all training modules that don't have one yet
// POST /sdk/v1/academy/courses/generate-all
func (h *AcademyHandlers) GenerateAllCourses(c *gin.Context) {
	if h.trainingStore == nil {
		c.JSON(http.StatusServiceUnavailable, gin.H{"error": "training store not available"})
		return
	}

	tenantID := rbac.GetTenantID(c)

	// Get all training modules
	modules, _, err := h.trainingStore.ListModules(c.Request.Context(), tenantID, &training.ModuleFilters{Limit: 100})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	generated := 0
	skipped := 0
	var errors []string

	for _, module := range modules {
		// Skip if already linked
		if module.AcademyCourseID != nil {
			skipped++
			continue
		}

		// Get content and quiz
		content, _ := h.trainingStore.GetLatestContent(c.Request.Context(), module.ID)
		quizQuestions, _ := h.trainingStore.ListQuizQuestions(c.Request.Context(), module.ID)

		category, ok := regulationToCategory[module.RegulationArea]
		if !ok {
			category = academy.CourseCategoryCustom
		}

		lessons := buildModuleLessons(module, content, quizQuestions)

		course := &academy.Course{
			TenantID:         tenantID,
			Title:            module.Title,
			Description:      module.Description,
			Category:         category,
			DurationMinutes:  module.DurationMinutes,
			RequiredForRoles: []string{},
			IsActive:         true,
		}

		if err := h.store.CreateCourse(c.Request.Context(), course); err != nil {
			errors = append(errors, fmt.Sprintf("%s: %v", module.ModuleCode, err))
			continue
		}

		for i := range lessons {
			lessons[i].CourseID = course.ID
			if err := h.store.CreateLesson(c.Request.Context(), &lessons[i]); err != nil {
				errors = append(errors, fmt.Sprintf("%s lesson: %v", module.ModuleCode, err))
			}
		}

		_ = h.trainingStore.SetAcademyCourseID(c.Request.Context(), module.ID, course.ID)
		generated++
	}

	c.JSON(http.StatusOK, gin.H{
		"generated": generated,
		"skipped":   skipped,
		"errors":    errors,
		"total":     len(modules),
	})
}

// buildModuleLessons constructs academy lessons from a training module, its content, and quiz questions.
func buildModuleLessons(module training.TrainingModule, content *training.ModuleContent, quizQuestions []training.QuizQuestion) []academy.Lesson {
	var lessons []academy.Lesson
	orderIdx := 0

	// Lesson 1: Text content (if generated)
	if content != nil && content.ContentBody != "" {
		lessons = append(lessons, academy.Lesson{
			Title:           fmt.Sprintf("%s - Schulungsinhalt", module.Title),
			Description:     content.Summary,
			LessonType:      academy.LessonTypeText,
			ContentURL:      content.ContentBody,
			DurationMinutes: estimateReadingTime(content.ContentBody),
			OrderIndex:      orderIdx,
		})
		orderIdx++
	}

	// Lesson 2: Quiz (if questions exist)
	if len(quizQuestions) > 0 {
		var academyQuiz []academy.QuizQuestion
		for _, q := range quizQuestions {
			academyQuiz = append(academyQuiz, academy.QuizQuestion{
				Question:     q.Question,
				Options:      q.Options,
				CorrectIndex: q.CorrectIndex,
				Explanation:  q.Explanation,
			})
		}
		lessons = append(lessons, academy.Lesson{
			Title:           fmt.Sprintf("%s - Quiz", module.Title),
			Description:     fmt.Sprintf("Wissenstest mit %d Fragen", len(quizQuestions)),
			LessonType:      academy.LessonTypeQuiz,
			DurationMinutes: len(quizQuestions) * 2, // ~2 min per question
			OrderIndex:      orderIdx,
			QuizQuestions:   academyQuiz,
		})
	}

	// If no content or quiz exists, create a placeholder
	if len(lessons) == 0 {
		lessons = append(lessons, academy.Lesson{
			Title:           module.Title,
			Description:     module.Description,
			LessonType:      academy.LessonTypeText,
			ContentURL:      fmt.Sprintf("# %s\n\n%s\n\nInhalte werden noch generiert.", module.Title, module.Description),
			DurationMinutes: module.DurationMinutes,
			OrderIndex:      0,
		})
	}

	return lessons
}
