package handlers

import (
	"fmt"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

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

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

type AboutHandler struct {
	aboutService *services.AboutService
}

func NewAboutHandler(aboutService *services.AboutService) *AboutHandler {
	return &AboutHandler{aboutService: aboutService}
}

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

// GetActiveAbout godoc
// @Summary Get active about entry
// @Description Retrieve the newest active about entry
// @Tags about
// @Produce json
// @Success 200 {object} models.About
// @Failure 404 {object} map[string]string
// @Router /about/active [get]
func (h *AboutHandler) GetActiveAbout(c *gin.Context) {
	about, err := h.aboutService.GetFirstActiveAbout()
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, about)
}

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

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

// CreateAbout godoc
// @Summary Create a new about entry (Admin)
// @Description Create a new about entry
// @Tags admin
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param title formData string true "Title"
// @Param image formData file false "Image"
// @Param image_sub formData string false "Image subtitle"
// @Param cv formData file false "CV file"
// @Param birthday formData string false "Birthday"
// @Param city formData string false "City"
// @Param study formData string false "Study"
// @Param website formData string false "Website"
// @Param phone formData string false "Phone"
// @Param age formData string false "Age"
// @Param interests formData string false "Interests"
// @Param degree formData string false "Degree"
// @Param x formData string false "X"
// @Param mail formData string false "Mail"
// @Param done formData int false "Done"
// @Param project_done formData string false "Project done"
// @Param user_h formData int false "User count"
// @Param hapy_user formData string false "Happy user"
// @Param great formData int false "Great"
// @Param great_reviews formData string false "Great reviews"
// @Param team formData int false "Team"
// @Param support_team formData string false "Support team"
// @Param is_active formData bool false "Is active"
// @Param counter_active formData bool false "Counter active"
// @Success 201 {object} models.About
// @Failure 400 {object} map[string]string
// @Router /admin/about [post]
func (h *AboutHandler) CreateAbout(c *gin.Context) {
	title := strings.TrimSpace(c.PostForm("title"))
	if title == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "title is required"})
		return
	}

	imageSub := strings.TrimSpace(c.PostForm("image_sub"))
	birthday := strings.TrimSpace(c.PostForm("birthday"))
	city := strings.TrimSpace(c.PostForm("city"))
	study := strings.TrimSpace(c.PostForm("study"))
	website := strings.TrimSpace(c.PostForm("website"))
	phone := strings.TrimSpace(c.PostForm("phone"))
	age := strings.TrimSpace(c.PostForm("age"))
	interests := strings.TrimSpace(c.PostForm("interests"))
	degree := strings.TrimSpace(c.PostForm("degree"))
	xValue := strings.TrimSpace(c.PostForm("x"))
	mail := strings.TrimSpace(c.PostForm("mail"))
	projectDone := strings.TrimSpace(c.PostForm("project_done"))
	hapyUser := strings.TrimSpace(c.PostForm("hapy_user"))
	greatReviews := strings.TrimSpace(c.PostForm("great_reviews"))
	supportTeam := strings.TrimSpace(c.PostForm("support_team"))

	done, err := parseOptionalInt(c, "done")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "done must be a number"})
		return
	}
	userH, err := parseOptionalInt(c, "user_h")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "user_h must be a number"})
		return
	}
	great, err := parseOptionalInt(c, "great")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "great must be a number"})
		return
	}
	team, err := parseOptionalInt(c, "team")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "team must be a number"})
		return
	}

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

	isActive := false
	if isActivePtr != nil {
		isActive = *isActivePtr
	}
	counterActive := false
	if counterActivePtr != nil {
		counterActive = *counterActivePtr
	}

	imageURL := ""
	imageFile, imageErr := c.FormFile("image")
	if imageErr == nil {
		if imageFile.Size > 5*1024*1024 {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Image size exceeds 5MB limit"})
			return
		}
		imageURL, err = utils.SaveOptimizedImage(imageFile, "./uploads/about", "about", &utils.ImageOptions{
			Width:   config.AppConfig.AboutImageWidth,
			Height:  config.AppConfig.AboutImageHeight,
			Quality: float32(config.AppConfig.AboutImageQuality),
			Format:  config.AppConfig.AboutImageFormat,
			Mode:    config.AppConfig.AboutImageMode,
		})
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image: " + err.Error()})
			return
		}
	}

	cvPath := ""
	cvFile, cvErr := c.FormFile("cv")
	if cvErr == nil {
		cvPath, err = saveUploadedFile(c, cvFile, "./uploads/cv", "cv")
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save CV: " + err.Error()})
			return
		}
	}

	about, err := h.aboutService.CreateAbout(
		title,
		imageURL,
		imageSub,
		cvPath,
		birthday,
		city,
		study,
		website,
		phone,
		age,
		interests,
		degree,
		xValue,
		mail,
		done,
		projectDone,
		userH,
		hapyUser,
		great,
		greatReviews,
		team,
		supportTeam,
		isActive,
		counterActive,
	)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, about)
}

