package handlers

import (
	"net/http"
	"strconv"

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

// ============================================================================
// Participant Management
// ============================================================================

// JoinSession allows a participant to join a session
// POST /sdk/v1/workshops/join/:code
func (h *WorkshopHandlers) JoinSession(c *gin.Context) {
	code := c.Param("code")

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

	if session.Status == workshop.SessionStatusCompleted || session.Status == workshop.SessionStatusCancelled {
		c.JSON(http.StatusBadRequest, gin.H{"error": "session is no longer active"})
		return
	}

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

	// Get user ID if authenticated
	var userID *uuid.UUID
	if id := rbac.GetUserID(c); id != uuid.Nil {
		userID = &id
	}

	// Check if authentication is required
	if session.RequireAuth && userID == nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required to join this session"})
		return
	}

	participant := &workshop.Participant{
		SessionID:  session.ID,
		UserID:     userID,
		Name:       req.Name,
		Email:      req.Email,
		Role:       req.Role,
		Department: req.Department,
		CanEdit:    true,
		CanComment: true,
	}

	if participant.Role == "" {
		participant.Role = workshop.ParticipantRoleStakeholder
	}

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

	c.JSON(http.StatusOK, workshop.JoinSessionResponse{
		Participant: *participant,
		Session:     *session,
	})
}

// ListParticipants lists participants in a session
// GET /sdk/v1/workshops/:id/participants
func (h *WorkshopHandlers) ListParticipants(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid session ID"})
		return
	}

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

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

