package handlers

import (
	"fmt"
	"net/http"
	"path/filepath"
	"time"

	"github.com/disintegration/imaging"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"

	"fishfish/database"
	"fishfish/models"
)

func GetItem(c *gin.Context) {
	id := c.Param("id")

	var item models.Item

	if err := database.DB.First(&item, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Товар не найден"})
		return
	}

	if item.AvatarURL != "" {
		item.AvatarURL = fmt.Sprintf("/static/items/%s", item.AvatarURL)
	} else {
		item.AvatarURL = fmt.Sprintf("/static/items/background.jpg")
	}

	c.JSON(http.StatusOK, item)
}

func GetAllItems(c *gin.Context) {
	var items []models.Item

	if err := database.DB.Find(&items).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Не удалось загрузить данные с сервера", "message": err.Error()})
		return
	}

	for i := range items {
		if items[i].AvatarURL != "" {
			items[i].AvatarURL = fmt.Sprintf("/static/items/%s", items[i].AvatarURL)
		} else {
			items[i].AvatarURL = fmt.Sprintf("/static/items/background.jpg")
		}
	}

	c.JSON(http.StatusOK, items)
}

func UpdateItem(c *gin.Context) {
	id := c.Param("id")

	var item models.Item

	if err := database.DB.First(&item, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Товар не найден"})
		return
	}

	var input models.Item
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Неверно введеные данные"})
		return
	}

	database.DB.Model(&item).Updates(models.Item{
		Name:     input.Name,
		Unit:     input.Unit,
		UnitType: input.UnitType,
		City:     input.City,
		Price:    input.Price,
		Category: input.Category,
	})

	c.JSON(http.StatusOK, item)
}

func AddItem(c *gin.Context) {
	var item models.Item

	if err := c.ShouldBindJSON(&item); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Неверные данные"})
		return
	}

	if item.UnitType != "weight" && item.UnitType != "piece" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Товар должен быть весовым или штучным"})
		return
	}

	if err := database.DB.Create(&item).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Не удалось создать товар"})
		return
	}

	c.JSON(http.StatusCreated, item)
}

func DeleteItem(c *gin.Context) {
	id := c.Param("id")
	var item models.Item

	if err := database.DB.First(&item, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Указанный товар не найден"})
		return
	}

	database.DB.Delete(&item)

	c.JSON(http.StatusOK, gin.H{"message": "Товар успешно удален"})
}

func GetCategories(c *gin.Context) {
	var item models.Item
	categories := make([]string, 0)

	err := database.DB.Model(&item).Where("category IS NOT NULL AND category != ''").Distinct().Pluck("category", &categories).Error
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, categories)
}

func UploadItemAvatar(c *gin.Context) {
	itemID := c.Param("id")

	var item models.Item

	if err := database.DB.First(&item, itemID).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Товар не найден"})
		return
	}

	file, err := c.FormFile("avatar")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Файл не найден в запросе"})
		return
	}

	src, err := file.Open()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Не удалось открыть файл"})
	}
	defer src.Close()

	img, err := imaging.Decode(src)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Не удалось обработать фотографию"})
		return
	}

	resized := imaging.Resize(img, 1200, 0, imaging.Lanczos)
	uniqueName := uuid.New().String() + ".jpg"
	dstPath := filepath.Join("./uploads/items/", uniqueName)

	if err := imaging.Save(resized, dstPath, imaging.JPEGQuality(82)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Не удалось сохранить фотографию"})
		return
	}

	item.AvatarURL = uniqueName
	database.DB.Save(&item)

	c.JSON(http.StatusOK, gin.H{"avatar_url": item.AvatarURL})
}

func GetAdminOrder(c *gin.Context) {
	orderID := c.Param("id")

	type OrderItemDetail struct {
		ItemID   uint    `json:"item_id"`
		Name     string  `json:"name"`
		Quantity float64 `json:"quantity"`
		Price    float64 `json:"price"`
		Unit     string  `json:"unit"`
	}
	type OrderHeader struct {
		OrderID   uint      `json:"order_id"`
		Address   string    `json:"address"`
		Status    string    `json:"status"`
		CreatedAt time.Time `json:"created_at"`
	}

	type OrderDetail struct {
		OrderHeader
		Items []OrderItemDetail `json:"items"`
		Total float64           `json:"total"`
	}

	var header OrderHeader

	err := database.DB.Table("orders").
		Select("orders.id as order_id, orders.status, orders.created_at").
		Where("orders.id = ?", orderID).
		Scan(&header).Error
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	if header.OrderID == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "заказ не найден"})
		return
	}

	var items []OrderItemDetail

	err = database.DB.Table("order_items").
		Select("order_items.item_id, items.name, order_items.quantity, order_items.price, items.unit").
		Joins("JOIN items ON items.id = order_items.item_id").
		Where("order_items.order_id = ?", orderID).
		Scan(&items).Error
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	order := OrderDetail{
		OrderHeader: header,
		Items:       items,
	}

	for _, it := range items {
		order.Total += it.Price * it.Quantity
	}

	c.JSON(http.StatusOK, order)
}