// UpdateAbout godoc
// @Summary Update an about entry (Admin)
// @Description Update an existing about entry
// @Tags admin
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param id path string true "About ID"
// @Param title formData string false "Title"
// @Param image formData file false "Image"
// @Param image_sub formData string false "Image subtitle"
// @Param cv formData file false "CV file"
// @Param birthday formData string false "Birthday"
// @Param city formData string false "City"
// @Param study formData string false "Study"
// @Param website formData string false "Website"
// @Param phone formData string false "Phone"
// @Param age formData string false "Age"
// @Param interests formData string false "Interests"
// @Param degree formData string false "Degree"
// @Param x formData string false "X"
// @Param mail formData string false "Mail"
// @Param done formData int false "Done"
// @Param project_done formData string false "Project done"
// @Param user_h formData int false "User count"
// @Param hapy_user formData string false "Happy user"
// @Param great formData int false "Great"
// @Param great_reviews formData string false "Great reviews"
// @Param team formData int false "Team"
// @Param support_team formData string false "Support team"
// @Param slug formData string false "Slug"
// @Param is_active formData bool false "Is active"
// @Param counter_active formData bool false "Counter active"
// @Success 200 {object} models.About
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /admin/about/{id} [put]
func (h *AboutHandler) UpdateAbout(c *gin.Context) {
	id := c.Param("id")

	title, hasTitle := getOptionalFormValue(c, "title")
	imageSub, hasImageSub := getOptionalFormValue(c, "image_sub")
	birthday, hasBirthday := getOptionalFormValue(c, "birthday")
	city, hasCity := getOptionalFormValue(c, "city")
	study, hasStudy := getOptionalFormValue(c, "study")
	website, hasWebsite := getOptionalFormValue(c, "website")
	phone, hasPhone := getOptionalFormValue(c, "phone")
	age, hasAge := getOptionalFormValue(c, "age")
	interests, hasInterests := getOptionalFormValue(c, "interests")
	degree, hasDegree := getOptionalFormValue(c, "degree")
	xValue, hasX := getOptionalFormValue(c, "x")
	mail, hasMail := getOptionalFormValue(c, "mail")
	projectDone, hasProjectDone := getOptionalFormValue(c, "project_done")
	hapyUser, hasHapyUser := getOptionalFormValue(c, "hapy_user")
	greatReviews, hasGreatReviews := getOptionalFormValue(c, "great_reviews")
	supportTeam, hasSupportTeam := getOptionalFormValue(c, "support_team")
	slug, hasSlug := getOptionalFormValue(c, "slug")

	done, err := parseOptionalInt(c, "done")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "done must be a number"})
		return
	}
	userH, err := parseOptionalInt(c, "user_h")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "user_h must be a number"})
		return
	}
	great, err := parseOptionalInt(c, "great")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "great must be a number"})
		return
	}
	team, err := parseOptionalInt(c, "team")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "team must be a number"})
		return
	}

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

	var titlePtr *string
	var imageSubPtr *string
	var birthdayPtr *string
	var cityPtr *string
	var studyPtr *string
	var websitePtr *string
	var phonePtr *string
	var agePtr *string
	var interestsPtr *string
	var degreePtr *string
	var xPtr *string
	var mailPtr *string
	var projectDonePtr *string
	var hapyUserPtr *string
	var greatReviewsPtr *string
	var supportTeamPtr *string
	var slugPtr *string

	if hasTitle {
		titlePtr = &title
	}
	if hasImageSub {
		imageSubPtr = &imageSub
	}
	if hasBirthday {
		birthdayPtr = &birthday
	}
	if hasCity {
		cityPtr = &city
	}
	if hasStudy {
		studyPtr = &study
	}
	if hasWebsite {
		websitePtr = &website
	}
	if hasPhone {
		phonePtr = &phone
	}
	if hasAge {
		agePtr = &age
	}
	if hasInterests {
		interestsPtr = &interests
	}
	if hasDegree {
		degreePtr = &degree
	}
	if hasX {
		xPtr = &xValue
	}
	if hasMail {
		mailPtr = &mail
	}
	if hasProjectDone {
		projectDonePtr = &projectDone
	}
	if hasHapyUser {
		hapyUserPtr = &hapyUser
	}
	if hasGreatReviews {
		greatReviewsPtr = &greatReviews
	}
	if hasSupportTeam {
		supportTeamPtr = &supportTeam
	}
	if hasSlug {
		slugPtr = &slug
	}

	var imagePtr *string
	imageFile, imageErr := c.FormFile("image")
	if imageErr == nil {
		if imageFile.Size > 5*1024*1024 {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Image size exceeds 5MB limit"})
			return
		}
		about, fetchErr := h.aboutService.GetAboutByID(id)
		if fetchErr != nil {
			c.JSON(http.StatusNotFound, gin.H{"error": fetchErr.Error()})
			return
		}
		if about.Image != "" && strings.HasPrefix(about.Image, "/uploads/") {
			oldPath := "." + about.Image
			_ = os.Remove(oldPath)
		}
		imageURL, saveErr := utils.SaveOptimizedImage(imageFile, "./uploads/about", id, &utils.ImageOptions{
			Width:   config.AppConfig.AboutImageWidth,
			Height:  config.AppConfig.AboutImageHeight,
			Quality: float32(config.AppConfig.AboutImageQuality),
			Format:  config.AppConfig.AboutImageFormat,
			Mode:    config.AppConfig.AboutImageMode,
		})
		if saveErr != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image: " + saveErr.Error()})
			return
		}
		imagePtr = &imageURL
	}

	var cvPtr *string
	cvFile, cvErr := c.FormFile("cv")
	if cvErr == nil {
		about, fetchErr := h.aboutService.GetAboutByID(id)
		if fetchErr != nil {
			c.JSON(http.StatusNotFound, gin.H{"error": fetchErr.Error()})
			return
		}
		if about.CV != "" && strings.HasPrefix(about.CV, "/uploads/") {
			oldPath := "." + about.CV
			_ = os.Remove(oldPath)
		}
		cvPath, saveErr := saveUploadedFile(c, cvFile, "./uploads/cv", "cv")
		if saveErr != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save CV: " + saveErr.Error()})
			return
		}
		cvPtr = &cvPath
	}

	about, err := h.aboutService.UpdateAbout(
		id,
		titlePtr,
		imagePtr,
		imageSubPtr,
		cvPtr,
		birthdayPtr,
		cityPtr,
		studyPtr,
		websitePtr,
		phonePtr,
		agePtr,
		interestsPtr,
		degreePtr,
		xPtr,
		mailPtr,
		done,
		projectDonePtr,
		userH,
		hapyUserPtr,
		great,
		greatReviewsPtr,
		team,
		supportTeamPtr,
		slugPtr,
		isActivePtr,
		counterActivePtr,
	)
	if err != nil {
		status := http.StatusInternalServerError
		if err.Error() == "about not found" {
			status = http.StatusNotFound
		}
		c.JSON(status, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, about)
}

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

func parseOptionalInt(c *gin.Context, key string) (*int, error) {
	value, exists := c.GetPostForm(key)
	if !exists {
		return nil, nil
	}
	value = strings.TrimSpace(value)
	if value == "" {
		return nil, nil
	}
	parsed, err := strconv.Atoi(value)
	if err != nil {
		return nil, err
	}
	return &parsed, nil
}

func saveUploadedFile(c *gin.Context, file *multipart.FileHeader, uploadDir string, prefix string) (string, error) {
	if err := os.MkdirAll(uploadDir, 0755); err != nil {
		return "", err
	}

	ext := filepath.Ext(file.Filename)
	filename := fmt.Sprintf("%s_%d%s", prefix, time.Now().UnixNano(), ext)
	fullPath := filepath.Join(uploadDir, filename)

	if err := c.SaveUploadedFile(file, fullPath); err != nil {
		return "", err
	}

	relPath := filepath.Join(uploadDir, filename)
	if strings.HasPrefix(relPath, ".") {
		relPath = relPath[1:]
	}
	if !strings.HasPrefix(relPath, "/") {
		relPath = "/" + relPath
	}

	return relPath, nil
}
