package controllers

import (
	database "ares/database/config"
	"ares/database/models"
	"errors"
	"net/http"
	"strconv"

	"github.com/gofiber/fiber/v3"
	"gorm.io/gorm"
)

// GetProducts godoc
// @Summary List products (public) with pagination
// @Tags Products
// @Produce json
// @Param page query int false "Page number"
// @Param per_page query int false "Items per page"
// @Success 200 {object} map[string]interface{}
// @Router /api/v1/products [get]
func GetProducts(c fiber.Ctx) error {
	pageStr := c.Query("page", "1")
	perPageStr := c.Query("per_page", "10")
	page, _ := strconv.Atoi(pageStr)
	perPage, _ := strconv.Atoi(perPageStr)
	if page < 1 {
		page = 1
	}
	if perPage < 1 {
		perPage = 10
	}
	if perPage > 100 {
		perPage = 100
	}
	offset := (page - 1) * perPage

	var total int64
	database.DB.Model(&models.Product{}).Count(&total)

	var products []models.Product
	database.DB.Preload("Categories").Preload("Tags").Limit(perPage).Offset(offset).Order("created_at desc").Find(&products)

	return c.JSON(fiber.Map{
		"data": products,
		"meta": fiber.Map{"page": page, "per_page": perPage, "total": total},
	})
}

// GetProduct godoc
// @Summary Get single product (public) by slug
// @Tags Products
// @Produce json
// @Param slug path string true "Product slug"
// @Success 200 {object} models.ProductDoc
// @Failure 404 {object} map[string]string
// @Router /api/v1/products/{slug} [get]
func GetProduct(c fiber.Ctx) error {
	slug := c.Params("slug")
	if slug == "" {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid slug"})
	}

	var product models.Product
	if err := database.DB.Preload("Categories").Preload("Tags").Where("slug = ? AND deleted_at IS NULL", slug).First(&product).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "product not found"})
		}
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "db error"})
	}

	return c.JSON(product)
}

// AddProductCommentRequest represents payload
type AddProductCommentRequest struct {
	ProductID uint   `json:"product_id" validate:"required"`
	Body      string `json:"body" validate:"required,min=3"`
}


func AddProductComment(c fiber.Ctx) error {
	userID, ok := c.Locals("user_id").(uint)
	if !ok || userID == 0 {
		return c.Status(http.StatusUnauthorized).JSON(fiber.Map{"error": "unauthorized"})
	}

	var input AddProductCommentRequest
	if err := c.Bind().Body(&input); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
	}

	// Add validation if needed
	if input.Body == "" {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "body is required"})
	}

	var product models.Product
	if err := database.DB.First(&product, input.ProductID).Error; err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "product not found"})
	}

	comment := models.ProductComment{
		UserID:    userID,
		ProductID: input.ProductID,
		Body:      input.Body,
	}

	if err := database.DB.Create(&comment).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "could not save comment"})
	}

	return c.Status(http.StatusCreated).JSON(comment)
}

// GetProductComments godoc
// @Summary Get comments for a product
// @Tags Products
// @Produce json
// @Param id path int true "Product ID"
// @Success 200 {array} models.ProductCommentDoc
// @Router /api/v1/products/{id}/comments [get]
func GetProductComments(c fiber.Ctx) error {
	productID, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid product id"})
	}

	var comments []models.ProductComment
	database.DB.Where("product_id = ?", productID).Order("created_at desc").Find(&comments)

	return c.JSON(comments)
}

// RecordProductCategoryView godoc
// @Summary Record a view for a product category
// @Tags Products
// @Produce json
// @Param id path int true "Category ID"
// @Success 201 {object} models.ProductCategoryViewDoc
// @Router /api/v1/product-categories/{id}/view [post]
func RecordProductCategoryView(c fiber.Ctx) error {
	categoryID, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid category id"})
	}

	var category models.ProductCategory
	if err := database.DB.First(&category, categoryID).Error; err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "category not found"})
	}

	view := models.ProductCategoryView{
		CategoryID: uint(categoryID),
		IPAddress:  c.IP(),
	}

	database.DB.Create(&view)

	return c.Status(http.StatusCreated).JSON(view)
}
