package handlers

import (
	"fmt"
	"net/http"

	"git.linuxforward.com/byop/byop-engine/models"
	"git.linuxforward.com/byop/byop-engine/services"
	"github.com/gin-gonic/gin"
)

// DeploymentHandler handles deployment-related operations
type DeploymentHandler struct {
	service *services.DeploymentService
}

// NewDeploymentHandler creates a new DeploymentHandler
func NewDeploymentHandler(service *services.DeploymentService) *DeploymentHandler {
	return &DeploymentHandler{
		service: service,
	}
}

// RegisterRoutes registers routes for deployment operations
func (h *DeploymentHandler) RegisterRoutes(r *gin.RouterGroup) {
	r.GET("/", h.ListDeployments)
	r.POST("/", h.CreateDeployment)
	r.GET("/:id", h.GetDeployment)
	r.PUT("/:id", h.UpdateDeployment)
	r.DELETE("/:id", h.DeleteDeployment)
	r.PUT("/:id/status", h.UpdateDeploymentStatus)
	r.GET("/by-client/:clientId", h.GetDeploymentsByClient)
	r.GET("/by-blueprint/:blueprintId", h.GetDeploymentsByBlueprint)
	r.GET("/by-user/:userId", h.GetDeploymentsByUser)
}

// ListDeployments returns all deployments with optional filtering
func (h *DeploymentHandler) ListDeployments(c *gin.Context) {
	filter := make(map[string]interface{})

	// Attempt to bind query parameters, but allow empty filters
	if err := c.ShouldBindQuery(&filter); err != nil && len(filter) > 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid query parameters"})
		return
	}

	deployments, err := h.service.ListDeployments(filter)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to list deployments: %v", err)})
		return
	}

	c.JSON(http.StatusOK, deployments)
}

// CreateDeployment creates a new deployment
func (h *DeploymentHandler) CreateDeployment(c *gin.Context) {
	var deployment models.Deployment

	if err := c.ShouldBindJSON(&deployment); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid request body: %v", err)})
		return
	}

	// Get the user ID from the context (set by auth middleware)
	userID, exists := c.Get("userID")
	if exists {
		deployment.CreatedBy = userID.(string)
	}

	if err := h.service.CreateDeployment(&deployment); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to create deployment: %v", err)})
		return
	}

	c.JSON(http.StatusCreated, deployment)
}

// GetDeployment returns a specific deployment
func (h *DeploymentHandler) GetDeployment(c *gin.Context) {
	id := c.Param("id")

	deployment, err := h.service.GetDeployment(id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to fetch deployment: %v", err)})
		return
	}

	if deployment == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Deployment not found"})
		return
	}

	c.JSON(http.StatusOK, deployment)
}

// UpdateDeployment updates a deployment
func (h *DeploymentHandler) UpdateDeployment(c *gin.Context) {
	id := c.Param("id")

	var updatedDeployment models.Deployment
	if err := c.ShouldBindJSON(&updatedDeployment); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid request body: %v", err)})
		return
	}

	// Ensure the ID matches the URL parameter
	updatedDeployment.ID = id

	if err := h.service.UpdateDeployment(&updatedDeployment); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to update deployment: %v", err)})
		return
	}

	c.JSON(http.StatusOK, updatedDeployment)
}

// DeleteDeployment deletes a deployment
func (h *DeploymentHandler) DeleteDeployment(c *gin.Context) {
	id := c.Param("id")

	if err := h.service.DeleteDeployment(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to delete deployment: %v", err)})
		return
	}

	c.Status(http.StatusNoContent)
}

// UpdateDeploymentStatus updates the status of a deployment
func (h *DeploymentHandler) UpdateDeploymentStatus(c *gin.Context) {
	id := c.Param("id")

	var statusUpdate struct {
		Status string `json:"status" binding:"required"`
	}

	if err := c.ShouldBindJSON(&statusUpdate); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid request body: %v", err)})
		return
	}

	if err := h.service.UpdateDeploymentStatus(id, statusUpdate.Status); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to update deployment status: %v", err)})
		return
	}

	c.Status(http.StatusOK)
}

// GetDeploymentsByClient returns all deployments for a specific client
func (h *DeploymentHandler) GetDeploymentsByClient(c *gin.Context) {
	clientID := c.Param("clientId")

	deployments, err := h.service.GetDeploymentsByClientID(clientID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to fetch client deployments: %v", err)})
		return
	}

	c.JSON(http.StatusOK, deployments)
}

// GetDeploymentsByBlueprint returns all deployments for a specific blueprint
func (h *DeploymentHandler) GetDeploymentsByBlueprint(c *gin.Context) {
	blueprintID := c.Param("blueprintId")

	deployments, err := h.service.GetDeploymentsByBlueprintID(blueprintID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to fetch blueprint deployments: %v", err)})
		return
	}

	c.JSON(http.StatusOK, deployments)
}

// GetDeploymentsByUser returns all deployments created by a specific user
func (h *DeploymentHandler) GetDeploymentsByUser(c *gin.Context) {
	userID := c.Param("userId")

	deployments, err := h.service.GetDeploymentsByUserID(userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to fetch user deployments: %v", err)})
		return
	}

	c.JSON(http.StatusOK, deployments)
}
