package handlers

import (
	"net/http"
	"os"
	"strings"

	"gauth-central/config"
	"gauth-central/internal/services"
	"gauth-central/pkg/utils"

	"github.com/gin-gonic/gin"
)

type ServiceHandler struct {
	serviceService *services.ServiceService
}

func NewServiceHandler(serviceService *services.ServiceService) *ServiceHandler {
	return &ServiceHandler{serviceService: serviceService}
}

// GetAllServices godoc
// @Summary Get all active services
// @Description Retrieve a list of active services
// @Tags services
// @Produce json
// @Success 200 {array} models.Service
// @Failure 500 {object} map[string]string
// @Router /services [get]
func (h *ServiceHandler) GetAllServices(c *gin.Context) {
	items, err := h.serviceService.GetAllServices(true)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, items)
}

// GetServiceBySlug godoc
// @Summary Get service by slug
// @Description Retrieve a single active service by slug
// @Tags services
// @Produce json
// @Param slug path string true "Service Slug"
// @Success 200 {object} models.Service
// @Failure 404 {object} map[string]string
// @Router /services/{slug} [get]
func (h *ServiceHandler) GetServiceBySlug(c *gin.Context) {
	slug := c.Param("slug")
	item, err := h.serviceService.GetServiceBySlug(slug, true)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, item)
}

// AdminGetAllServices godoc
// @Summary Get all services (Admin)
// @Description Retrieve a list of all services including inactive ones
// @Tags admin
// @Security ApiKeyAuth
// @Produce json
// @Success 200 {array} models.Service
// @Failure 500 {object} map[string]string
// @Router /admin/services [get]
func (h *ServiceHandler) AdminGetAllServices(c *gin.Context) {
	items, err := h.serviceService.GetAllServices(false)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, items)
}

// AdminGetServiceByID godoc
// @Summary Get a service by ID (Admin)
// @Description Retrieve details of a specific service
// @Tags admin
// @Security ApiKeyAuth
// @Produce json
// @Param id path string true "Service ID"
// @Success 200 {object} models.Service
// @Failure 404 {object} map[string]string
// @Router /admin/services/{id} [get]
func (h *ServiceHandler) AdminGetServiceByID(c *gin.Context) {
	id := c.Param("id")
	item, err := h.serviceService.GetServiceByID(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, item)
}

// CreateService godoc
// @Summary Create a new service (Admin)
// @Description Create a new service entry
// @Tags admin
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param title formData string true "Title"
// @Param content formData string false "Content"
// @Param image formData file false "Image"
// @Param is_active formData bool false "Is active"
// @Success 201 {object} models.Service
// @Failure 400 {object} map[string]string
// @Router /admin/services [post]
func (h *ServiceHandler) CreateService(c *gin.Context) {
	title := strings.TrimSpace(c.PostForm("title"))
	content := strings.TrimSpace(c.PostForm("content"))
	if title == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "title is required"})
		return
	}

	isActive := false
	isActivePtr, err := parseOptionalBool(c, "is_active")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "is_active must be true or false"})
		return
	}
	if isActivePtr != nil {
		isActive = *isActivePtr
	}

	item, err := h.serviceService.CreateService(title, content, "", isActive)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	file, fileErr := c.FormFile("image")
	if fileErr == nil {
		if file.Size > 5*1024*1024 {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Image size exceeds 5MB limit"})
			return
		}

		imageURL, saveErr := utils.SaveOptimizedImage(file, "./uploads/services", item.ID.String(), &utils.ImageOptions{
			Width:   config.AppConfig.ServiceImageWidth,
			Height:  config.AppConfig.ServiceImageHeight,
			Quality: float32(config.AppConfig.ServiceImageQuality),
			Format:  config.AppConfig.ServiceImageFormat,
			Mode:    config.AppConfig.ServiceImageMode,
		})
		if saveErr != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image: " + saveErr.Error()})
			return
		}

		updated, updateErr := h.serviceService.UpdateService(
			item.ID.String(),
			nil,
			nil,
			&imageURL,
			nil,
			nil,
		)
		if updateErr != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": updateErr.Error()})
			return
		}
		item = updated
	}

	c.JSON(http.StatusCreated, item)
}

// UpdateService godoc
// @Summary Update a service (Admin)
// @Description Update an existing service entry
// @Tags admin
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param id path string true "Service ID"
// @Param title formData string false "Title"
// @Param content formData string false "Content"
// @Param image formData file false "Image"
// @Param slug formData string false "Slug"
// @Param is_active formData bool false "Is active"
// @Success 200 {object} models.Service
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /admin/services/{id} [put]
func (h *ServiceHandler) UpdateService(c *gin.Context) {
	id := c.Param("id")

	title, hasTitle := getOptionalFormValue(c, "title")
	content, hasContent := getOptionalFormValue(c, "content")
	slug, hasSlug := getOptionalFormValue(c, "slug")

	var titlePtr *string
	var contentPtr *string
	var slugPtr *string

	if hasTitle {
		titlePtr = &title
	}
	if hasContent {
		contentPtr = &content
	}
	if hasSlug {
		slugPtr = &slug
	}

	isActivePtr, err := parseOptionalBool(c, "is_active")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "is_active must be true or false"})
		return
	}

	var imagePtr *string
	file, fileErr := c.FormFile("image")
	if fileErr == nil {
		if file.Size > 5*1024*1024 {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Image size exceeds 5MB limit"})
			return
		}

		item, fetchErr := h.serviceService.GetServiceByID(id)
		if fetchErr != nil {
			c.JSON(http.StatusNotFound, gin.H{"error": fetchErr.Error()})
			return
		}

		if item.Image != "" && strings.HasPrefix(item.Image, "/uploads/") {
			oldPath := "." + item.Image
			_ = os.Remove(oldPath)
		}

		imageURL, saveErr := utils.SaveOptimizedImage(file, "./uploads/services", id, &utils.ImageOptions{
			Width:   config.AppConfig.ServiceImageWidth,
			Height:  config.AppConfig.ServiceImageHeight,
			Quality: float32(config.AppConfig.ServiceImageQuality),
			Format:  config.AppConfig.ServiceImageFormat,
			Mode:    config.AppConfig.ServiceImageMode,
		})
		if saveErr != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image: " + saveErr.Error()})
			return
		}
		imagePtr = &imageURL
	}

	item, err := h.serviceService.UpdateService(
		id,
		titlePtr,
		contentPtr,
		imagePtr,
		slugPtr,
		isActivePtr,
	)
	if err != nil {
		status := http.StatusInternalServerError
		if err.Error() == "service not found" {
			status = http.StatusNotFound
		} else if err.Error() == "slug already exists" || err.Error() == "slug cannot be empty" {
			status = http.StatusBadRequest
		}
		c.JSON(status, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, item)
}

// DeleteService godoc
// @Summary Delete a service (Admin)
// @Description Delete a service by ID
// @Tags admin
// @Security ApiKeyAuth
// @Param id path string true "Service ID"
// @Success 200 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /admin/services/{id} [delete]
func (h *ServiceHandler) DeleteService(c *gin.Context) {
	id := c.Param("id")
	if err := h.serviceService.DeleteService(id); err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Service deleted successfully"})
}
