package handlers

import (
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"

	"customer-support-system/internal/knowledge"
	"customer-support-system/internal/models"
	"customer-support-system/pkg/logger"
)

// KnowledgeHandler handles knowledge base-related HTTP requests
type KnowledgeHandler struct {
	knowledgeService *knowledge.KnowledgeService
}

// NewKnowledgeHandler creates a new knowledge handler
func NewKnowledgeHandler() *KnowledgeHandler {
	return &KnowledgeHandler{
		knowledgeService: knowledge.NewKnowledgeService(),
	}
}

// CreateKnowledgeEntry handles creating a new knowledge base entry
func (h *KnowledgeHandler) CreateKnowledgeEntry(c *gin.Context) {
	// Get user ID from context
	userID, exists := c.Get("userID")
	if !exists {
		logger.Error("Failed to get user ID from context")
		c.JSON(http.StatusUnauthorized, gin.H{
			"success": false,
			"message": "Unauthorized",
		})
		return
	}

	var req models.CreateKnowledgeBaseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse create knowledge entry request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

	// Create knowledge entry
	entry, err := h.knowledgeService.CreateKnowledgeEntry(userID.(uint), &req)
	if err != nil {
		logger.WithError(err).Error("Failed to create knowledge entry")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to create knowledge entry",
		})
		return
	}

	c.JSON(http.StatusCreated, gin.H{
		"success": true,
		"message": "Knowledge entry created successfully",
		"data": gin.H{
			"entry": entry,
		},
	})
}

// GetKnowledgeEntry handles getting a knowledge base entry by ID
func (h *KnowledgeHandler) GetKnowledgeEntry(c *gin.Context) {
	// Get knowledge entry ID from URL params
	entryID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse knowledge entry ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid knowledge entry ID",
		})
		return
	}

	// Get knowledge entry
	entry, err := h.knowledgeService.GetKnowledgeEntry(uint(entryID))
	if err != nil {
		logger.WithError(err).Error("Failed to get knowledge entry")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get knowledge entry",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"entry": entry,
		},
	})
}

// ListKnowledgeEntries handles listing knowledge base entries
func (h *KnowledgeHandler) ListKnowledgeEntries(c *gin.Context) {
	// Parse query parameters
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	category := c.DefaultQuery("category", "")
	activeStr := c.DefaultQuery("active", "true")

	if page < 1 {
		page = 1
	}
	if pageSize < 1 || pageSize > 100 {
		pageSize = 10
	}

	// Parse active parameter
	var active *bool
	if activeStr != "" {
		activeVal := activeStr == "true"
		active = &activeVal
	}

	// List knowledge entries
	response, err := h.knowledgeService.ListKnowledgeEntries(page, pageSize, category, active)
	if err != nil {
		logger.WithError(err).Error("Failed to list knowledge entries")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to list knowledge entries",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"entries":  response.Entries,
			"total":    response.Total,
			"page":     response.Page,
			"pageSize": response.PageSize,
		},
	})
}

// UpdateKnowledgeEntry handles updating a knowledge base entry
func (h *KnowledgeHandler) UpdateKnowledgeEntry(c *gin.Context) {
	// Get user ID from context
	userID, exists := c.Get("userID")
	if !exists {
		logger.Error("Failed to get user ID from context")
		c.JSON(http.StatusUnauthorized, gin.H{
			"success": false,
			"message": "Unauthorized",
		})
		return
	}

	// Get knowledge entry ID from URL params
	entryID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse knowledge entry ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid knowledge entry ID",
		})
		return
	}

	var req models.UpdateKnowledgeBaseRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse update knowledge entry request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

	// Update knowledge entry
	entry, err := h.knowledgeService.UpdateKnowledgeEntry(uint(entryID), userID.(uint), &req)
	if err != nil {
		logger.WithError(err).Error("Failed to update knowledge entry")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to update knowledge entry",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"message": "Knowledge entry updated successfully",
		"data": gin.H{
			"entry": entry,
		},
	})
}

// DeleteKnowledgeEntry handles deleting a knowledge base entry
func (h *KnowledgeHandler) DeleteKnowledgeEntry(c *gin.Context) {
	// Get user ID from context
	userID, exists := c.Get("userID")
	if !exists {
		logger.Error("Failed to get user ID from context")
		c.JSON(http.StatusUnauthorized, gin.H{
			"success": false,
			"message": "Unauthorized",
		})
		return
	}

	// Get knowledge entry ID from URL params
	entryID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse knowledge entry ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid knowledge entry ID",
		})
		return
	}

	// Delete knowledge entry
	err = h.knowledgeService.DeleteKnowledgeEntry(uint(entryID), userID.(uint))
	if err != nil {
		logger.WithError(err).Error("Failed to delete knowledge entry")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to delete knowledge entry",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"message": "Knowledge entry deleted successfully",
	})
}

