package handlers

import (
	"net/http"
	"strconv"

	"github.com/breakpilot/edu-search-service/internal/orchestrator"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// AudienceHandler handles audience-related HTTP requests
type AudienceHandler struct {
	repo orchestrator.AudienceRepository
}

// NewAudienceHandler creates a new audience handler
func NewAudienceHandler(repo orchestrator.AudienceRepository) *AudienceHandler {
	return &AudienceHandler{repo: repo}
}

// CreateAudienceRequest represents a request to create an audience
type CreateAudienceRequest struct {
	Name        string                      `json:"name" binding:"required"`
	Description string                      `json:"description"`
	Filters     orchestrator.AudienceFilters `json:"filters"`
	CreatedBy   string                      `json:"created_by"`
}

// UpdateAudienceRequest represents a request to update an audience
type UpdateAudienceRequest struct {
	Name        string                      `json:"name" binding:"required"`
	Description string                      `json:"description"`
	Filters     orchestrator.AudienceFilters `json:"filters"`
	IsActive    bool                        `json:"is_active"`
}

// CreateExportRequest represents a request to create an export
type CreateExportRequest struct {
	ExportType string `json:"export_type" binding:"required"` // csv, json, email_list
	Purpose    string `json:"purpose"`
	ExportedBy string `json:"exported_by"`
}

// ListAudiences returns all audiences
func (h *AudienceHandler) ListAudiences(c *gin.Context) {
	activeOnly := c.Query("active_only") == "true"

	audiences, err := h.repo.ListAudiences(c.Request.Context(), activeOnly)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list audiences", "details": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"audiences": audiences,
		"count":     len(audiences),
	})
}

// GetAudience returns a single audience
func (h *AudienceHandler) GetAudience(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid audience ID"})
		return
	}

	audience, err := h.repo.GetAudience(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Audience not found", "details": err.Error()})
		return
	}

	c.JSON(http.StatusOK, audience)
}

// CreateAudience creates a new audience
func (h *AudienceHandler) CreateAudience(c *gin.Context) {
	var req CreateAudienceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
		return
	}

	audience := &orchestrator.Audience{
		Name:        req.Name,
		Description: req.Description,
		Filters:     req.Filters,
		CreatedBy:   req.CreatedBy,
		IsActive:    true,
	}

	if err := h.repo.CreateAudience(c.Request.Context(), audience); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create audience", "details": err.Error()})
		return
	}

	// Update the member count
	count, _ := h.repo.UpdateAudienceCount(c.Request.Context(), audience.ID)
	audience.MemberCount = count

	c.JSON(http.StatusCreated, audience)
}

// UpdateAudience updates an existing audience
func (h *AudienceHandler) UpdateAudience(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid audience ID"})
		return
	}

	var req UpdateAudienceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
		return
	}

	audience := &orchestrator.Audience{
		ID:          id,
		Name:        req.Name,
		Description: req.Description,
		Filters:     req.Filters,
		IsActive:    req.IsActive,
	}

	if err := h.repo.UpdateAudience(c.Request.Context(), audience); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update audience", "details": err.Error()})
		return
	}

	// Update the member count
	count, _ := h.repo.UpdateAudienceCount(c.Request.Context(), audience.ID)
	audience.MemberCount = count

	c.JSON(http.StatusOK, audience)
}

// DeleteAudience soft-deletes an audience
func (h *AudienceHandler) DeleteAudience(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid audience ID"})
		return
	}

	if err := h.repo.DeleteAudience(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete audience", "details": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"deleted": true, "id": idStr})
}

// GetAudienceMembers returns members matching the audience filters
func (h *AudienceHandler) GetAudienceMembers(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid audience ID"})
		return
	}

	// Parse pagination
	limit := 50
	offset := 0
	if l := c.Query("limit"); l != "" {
		if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 && parsed <= 500 {
			limit = parsed
		}
	}
	if o := c.Query("offset"); o != "" {
		if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 {
			offset = parsed
		}
	}

	members, totalCount, err := h.repo.GetAudienceMembers(c.Request.Context(), id, limit, offset)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get members", "details": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"members":     members,
		"count":       len(members),
		"total_count": totalCount,
		"limit":       limit,
		"offset":      offset,
	})
}

// RefreshAudienceCount recalculates the member count
func (h *AudienceHandler) RefreshAudienceCount(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid audience ID"})
		return
	}

	count, err := h.repo.UpdateAudienceCount(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to refresh count", "details": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"audience_id":  idStr,
		"member_count": count,
	})
}

// PreviewAudienceFilters previews the result of filters without saving
func (h *AudienceHandler) PreviewAudienceFilters(c *gin.Context) {
	var filters orchestrator.AudienceFilters
	if err := c.ShouldBindJSON(&filters); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
		return
	}

	// Return the filters for now - preview functionality can be expanded later
	c.JSON(http.StatusOK, gin.H{
		"filters": filters,
		"message": "Preview functionality requires direct repository access",
	})
}

// CreateExport creates a new export for an audience
func (h *AudienceHandler) CreateExport(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid audience ID"})
		return
	}

	var req CreateExportRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
		return
	}

	// Get the member count for the export
	_, totalCount, err := h.repo.GetAudienceMembers(c.Request.Context(), id, 1, 0)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get members", "details": err.Error()})
		return
	}

	export := &orchestrator.AudienceExport{
		AudienceID:  id,
		ExportType:  req.ExportType,
		RecordCount: totalCount,
		ExportedBy:  req.ExportedBy,
		Purpose:     req.Purpose,
	}

	if err := h.repo.CreateExport(c.Request.Context(), export); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create export", "details": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, export)
}

// ListExports lists exports for an audience
func (h *AudienceHandler) ListExports(c *gin.Context) {
	idStr := c.Param("id")
	id, err := uuid.Parse(idStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid audience ID"})
		return
	}

	exports, err := h.repo.ListExports(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list exports", "details": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"exports": exports,
		"count":   len(exports),
	})
}

// SetupAudienceRoutes configures audience API routes
func SetupAudienceRoutes(r *gin.RouterGroup, h *AudienceHandler) {
	audiences := r.Group("/audiences")
	{
		// Audience CRUD
		audiences.GET("", h.ListAudiences)
		audiences.GET("/:id", h.GetAudience)
		audiences.POST("", h.CreateAudience)
		audiences.PUT("/:id", h.UpdateAudience)
		audiences.DELETE("/:id", h.DeleteAudience)

		// Members
		audiences.GET("/:id/members", h.GetAudienceMembers)
		audiences.POST("/:id/refresh", h.RefreshAudienceCount)

		// Exports
		audiences.GET("/:id/exports", h.ListExports)
		audiences.POST("/:id/exports", h.CreateExport)

		// Preview (no audience required)
		audiences.POST("/preview", h.PreviewAudienceFilters)
	}
}
