package handlers

import (
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"

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

// ConversationHandler handles conversation-related HTTP requests
type ConversationHandler struct {
	conversationService *conversation.ConversationService
}

// NewConversationHandler creates a new conversation handler
func NewConversationHandler() *ConversationHandler {
	return &ConversationHandler{
		conversationService: conversation.NewConversationService(),
	}
}

// CreateConversation handles creating a new conversation
func (h *ConversationHandler) CreateConversation(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.CreateConversationRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse create conversation request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

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

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

// GetConversation handles getting a conversation by ID
func (h *ConversationHandler) GetConversation(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 conversation ID from URL params
	conversationID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse conversation ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid conversation ID",
		})
		return
	}

	// Get conversation
	conv, err := h.conversationService.GetConversation(uint(conversationID), userID.(uint))
	if err != nil {
		logger.WithError(err).Error("Failed to get conversation")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get conversation",
		})
		return
	}

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

// ListConversations handles listing conversations for a user
func (h *ConversationHandler) ListConversations(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
	}

	// Parse query parameters
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	status := c.DefaultQuery("status", "")

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

	// List conversations
	response, err := h.conversationService.ListConversations(userID.(uint), page, pageSize, status)
	if err != nil {
		logger.WithError(err).Error("Failed to list conversations")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to list conversations",
		})
		return
	}

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

// UpdateConversation handles updating a conversation
func (h *ConversationHandler) UpdateConversation(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 conversation ID from URL params
	conversationID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse conversation ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid conversation ID",
		})
		return
	}

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

	// Update conversation
	conv, err := h.conversationService.UpdateConversation(uint(conversationID), userID.(uint), &req)
	if err != nil {
		logger.WithError(err).Error("Failed to update conversation")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to update conversation",
		})
		return
	}

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

// DeleteConversation handles deleting a conversation
func (h *ConversationHandler) DeleteConversation(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 conversation ID from URL params
	conversationID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse conversation ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid conversation ID",
		})
		return
	}

	// Delete conversation
	err = h.conversationService.DeleteConversation(uint(conversationID), userID.(uint))
	if err != nil {
		logger.WithError(err).Error("Failed to delete conversation")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to delete conversation",
		})
		return
	}

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

// CreateMessage handles creating a new message in a conversation
func (h *ConversationHandler) CreateMessage(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 conversation ID from URL params
	conversationID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse conversation ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid conversation ID",
		})
		return
	}

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

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

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

// GetMessages handles getting messages in a conversation
func (h *ConversationHandler) GetMessages(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 conversation ID from URL params
	conversationID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse conversation ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid conversation ID",
		})
		return
	}

	// Parse query parameters
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))

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

	// Get messages
	response, err := h.conversationService.GetMessages(uint(conversationID), userID.(uint), page, pageSize)
	if err != nil {
		logger.WithError(err).Error("Failed to get messages")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get messages",
		})
		return
	}

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

// UpdateMessage handles updating a message
func (h *ConversationHandler) UpdateMessage(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 message ID from URL params
	messageID, err := strconv.ParseUint(c.Param("messageId"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse message ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid message ID",
		})
		return
	}

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

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

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

// DeleteMessage handles deleting a message
func (h *ConversationHandler) DeleteMessage(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 message ID from URL params
	messageID, err := strconv.ParseUint(c.Param("messageId"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse message ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid message ID",
		})
		return
	}

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

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

// SendMessageWithAI handles sending a message and getting an AI response
func (h *ConversationHandler) SendMessageWithAI(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 conversation ID from URL params
	conversationID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse conversation ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid conversation ID",
		})
		return
	}

	var req struct {
		Content string `json:"content" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse send message request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

	// Send message and get AI response
	userMessage, aiMessage, err := h.conversationService.SendMessageWithAI(uint(conversationID), userID.(uint), req.Content)
	if err != nil {
		logger.WithError(err).Error("Failed to send message with AI")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to send message with AI",
		})
		return
	}

	c.JSON(http.StatusCreated, gin.H{
		"success": true,
		"message": "Message sent and AI response received",
		"data": gin.H{
			"userMessage": userMessage,
			"aiMessage":   aiMessage,
		},
	})
}

// GetConversationStats handles getting statistics for a conversation
func (h *ConversationHandler) GetConversationStats(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 conversation ID from URL params
	conversationID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse conversation ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid conversation ID",
		})
		return
	}

	// Get conversation stats
	stats, err := h.conversationService.GetConversationStats(uint(conversationID), userID.(uint))
	if err != nil {
		logger.WithError(err).Error("Failed to get conversation stats")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get conversation stats",
		})
		return
	}

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