package handlers

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

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

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

type HomeHandler struct {
	homeService *services.HomeService
}

func NewHomeHandler(homeService *services.HomeService) *HomeHandler {
	return &HomeHandler{homeService: homeService}
}

type CreateHomeRequest struct {
	Name     string   `json:"name" binding:"required"`
	Title    string   `json:"title" binding:"required"`
	Button1  string   `json:"button1" binding:"required"`
	Button2  string   `json:"button2" binding:"required"`
	Video    string   `json:"video"`
	Keywords string   `json:"keywords" binding:"required"`
	TagIDs   []string `json:"tag_ids"`
	Image    string   `json:"image"`
	IsActive *bool    `json:"is_active"`
}

type UpdateHomeRequest struct {
	Name     *string   `json:"name"`
	Title    *string   `json:"title"`
	Button1  *string   `json:"button1"`
	Button2  *string   `json:"button2"`
	Video    *string   `json:"video"`
	Keywords *string   `json:"keywords"`
	TagIDs   *[]string `json:"tag_ids"`
	Image    *string   `json:"image"`
	Slug     *string   `json:"slug"`
	IsActive *bool     `json:"is_active"`
}

// GetAllHomes godoc
// @Summary Get all active homes
// @Description Retrieve a list of active home entries
// @Tags home
// @Produce json
// @Success 200 {array} models.Home
// @Failure 500 {object} map[string]string
// @Router /homes [get]
func (h *HomeHandler) GetAllHomes(c *gin.Context) {
	homes, err := h.homeService.GetAllHomes(true)
	if err != nil {
		status := http.StatusInternalServerError
		if isHomeBadRequest(err) {
			status = http.StatusBadRequest
		}
		c.JSON(status, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, homes)
}

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

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

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

// CreateHome godoc
// @Summary Create a new home (Admin)
// @Description Create a new home entry
// @Tags admin
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param name formData string true "Name"
// @Param title formData string true "Title"
// @Param button1 formData string true "Button 1"
// @Param button2 formData string true "Button 2"
// @Param video formData string false "Video URL"
// @Param keywords formData string true "Keywords"
// @Param tag_ids formData []string false "Tag IDs"
// @Param image formData file false "Home image"
// @Param is_active formData bool false "Is active"
// @Success 201 {object} models.Home
// @Failure 400 {object} map[string]string
// @Router /admin/homes [post]
func (h *HomeHandler) CreateHome(c *gin.Context) {
	name := strings.TrimSpace(c.PostForm("name"))
	title := strings.TrimSpace(c.PostForm("title"))
	button1 := strings.TrimSpace(c.PostForm("button1"))
	button2 := strings.TrimSpace(c.PostForm("button2"))
	video := strings.TrimSpace(c.PostForm("video"))
	keywords := strings.TrimSpace(c.PostForm("keywords"))

	if name == "" || title == "" || button1 == "" || button2 == "" || keywords == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "name, title, button1, button2, and keywords are required"})
		return
	}

	isActive := false
	if rawActive := strings.TrimSpace(c.PostForm("is_active")); rawActive != "" {
		parsed, err := strconv.ParseBool(rawActive)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "is_active must be true or false"})
			return
		}
		isActive = parsed
	}

	tagIDs := parseTagIDs(c)

	home, err := h.homeService.CreateHome(
		name,
		title,
		button1,
		button2,
		video,
		keywords,
		"",
		tagIDs,
		isActive,
	)
	if err != nil {
		status := http.StatusInternalServerError
		if isHomeBadRequest(err) {
			status = http.StatusBadRequest
		}
		c.JSON(status, gin.H{"error": err.Error()})
		return
	}

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

		imageURL, saveErr := utils.SaveOptimizedImage(file, "./uploads/homes", home.ID.String(), &utils.ImageOptions{
			Width:   config.AppConfig.HomeImageWidth,
			Height:  config.AppConfig.HomeImageHeight,
			Quality: float32(config.AppConfig.HomeImageQuality),
			Format:  config.AppConfig.HomeImageFormat,
			Mode:    config.AppConfig.HomeImageMode,
		})
		if saveErr != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image: " + saveErr.Error()})
			return
		}

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

	c.JSON(http.StatusCreated, home)
}