// LeaveSession removes a participant from a session
// POST /sdk/v1/workshops/:id/leave
func (h *WorkshopHandlers) LeaveSession(c *gin.Context) {
	var req struct {
		ParticipantID uuid.UUID `json:"participant_id"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

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

	c.JSON(http.StatusOK, gin.H{"message": "left session"})
}

// UpdateParticipant updates a participant's info
// PUT /sdk/v1/workshops/:id/participants/:participantId
func (h *WorkshopHandlers) UpdateParticipant(c *gin.Context) {
	participantID, err := uuid.Parse(c.Param("participantId"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid participant ID"})
		return
	}

	var req struct {
		Name       string                   `json:"name"`
		Role       workshop.ParticipantRole `json:"role"`
		Department string                   `json:"department"`
		CanEdit    *bool                    `json:"can_edit,omitempty"`
		CanComment *bool                    `json:"can_comment,omitempty"`
		CanApprove *bool                    `json:"can_approve,omitempty"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

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

	if req.Name != "" {
		participant.Name = req.Name
	}
	if req.Role != "" {
		participant.Role = req.Role
	}
	if req.Department != "" {
		participant.Department = req.Department
	}
	if req.CanEdit != nil {
		participant.CanEdit = *req.CanEdit
	}
	if req.CanComment != nil {
		participant.CanComment = *req.CanComment
	}
	if req.CanApprove != nil {
		participant.CanApprove = *req.CanApprove
	}

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

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

// RemoveParticipant removes a participant from a session
// DELETE /sdk/v1/workshops/:id/participants/:participantId
func (h *WorkshopHandlers) RemoveParticipant(c *gin.Context) {
	participantID, err := uuid.Parse(c.Param("participantId"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid participant ID"})
		return
	}

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

	c.JSON(http.StatusOK, gin.H{"message": "participant removed"})
}

// ============================================================================
// Wizard Navigation & Responses
// ============================================================================

// SubmitResponse submits a response to a question
// POST /sdk/v1/workshops/:id/responses
func (h *WorkshopHandlers) SubmitResponse(c *gin.Context) {
	sessionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid session ID"})
		return
	}

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

	// Get participant ID from request or context
	participantID, err := uuid.Parse(c.GetHeader("X-Participant-ID"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "participant ID required"})
		return
	}

	// Determine value type
	valueType := "string"
	switch req.Value.(type) {
	case bool:
		valueType = "boolean"
	case float64:
		valueType = "number"
	case []interface{}:
		valueType = "array"
	case map[string]interface{}:
		valueType = "object"
	}

	response := &workshop.Response{
		SessionID:     sessionID,
		ParticipantID: participantID,
		StepNumber:    req.StepNumber,
		FieldID:       req.FieldID,
		Value:         req.Value,
		ValueType:     valueType,
		Status:        workshop.ResponseStatusSubmitted,
	}

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

	// Update participant activity
	h.store.UpdateParticipantActivity(c.Request.Context(), participantID)

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

// GetResponses retrieves responses for a session
// GET /sdk/v1/workshops/:id/responses
func (h *WorkshopHandlers) GetResponses(c *gin.Context) {
	sessionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid session ID"})
		return
	}

	var stepNumber *int
	if step := c.Query("step"); step != "" {
		if s, err := strconv.Atoi(step); err == nil {
			stepNumber = &s
		}
	}

	responses, err := h.store.GetResponses(c.Request.Context(), sessionID, stepNumber)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

// AdvanceStep moves the session to the next step
// POST /sdk/v1/workshops/:id/advance
func (h *WorkshopHandlers) AdvanceStep(c *gin.Context) {
	sessionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid session ID"})
		return
	}

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

	if session.CurrentStep >= session.TotalSteps {
		c.JSON(http.StatusBadRequest, gin.H{"error": "already at last step"})
		return
	}

	// Mark current step as completed
	h.store.UpdateStepProgress(c.Request.Context(), sessionID, session.CurrentStep, "completed", 100)

	// Advance to next step
	if err := h.store.AdvanceStep(c.Request.Context(), sessionID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Initialize next step
	h.store.UpdateStepProgress(c.Request.Context(), sessionID, session.CurrentStep+1, "in_progress", 0)

	c.JSON(http.StatusOK, gin.H{
		"previous_step": session.CurrentStep,
		"current_step":  session.CurrentStep + 1,
		"message":       "advanced to next step",
	})
}

// GoToStep navigates to a specific step (if allowed)
// POST /sdk/v1/workshops/:id/goto
func (h *WorkshopHandlers) GoToStep(c *gin.Context) {
	sessionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid session ID"})
		return
	}

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

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

	// Check if back navigation is allowed
	if req.StepNumber < session.CurrentStep && !session.Settings.AllowBackNavigation {
		c.JSON(http.StatusBadRequest, gin.H{"error": "back navigation not allowed"})
		return
	}

	// Validate step number
	if req.StepNumber < 1 || req.StepNumber > session.TotalSteps {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid step number"})
		return
	}

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

	c.JSON(http.StatusOK, gin.H{
		"current_step": req.StepNumber,
		"message":      "navigated to step",
	})
}

// ============================================================================
// Comments
// ============================================================================

// AddComment adds a comment to a session
// POST /sdk/v1/workshops/:id/comments
func (h *WorkshopHandlers) AddComment(c *gin.Context) {
	sessionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid session ID"})
		return
	}

	var req struct {
		ParticipantID uuid.UUID  `json:"participant_id"`
		StepNumber    *int       `json:"step_number,omitempty"`
		FieldID       *string    `json:"field_id,omitempty"`
		ResponseID    *uuid.UUID `json:"response_id,omitempty"`
		Text          string     `json:"text"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if req.Text == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "comment text is required"})
		return
	}

	comment := &workshop.Comment{
		SessionID:     sessionID,
		ParticipantID: req.ParticipantID,
		StepNumber:    req.StepNumber,
		FieldID:       req.FieldID,
		ResponseID:    req.ResponseID,
		Text:          req.Text,
	}

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

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

// GetComments retrieves comments for a session
// GET /sdk/v1/workshops/:id/comments
func (h *WorkshopHandlers) GetComments(c *gin.Context) {
	sessionID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid session ID"})
		return
	}

	var stepNumber *int
	if step := c.Query("step"); step != "" {
		if s, err := strconv.Atoi(step); err == nil {
			stepNumber = &s
		}
	}

	comments, err := h.store.GetComments(c.Request.Context(), sessionID, stepNumber)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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