package handlers

import (
	"net/http"

	"erp-mvp/core-service/internal/api/middleware"
	"erp-mvp/core-service/internal/models"
	"erp-mvp/core-service/internal/service"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/google/uuid"
)

type OperationsHandler struct {
	operationsService service.OperationsService
	validate          *validator.Validate
}

func NewOperationsHandler(operationsService service.OperationsService) *OperationsHandler {
	return &OperationsHandler{
		operationsService: operationsService,
		validate:          validator.New(),
	}
}

// PlaceItem размещает товар в месте хранения
func (h *OperationsHandler) PlaceItem(c *gin.Context) {
	claims := middleware.GetClaims(c)
	if claims == nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
		return
	}

	var req models.PlaceItemRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	if err := h.validate.Struct(req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Validation failed", "details": err.Error()})
		return
	}

	placement, err := h.operationsService.PlaceItem(c.Request.Context(), claims.OrganizationID, &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to place item"})
		return
	}

	c.JSON(http.StatusCreated, placement)
}

// MoveItem перемещает товар в другое место хранения
func (h *OperationsHandler) MoveItem(c *gin.Context) {
	claims := middleware.GetClaims(c)
	if claims == nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
		return
	}

	placementIDStr := c.Param("id")
	placementID, err := uuid.Parse(placementIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid placement ID"})
		return
	}

	var req struct {
		NewLocationID uuid.UUID `json:"new_location_id" validate:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	if err := h.validate.Struct(req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Validation failed", "details": err.Error()})
		return
	}

	if err := h.operationsService.MoveItem(c.Request.Context(), placementID, req.NewLocationID, claims.OrganizationID); err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Placement not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Item moved successfully"})
}

// GetItemPlacements получает все размещения товара
func (h *OperationsHandler) GetItemPlacements(c *gin.Context) {
	claims := middleware.GetClaims(c)
	if claims == nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
		return
	}

	itemIDStr := c.Param("item_id")
	itemID, err := uuid.Parse(itemIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid item ID"})
		return
	}

	placements, err := h.operationsService.GetItemPlacements(c.Request.Context(), itemID, claims.OrganizationID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Item not found"})
		return
	}

	c.JSON(http.StatusOK, placements)
}

// GetLocationPlacements получает все товары в месте хранения
func (h *OperationsHandler) GetLocationPlacements(c *gin.Context) {
	claims := middleware.GetClaims(c)
	if claims == nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
		return
	}

	locationIDStr := c.Param("location_id")
	locationID, err := uuid.Parse(locationIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid location ID"})
		return
	}

	placements, err := h.operationsService.GetLocationPlacements(c.Request.Context(), locationID, claims.OrganizationID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Location not found"})
		return
	}

	c.JSON(http.StatusOK, placements)
}

// UpdateQuantity обновляет количество товара в размещении
func (h *OperationsHandler) UpdateQuantity(c *gin.Context) {
	claims := middleware.GetClaims(c)
	if claims == nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
		return
	}

	placementIDStr := c.Param("id")
	placementID, err := uuid.Parse(placementIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid placement ID"})
		return
	}

	var req struct {
		Quantity int `json:"quantity" validate:"required,min=1"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
		return
	}

	if err := h.validate.Struct(req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Validation failed", "details": err.Error()})
		return
	}

	if err := h.operationsService.UpdateQuantity(c.Request.Context(), placementID, req.Quantity, claims.OrganizationID); err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Placement not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Quantity updated successfully"})
}

// DeletePlacement удаляет размещение товара
func (h *OperationsHandler) DeletePlacement(c *gin.Context) {
	claims := middleware.GetClaims(c)
	if claims == nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
		return
	}

	placementIDStr := c.Param("id")
	placementID, err := uuid.Parse(placementIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid placement ID"})
		return
	}

	if err := h.operationsService.DeletePlacement(c.Request.Context(), placementID, claims.OrganizationID); err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Placement not found"})
		return
	}

	c.JSON(http.StatusNoContent, nil)
}

// Search выполняет поиск товаров с местами размещения
func (h *OperationsHandler) Search(c *gin.Context) {
	claims := middleware.GetClaims(c)
	if claims == nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
		return
	}

	var req models.SearchRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid query parameters"})
		return
	}

	// Устанавливаем значения по умолчанию
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 20
	}

	response, err := h.operationsService.Search(c.Request.Context(), claims.OrganizationID, &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to search"})
		return
	}

	c.JSON(http.StatusOK, response)
}