// UpdateHome godoc
// @Summary Update a home (Admin)
// @Description Update an existing home entry
// @Tags admin
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param id path string true "Home ID"
// @Param name formData string false "Name"
// @Param title formData string false "Title"
// @Param button1 formData string false "Button 1"
// @Param button2 formData string false "Button 2"
// @Param video formData string false "Video URL"
// @Param keywords formData string false "Keywords"
// @Param tag_ids formData []string false "Tag IDs"
// @Param image formData file false "Home image"
// @Param slug formData string false "Slug"
// @Param is_active formData bool false "Is active"
// @Success 200 {object} models.Home
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /admin/homes/{id} [put]
func (h *HomeHandler) UpdateHome(c *gin.Context) {
	id := c.Param("id")

	name, hasName := getOptionalFormValue(c, "name")
	title, hasTitle := getOptionalFormValue(c, "title")
	button1, hasButton1 := getOptionalFormValue(c, "button1")
	button2, hasButton2 := getOptionalFormValue(c, "button2")
	video, hasVideo := getOptionalFormValue(c, "video")
	keywords, hasKeywords := getOptionalFormValue(c, "keywords")
	slug, hasSlug := getOptionalFormValue(c, "slug")

	var namePtr *string
	var titlePtr *string
	var button1Ptr *string
	var button2Ptr *string
	var videoPtr *string
	var keywordsPtr *string
	var slugPtr *string

	if hasName {
		namePtr = &name
	}
	if hasTitle {
		titlePtr = &title
	}
	if hasButton1 {
		button1Ptr = &button1
	}
	if hasButton2 {
		button2Ptr = &button2
	}
	if hasVideo {
		videoPtr = &video
	}
	if hasKeywords {
		keywordsPtr = &keywords
	}
	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 tagIDsPtr *[]string
	if hasTagIDs(c) {
		tagIDs := parseTagIDs(c)
		tagIDsPtr = &tagIDs
	}

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

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

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

		imageURL, saveErr := utils.SaveOptimizedImage(file, "./uploads/homes", id, &utils.ImageOptions{
			Width:   config.AppConfig.HomeImageWidth,
			Height:  config.AppConfig.HomeImageHeight,
			Quality: float32(config.AppConfig.HomeImageQuality),
			Format:  config.AppConfig.HomeImageFormat,
			Mode:    config.AppConfig.HomeImageMode,
		})
		if saveErr != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image: " + saveErr.Error()})
			return
		}
		imagePtr = &imageURL
	}

	home, err := h.homeService.UpdateHome(
		id,
		namePtr,
		titlePtr,
		button1Ptr,
		button2Ptr,
		videoPtr,
		keywordsPtr,
		imagePtr,
		slugPtr,
		tagIDsPtr,
		isActivePtr,
	)
	if err != nil {
		status := http.StatusInternalServerError
		if err.Error() == "home not found" {
			status = http.StatusNotFound
		} else if isHomeBadRequest(err) {
			status = http.StatusBadRequest
		}
		c.JSON(status, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, home)
}

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

// AdminUploadHomeImage godoc
// @Summary Upload home image (Admin)
// @Description Upload an image for a specific home entry
// @Tags admin
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param id path string true "Home ID"
// @Param image formData file true "Home image"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /admin/homes/{id}/image [post]
func (h *HomeHandler) AdminUploadHomeImage(c *gin.Context) {
	id := c.Param("id")

	file, err := c.FormFile("image")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "No file uploaded"})
		return
	}

	if file.Size > 5*1024*1024 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "File size exceeds 5MB limit"})
		return
	}

	home, err := h.homeService.GetHomeByID(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

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

	imageURL, err := utils.SaveOptimizedImage(file, "./uploads/homes", id, &utils.ImageOptions{
		Width:   config.AppConfig.HomeImageWidth,
		Height:  config.AppConfig.HomeImageHeight,
		Quality: float32(config.AppConfig.HomeImageQuality),
		Format:  config.AppConfig.HomeImageFormat,
		Mode:    config.AppConfig.HomeImageMode,
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image: " + err.Error()})
		return
	}

	updated, err := h.homeService.UpdateHome(
		id,
		nil,
		nil,
		nil,
		nil,
		nil,
		nil,
		&imageURL,
		nil,
		nil,
		nil,
	)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message":   "Home image uploaded successfully",
		"image_url": imageURL,
		"home":      updated,
	})
}

func isHomeBadRequest(err error) bool {
	if err == nil {
		return false
	}

	switch err.Error() {
	case "slug already exists", "slug cannot be empty", "one or more tags not found":
		return true
	default:
		return false
	}
}

func parseTagIDs(c *gin.Context) []string {
	tagIDs := c.PostFormArray("tag_ids")
	if len(tagIDs) == 0 {
		raw := strings.TrimSpace(c.PostForm("tag_ids"))
		if raw == "" {
			return tagIDs
		}
		parts := strings.Split(raw, ",")
		for _, part := range parts {
			trimmed := strings.TrimSpace(part)
			if trimmed != "" {
				tagIDs = append(tagIDs, trimmed)
			}
		}
	}
	return tagIDs
}

func hasTagIDs(c *gin.Context) bool {
	if len(c.PostFormArray("tag_ids")) > 0 {
		return true
	}
	if raw := strings.TrimSpace(c.PostForm("tag_ids")); raw != "" {
		return true
	}
	return false
}
