package handlers

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

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

// ============================================================================
// Assignment Endpoints
// ============================================================================

// ComputeAssignments computes assignments for a user based on roles
// POST /sdk/v1/training/assignments/compute
func (h *TrainingHandlers) ComputeAssignments(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)

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

	trigger := req.Trigger
	if trigger == "" {
		trigger = "manual"
	}

	assignments, err := training.ComputeAssignments(
		c.Request.Context(), h.store, tenantID,
		req.UserID, req.UserName, req.UserEmail, req.Roles, trigger,
	)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"assignments": assignments,
		"created":     len(assignments),
	})
}

// ListAssignments returns assignments for the tenant
// GET /sdk/v1/training/assignments
func (h *TrainingHandlers) ListAssignments(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)

	filters := &training.AssignmentFilters{
		Limit:  50,
		Offset: 0,
	}

	if v := c.Query("user_id"); v != "" {
		if uid, err := uuid.Parse(v); err == nil {
			filters.UserID = &uid
		}
	}
	if v := c.Query("module_id"); v != "" {
		if mid, err := uuid.Parse(v); err == nil {
			filters.ModuleID = &mid
		}
	}
	if v := c.Query("role"); v != "" {
		filters.RoleCode = v
	}
	if v := c.Query("status"); v != "" {
		filters.Status = training.AssignmentStatus(v)
	}
	if v := c.Query("limit"); v != "" {
		if n, err := strconv.Atoi(v); err == nil {
			filters.Limit = n
		}
	}
	if v := c.Query("offset"); v != "" {
		if n, err := strconv.Atoi(v); err == nil {
			filters.Offset = n
		}
	}

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

	c.JSON(http.StatusOK, training.AssignmentListResponse{
		Assignments: assignments,
		Total:       total,
	})
}

// GetAssignment returns a single assignment
// GET /sdk/v1/training/assignments/:id
func (h *TrainingHandlers) GetAssignment(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid assignment ID"})
		return
	}

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

	c.JSON(http.StatusOK, assignment)
}

// StartAssignment marks an assignment as started
// POST /sdk/v1/training/assignments/:id/start
func (h *TrainingHandlers) StartAssignment(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid assignment ID"})
		return
	}
	tenantID := rbac.GetTenantID(c)

	if err := h.store.UpdateAssignmentStatus(c.Request.Context(), id, training.AssignmentStatusInProgress, 0); 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:   tenantID,
		UserID:     &userID,
		Action:     training.AuditActionStarted,
		EntityType: training.AuditEntityAssignment,
		EntityID:   &id,
	})

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

// UpdateAssignmentProgress updates progress on an assignment
// POST /sdk/v1/training/assignments/:id/progress
func (h *TrainingHandlers) UpdateAssignmentProgress(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid assignment ID"})
		return
	}

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

	status := training.AssignmentStatusInProgress
	if req.Progress >= 100 {
		status = training.AssignmentStatusCompleted
	}

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

	c.JSON(http.StatusOK, gin.H{"status": string(status), "progress": req.Progress})
}

// UpdateAssignment updates assignment fields (e.g. deadline)
// PUT /sdk/v1/training/assignments/:id
func (h *TrainingHandlers) UpdateAssignment(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid assignment ID"})
		return
	}

	var req struct {
		Deadline *string `json:"deadline"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
		return
	}

	if req.Deadline != nil {
		deadline, err := time.Parse(time.RFC3339, *req.Deadline)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid deadline format (use RFC3339)"})
			return
		}
		if err := h.store.UpdateAssignmentDeadline(c.Request.Context(), id, deadline); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}

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

	c.JSON(http.StatusOK, assignment)
}

// CompleteAssignment marks an assignment as completed
// POST /sdk/v1/training/assignments/:id/complete
func (h *TrainingHandlers) CompleteAssignment(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid assignment ID"})
		return
	}
	tenantID := rbac.GetTenantID(c)

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

	userID := rbac.GetUserID(c)
	h.store.LogAction(c.Request.Context(), &training.AuditLogEntry{
		TenantID:   tenantID,
		UserID:     &userID,
		Action:     training.AuditActionCompleted,
		EntityType: training.AuditEntityAssignment,
		EntityID:   &id,
	})

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