package handlers

import (
	"net/http"

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

// Handler contains all HTTP handlers
type Handler struct {
	cfg           *config.Config
	searchService *search.Service
	indexClient   *indexer.Client
}

// NewHandler creates a new handler instance
func NewHandler(cfg *config.Config, searchService *search.Service, indexClient *indexer.Client) *Handler {
	return &Handler{
		cfg:           cfg,
		searchService: searchService,
		indexClient:   indexClient,
	}
}

// Health returns service health status
func (h *Handler) Health(c *gin.Context) {
	status := "ok"

	// Check OpenSearch health
	osStatus, err := h.indexClient.Health(c.Request.Context())
	if err != nil {
		status = "degraded"
		osStatus = "unreachable"
	}

	c.JSON(http.StatusOK, gin.H{
		"status":           status,
		"opensearch":       osStatus,
		"service":          "edu-search-service",
		"version":          "0.1.0",
	})
}

// Search handles /v1/search requests
func (h *Handler) Search(c *gin.Context) {
	var req search.SearchRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
		return
	}

	// Set defaults
	if req.Limit <= 0 || req.Limit > 100 {
		req.Limit = 10
	}
	if req.Mode == "" {
		req.Mode = "keyword" // MVP: only BM25
	}

	// Generate query ID
	queryID := uuid.New().String()

	// Execute search
	result, err := h.searchService.Search(c.Request.Context(), &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Search failed", "details": err.Error()})
		return
	}

	result.QueryID = queryID
	c.JSON(http.StatusOK, result)
}

// GetDocument retrieves a single document
func (h *Handler) GetDocument(c *gin.Context) {
	docID := c.Query("doc_id")
	if docID == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "doc_id parameter required"})
		return
	}

	// TODO: Implement document retrieval
	c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented yet"})
}

// AuthMiddleware validates API keys
func AuthMiddleware(apiKey string) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Skip auth for health endpoint
		if c.Request.URL.Path == "/v1/health" {
			c.Next()
			return
		}

		// Check API key
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Missing Authorization header"})
			return
		}

		// Extract Bearer token
		if len(authHeader) < 7 || authHeader[:7] != "Bearer " {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid Authorization format"})
			return
		}

		token := authHeader[7:]
		if apiKey != "" && token != apiKey {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid API key"})
			return
		}

		c.Next()
	}
}

// RateLimitMiddleware implements basic rate limiting
func RateLimitMiddleware() gin.HandlerFunc {
	// TODO: Implement proper rate limiting with Redis
	return func(c *gin.Context) {
		c.Next()
	}
}

// SetupRoutes configures all API routes
func SetupRoutes(r *gin.Engine, h *Handler, apiKey string) {
	// Health endpoint (no auth)
	r.GET("/v1/health", h.Health)

	// API v1 group with auth
	v1 := r.Group("/v1")
	v1.Use(AuthMiddleware(apiKey))
	v1.Use(RateLimitMiddleware())
	{
		v1.POST("/search", h.Search)
		v1.GET("/document", h.GetDocument)

		// Admin routes
		SetupAdminRoutes(v1, h)
	}
}
