package handlers

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"

	"fishfish/database"
	"fishfish/models"
)

func CreateOrder(c *gin.Context) {
	userID := getUserID(c)

	var req struct {
		DeliveryAddress string `json:"delivery_address" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Не указан адрес доставки"})
		return
	}

	var cartItems []models.CartItem
	if err := database.DB.Preload("Item").Where("user_id = ? ", userID).Find(&cartItems).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Не удалось получить корзину"})
		return
	}

	if len(cartItems) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Корзина пуста"})
		return
	}

	var order models.Order
	err := database.DB.Transaction(func(tx *gorm.DB) error {
		var total float64
		var orderItems []models.OrderItem

		for _, cartItem := range cartItems {
			item := cartItem.Item

			result := tx.Model(&models.Item{}).Where("id = ? AND stock >= ?", item.ID, cartItem.Quantity).Update("stock", gorm.Expr("stock - ? ", cartItem.Quantity))

			if result.RowsAffected == 0 {
				return fmt.Errorf("недостаточно товара '%s' на складе", item.Name)
			}

			itemTotal := float64(item.Price) * cartItem.Quantity
			total += itemTotal

			orderItems = append(orderItems, models.OrderItem{
				ItemID:   cartItem.ItemID,
				Quantity: cartItem.Quantity,
				Price:    float64(item.Price),
			})
		}

		order = models.Order{
			UserID:          userID,
			Status:          "new",
			DeliveryAddress: req.DeliveryAddress,
			TotalPrice:      total,
			Items:           orderItems,
		}

		if err := tx.Create(&order).Error; err != nil {
			return err
		}

		for _, oi := range order.Items {
			movement := models.StockMovement{
				ItemID:   oi.ItemID,
				Type:     "out",
				Quantity: oi.Quantity,
				Reason:   "order",
				OrderID:  &order.ID,
			}

			if err := tx.Omit("Item").Create(&movement).Error; err != nil {
				return err
			}
		}

		if err := tx.Where("user_id = ? ", userID).Delete(&models.CartItem{}).Error; err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, order)
}

func GetUserOrders(c *gin.Context) {
	userID := getUserID(c)

	var orders []models.Order
	if err := database.DB.Preload("Items.Item").Where("user_id = ? ", userID).Find(&orders).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Не удалось вывести заказы"})
		return
	}

	c.JSON(http.StatusOK, orders)
}

func GetOrder(c *gin.Context) {
	userID := getUserID(c)

	orderID := c.Param("id")

	var order models.Order

	if err := database.DB.Preload("Items.Item").Where("id = ? AND user_id = ? ", orderID, userID).First(&order).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Заказ не найден"})
		return
	}

	c.JSON(http.StatusOK, order)
}

func GetAllOrders(c *gin.Context) {
	var orders []models.Order

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

	c.JSON(http.StatusOK, orders)
}

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

	var req struct {
		Status string `json:"status" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Не указан статус заказа"})
		return
	}

	if req.Status != "new" && req.Status != "packed" && req.Status != "delivered" && req.Status != "cancel" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Неверно указанный статус заказа"})
		return
	}

	result := database.DB.Model(&models.Order{}).Where("id = ? ", orderID).Update("status", req.Status)
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Ошибка при изменении статуса заказа"})
		return
	}

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

	c.JSON(http.StatusAccepted, "Статус заказа успешно изменен")
}
