package handlers

import (
	"net/http"

	"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"
)

// ============================================================================
// Media Endpoints
// ============================================================================

// GetModuleMedia returns all media files for a module
// GET /sdk/v1/training/media/:moduleId
func (h *TrainingHandlers) GetModuleMedia(c *gin.Context) {
	moduleID, err := uuid.Parse(c.Param("moduleId"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid module ID"})
		return
	}

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

	c.JSON(http.StatusOK, gin.H{
		"media": mediaList,
		"total": len(mediaList),
	})
}

// GetMediaURL returns a presigned URL for a media file
// GET /sdk/v1/training/media/:id/url
func (h *TrainingHandlers) GetMediaURL(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid media ID"})
		return
	}

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

	// Return the object info for the frontend to construct the URL
	c.JSON(http.StatusOK, gin.H{
		"bucket":     media.Bucket,
		"object_key": media.ObjectKey,
		"mime_type":  media.MimeType,
	})
}

// PublishMedia publishes or unpublishes a media file
// POST /sdk/v1/training/media/:id/publish
func (h *TrainingHandlers) PublishMedia(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid media ID"})
		return
	}

	var req struct {
		Publish bool `json:"publish"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		req.Publish = true // Default to publish
	}

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

	c.JSON(http.StatusOK, gin.H{"status": "ok", "is_published": req.Publish})
}

// StreamMedia returns a redirect to a presigned URL for a media file
// GET /sdk/v1/training/media/:mediaId/stream
func (h *TrainingHandlers) StreamMedia(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid media ID"})
		return
	}

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

	if h.ttsClient == nil {
		c.JSON(http.StatusServiceUnavailable, gin.H{"error": "media streaming not available"})
		return
	}

	url, err := h.ttsClient.GetPresignedURL(c.Request.Context(), media.Bucket, media.ObjectKey)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate streaming URL: " + err.Error()})
		return
	}

	c.Redirect(http.StatusTemporaryRedirect, url)
}

// ============================================================================
// Interactive Video Endpoints
// ============================================================================

// GetInteractiveManifest returns the interactive video manifest with checkpoints and progress
// GET /sdk/v1/training/content/:moduleId/interactive-manifest
func (h *TrainingHandlers) GetInteractiveManifest(c *gin.Context) {
	moduleID, err := uuid.Parse(c.Param("moduleId"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid module ID"})
		return
	}

	// Get interactive video media
	mediaList, err := h.store.GetMediaForModule(c.Request.Context(), moduleID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Find interactive video
	var interactiveMedia *training.TrainingMedia
	for i := range mediaList {
		if mediaList[i].MediaType == training.MediaTypeInteractiveVideo && mediaList[i].Status == training.MediaStatusCompleted {
			interactiveMedia = &mediaList[i]
			break
		}
	}

	if interactiveMedia == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "no interactive video found for this module"})
		return
	}

	// Get checkpoints
	checkpoints, err := h.store.ListCheckpoints(c.Request.Context(), moduleID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Optional: get assignment ID for progress
	assignmentIDStr := c.Query("assignment_id")

	// Build manifest entries
	entries := make([]training.CheckpointManifestEntry, len(checkpoints))
	for i, cp := range checkpoints {
		// Get questions for this checkpoint
		questions, _ := h.store.GetCheckpointQuestions(c.Request.Context(), cp.ID)

		cpQuestions := make([]training.CheckpointQuestion, len(questions))
		for j, q := range questions {
			cpQuestions[j] = training.CheckpointQuestion{
				Question:     q.Question,
				Options:      q.Options,
				CorrectIndex: q.CorrectIndex,
				Explanation:  q.Explanation,
			}
		}

		entry := training.CheckpointManifestEntry{
			CheckpointID:     cp.ID,
			Index:            cp.CheckpointIndex,
			Title:            cp.Title,
			TimestampSeconds: cp.TimestampSeconds,
			Questions:        cpQuestions,
		}

		// Get progress if assignment_id provided
		if assignmentIDStr != "" {
			if assignmentID, err := uuid.Parse(assignmentIDStr); err == nil {
				progress, _ := h.store.GetCheckpointProgress(c.Request.Context(), assignmentID, cp.ID)
				entry.Progress = progress
			}
		}

		entries[i] = entry
	}

	// Get stream URL
	streamURL := ""
	if h.ttsClient != nil {
		url, err := h.ttsClient.GetPresignedURL(c.Request.Context(), interactiveMedia.Bucket, interactiveMedia.ObjectKey)
		if err == nil {
			streamURL = url
		}
	}

	manifest := training.InteractiveVideoManifest{
		MediaID:     interactiveMedia.ID,
		StreamURL:   streamURL,
		Checkpoints: entries,
	}

	c.JSON(http.StatusOK, manifest)
}

// SubmitCheckpointQuiz handles checkpoint quiz submission
// POST /sdk/v1/training/checkpoints/:checkpointId/submit
func (h *TrainingHandlers) SubmitCheckpointQuiz(c *gin.Context) {
	checkpointID, err := uuid.Parse(c.Param("checkpointId"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid checkpoint ID"})
		return
	}

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

	assignmentID, err := uuid.Parse(req.AssignmentID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid assignment ID"})
		return
	}

	// Get checkpoint questions
	questions, err := h.store.GetCheckpointQuestions(c.Request.Context(), checkpointID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	if len(questions) == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "no questions found for this checkpoint"})
		return
	}

	// Grade answers
	correctCount := 0
	feedback := make([]training.CheckpointQuizFeedback, len(questions))
	for i, q := range questions {
		isCorrect := false
		if i < len(req.Answers) && req.Answers[i] == q.CorrectIndex {
			isCorrect = true
			correctCount++
		}
		feedback[i] = training.CheckpointQuizFeedback{
			Question:    q.Question,
			Correct:     isCorrect,
			Explanation: q.Explanation,
		}
	}

	score := float64(correctCount) / float64(len(questions)) * 100
	passed := score >= 70 // 70% threshold for checkpoint

	// Update progress
	progress := &training.CheckpointProgress{
		AssignmentID: assignmentID,
		CheckpointID: checkpointID,
		Passed:       passed,
		Attempts:     1,
	}
	if err := h.store.UpsertCheckpointProgress(c.Request.Context(), progress); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Audit log
	userID := rbac.GetUserID(c)
	h.store.LogAction(c.Request.Context(), &training.AuditLogEntry{
		TenantID:   rbac.GetTenantID(c),
		UserID:     &userID,
		Action:     training.AuditAction("checkpoint_submitted"),
		EntityType: training.AuditEntityType("checkpoint"),
		EntityID:   &checkpointID,
		Details: map[string]interface{}{
			"assignment_id": assignmentID.String(),
			"score":         score,
			"passed":        passed,
			"correct":       correctCount,
			"total":         len(questions),
		},
	})

	c.JSON(http.StatusOK, training.SubmitCheckpointQuizResponse{
		Passed:   passed,
		Score:    score,
		Feedback: feedback,
	})
}

// GetCheckpointProgress returns all checkpoint progress for an assignment
// GET /sdk/v1/training/checkpoints/progress/:assignmentId
func (h *TrainingHandlers) GetCheckpointProgress(c *gin.Context) {
	assignmentID, err := uuid.Parse(c.Param("assignmentId"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid assignment ID"})
		return
	}

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

	c.JSON(http.StatusOK, gin.H{
		"progress": progress,
		"total":    len(progress),
	})
}
