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"
)

// AppHandler handles application-related operations
type AppHandler struct {
	service *services.AppService
}

// NewAppHandler creates a new AppHandler
func NewAppHandler(service *services.AppService) *AppHandler {
	return &AppHandler{
		service: service,
	}
}

// RegisterRoutes registers routes for app operations
func (h *AppHandler) RegisterRoutes(r *gin.RouterGroup) {
	r.GET("/", h.ListApps)
	r.POST("/", h.CreateApp)
	r.GET("/:id", h.GetApp)
	r.PUT("/:id", h.UpdateApp)
	r.DELETE("/:id", h.DeleteApp)
	r.GET("/:id/deployments", h.GetAppDeployments)
}

// ListApps returns all applications with optional filtering
func (h *AppHandler) ListApps(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
	}

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

	c.JSON(http.StatusOK, apps)
}

// CreateApp creates a new application
func (h *AppHandler) CreateApp(c *gin.Context) {
	var app models.App

	if err := c.ShouldBindJSON(&app); 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 {
		app.CreatedBy = userID.(string)
	}

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

	c.JSON(http.StatusCreated, app)
}

// GetApp returns a specific application
func (h *AppHandler) GetApp(c *gin.Context) {
	id := c.Param("id")

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

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

	c.JSON(http.StatusOK, app)
}

// UpdateApp updates an application
func (h *AppHandler) UpdateApp(c *gin.Context) {
	id := c.Param("id")

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

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

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

	c.JSON(http.StatusOK, updatedApp)
}

// DeleteApp deletes an application
func (h *AppHandler) DeleteApp(c *gin.Context) {
	id := c.Param("id")

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

	c.Status(http.StatusNoContent)
}

// GetAppDeployments returns all deployments for an application
func (h *AppHandler) GetAppDeployments(c *gin.Context) {
	id := c.Param("id")

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

	c.JSON(http.StatusOK, deployments)
}