// SearchKnowledge handles searching knowledge base entries
func (h *KnowledgeHandler) SearchKnowledge(c *gin.Context) {
	// Parse query parameters
	query := c.DefaultQuery("query", "")
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	category := c.DefaultQuery("category", "")

	if page < 1 {
		page = 1
	}
	if pageSize < 1 || pageSize > 100 {
		pageSize = 10
	}

	// Search knowledge entries
	response, err := h.knowledgeService.SearchKnowledge(query, page, pageSize, category)
	if err != nil {
		logger.WithError(err).Error("Failed to search knowledge entries")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to search knowledge entries",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"results":  response.Results,
			"total":    response.Total,
			"query":    response.Query,
			"page":     response.Page,
			"pageSize": response.PageSize,
		},
	})
}

// GetCategories handles getting all unique categories in the knowledge base
func (h *KnowledgeHandler) GetCategories(c *gin.Context) {
	// Get categories
	categories, err := h.knowledgeService.GetCategories()
	if err != nil {
		logger.WithError(err).Error("Failed to get knowledge categories")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get knowledge categories",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"categories": categories,
		},
	})
}

// GetTags handles getting all unique tags in the knowledge base
func (h *KnowledgeHandler) GetTags(c *gin.Context) {
	// Get tags
	tags, err := h.knowledgeService.GetTags()
	if err != nil {
		logger.WithError(err).Error("Failed to get knowledge tags")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get knowledge tags",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"tags": tags,
		},
	})
}

// RateKnowledgeEntry handles rating a knowledge base entry as helpful or not
func (h *KnowledgeHandler) RateKnowledgeEntry(c *gin.Context) {
	// Get user ID from context
	userID, exists := c.Get("userID")
	if !exists {
		logger.Error("Failed to get user ID from context")
		c.JSON(http.StatusUnauthorized, gin.H{
			"success": false,
			"message": "Unauthorized",
		})
		return
	}

	// Get knowledge entry ID from URL params
	entryID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse knowledge entry ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid knowledge entry ID",
		})
		return
	}

	var req models.CreateKnowledgeBaseFeedbackRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse rate knowledge entry request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

	// Rate knowledge entry
	err = h.knowledgeService.RateKnowledgeEntry(uint(entryID), userID.(uint), req.Helpful, req.Comment)
	if err != nil {
		logger.WithError(err).Error("Failed to rate knowledge entry")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to rate knowledge entry",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"message": "Knowledge entry rated successfully",
	})
}

// GetPopularKnowledge handles getting popular knowledge base entries
func (h *KnowledgeHandler) GetPopularKnowledge(c *gin.Context) {
	// Parse query parameters
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
	if limit < 1 || limit > 100 {
		limit = 10
	}

	// Get popular knowledge entries
	entries, err := h.knowledgeService.GetPopularKnowledge(limit)
	if err != nil {
		logger.WithError(err).Error("Failed to get popular knowledge entries")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get popular knowledge entries",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"entries": entries,
		},
	})
}

// GetRecentKnowledge handles getting recent knowledge base entries
func (h *KnowledgeHandler) GetRecentKnowledge(c *gin.Context) {
	// Parse query parameters
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
	if limit < 1 || limit > 100 {
		limit = 10
	}

	// Get recent knowledge entries
	entries, err := h.knowledgeService.GetRecentKnowledge(limit)
	if err != nil {
		logger.WithError(err).Error("Failed to get recent knowledge entries")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get recent knowledge entries",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"entries": entries,
		},
	})
}

// FindBestMatch handles finding the best matching knowledge base entry for a query
func (h *KnowledgeHandler) FindBestMatch(c *gin.Context) {
	// Parse query parameters
	query := c.DefaultQuery("query", "")
	if query == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Query parameter is required",
		})
		return
	}

	// Find best match
	entry, err := h.knowledgeService.FindBestMatch(query)
	if err != nil {
		logger.WithError(err).Error("Failed to find best match")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to find best match",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"entry": entry,
		},
	})
}

// GetKnowledgeStats handles getting statistics for the knowledge base
func (h *KnowledgeHandler) GetKnowledgeStats(c *gin.Context) {
	// Get knowledge stats
	stats, err := h.knowledgeService.GetKnowledgeStats()
	if err != nil {
		logger.WithError(err).Error("Failed to get knowledge stats")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get knowledge stats",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"stats": stats,
		},
	})
}
