package handlers

import (
	"math"
	"net/http"
	"strconv"

	"sale/internal/models"
	"sale/internal/schemas"
	"sale/internal/utils"

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

type ArticleHandler struct{}

func NewArticleHandler() *ArticleHandler {
	return &ArticleHandler{}
}

func (h *ArticleHandler) List(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))

	var total int64
	utils.DB.Model(&models.Article{}).Where("is_published = ?", true).Count(&total)

	var articles []models.Article
	offset := (page - 1) * pageSize
	utils.DB.Where("is_published = ?", true).
		Order("is_pinned DESC, sort_order ASC, created_at DESC").
		Offset(offset).Limit(pageSize).Find(&articles)

	totalPages := int(math.Ceil(float64(total) / float64(pageSize)))
	c.JSON(http.StatusOK, gin.H{
		"data": articles,
		"pagination": gin.H{
			"page":       page,
			"page_size":  pageSize,
			"total":      total,
			"total_pages": totalPages,
		},
	})
}

func (h *ArticleHandler) GetByID(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	var article models.Article
	if err := utils.DB.Preload("Author").First(&article, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Article not found"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"data": article})
}

func (h *ArticleHandler) AdminList(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))

	var total int64
	utils.DB.Model(&models.Article{}).Count(&total)

	var articles []models.Article
	offset := (page - 1) * pageSize
	utils.DB.Preload("Author").
		Order("is_pinned DESC, sort_order ASC, created_at DESC").
		Offset(offset).Limit(pageSize).Find(&articles)

	totalPages := int(math.Ceil(float64(total) / float64(pageSize)))
	c.JSON(http.StatusOK, gin.H{
		"data": articles,
		"pagination": gin.H{
			"page":       page,
			"page_size":  pageSize,
			"total":      total,
			"total_pages": totalPages,
		},
	})
}

func (h *ArticleHandler) Create(c *gin.Context) {
	userID := c.GetUint("user_id")
	var req schemas.CreateArticleRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	article := models.Article{
		Title:       req.Title,
		Content:     req.Content,
		Summary:     req.Summary,
		CoverImage:  req.CoverImage,
		IsPinned:    req.IsPinned,
		IsPublished: req.IsPublished,
		SortOrder:   req.SortOrder,
		AuthorID:    &userID,
	}

	utils.DB.Create(&article)
	c.JSON(http.StatusCreated, gin.H{"data": article})
}

func (h *ArticleHandler) Update(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	var article models.Article
	if err := utils.DB.First(&article, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Article not found"})
		return
	}

	var req schemas.UpdateArticleRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	updates := make(map[string]interface{})
	if req.Title != nil {
		updates["title"] = *req.Title
	}
	if req.Content != nil {
		updates["content"] = *req.Content
	}
	if req.Summary != nil {
		updates["summary"] = *req.Summary
	}
	if req.CoverImage != nil {
		updates["cover_image"] = *req.CoverImage
	}
	if req.IsPinned != nil {
		updates["is_pinned"] = *req.IsPinned
	}
	if req.IsPublished != nil {
		updates["is_published"] = *req.IsPublished
	}
	if req.SortOrder != nil {
		updates["sort_order"] = *req.SortOrder
	}

	utils.DB.Model(&article).Updates(updates)
	c.JSON(http.StatusOK, gin.H{"data": article})
}

func (h *ArticleHandler) Delete(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	if err := utils.DB.Delete(&models.Article{}, id).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete article"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Article deleted successfully"})
}

func (h *ArticleHandler) TogglePin(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	var article models.Article
	if err := utils.DB.First(&article, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Article not found"})
		return
	}

	utils.DB.Model(&article).Update("is_pinned", !article.IsPinned)
	utils.DB.First(&article, id)
	c.JSON(http.StatusOK, gin.H{"data": article})
}
