package api

import (
	"log"
	"net/http"
	"rrbec_server/internal/models"
	"rrbec_server/internal/repository"
	"rrbec_server/internal/service"
	"strconv"
	"time"

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

type Handler struct {
	svc    *service.Service
	syncer interface{ SyncProductsOnly() }
}

func NewHandler(svc *service.Service) *Handler {
	return &Handler{svc: svc}
}

func (h *Handler) SetSyncer(syncer interface{ SyncProductsOnly() }) {
	h.syncer = syncer
}

func parsePagination(c *gin.Context) *repository.PaginationParams {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50"))
	sort := c.DefaultQuery("sort", "id ASC")

	params := &repository.PaginationParams{
		Page:    page,
		Limit:   limit,
		Sort:    sort,
		Filters: make(map[string]interface{}),
	}

	if name := c.Query("name"); name != "" {
		params.Filters["name"] = name
	}
	if active := c.Query("active"); active != "" {
		if b, err := strconv.ParseBool(active); err == nil {
			params.Filters["active"] = b
		}
	}
	if status := c.Query("status"); status != "" {
		params.Filters["status"] = status
	}
	if category := c.Query("category"); category != "" {
		if c, err := strconv.ParseUint(category, 10, 64); err == nil {
			params.Filters["category"] = uint(c)
		}
	}
	if cuisine := c.Query("cuisine"); cuisine != "" {
		if b, err := strconv.ParseBool(cuisine); err == nil {
			params.Filters["cuisine"] = b
		}
	}
	if dateFrom := c.Query("date_from"); dateFrom != "" {
		if t, err := time.Parse("2006-01-02", dateFrom); err == nil {
			params.Filters["date_from"] = t
		}
	}
	if dateTo := c.Query("date_to"); dateTo != "" {
		if t, err := time.Parse("2006-01-02", dateTo); err == nil {
			params.Filters["date_to"] = t
		}
	}
	if comandaID := c.Query("comanda_id"); comandaID != "" {
		if c, err := strconv.ParseUint(comandaID, 10, 64); err == nil {
			params.Filters["comanda_id"] = uint(c)
		}
	}
	if canceled := c.Query("canceled"); canceled != "" {
		if b, err := strconv.ParseBool(canceled); err == nil {
			params.Filters["canceled"] = b
		}
	}
	if delivered := c.Query("delivered"); delivered != "" {
		if b, err := strconv.ParseBool(delivered); err == nil {
			params.Filters["delivered"] = b
		}
	}

	return params
}

func (h *Handler) GetProducts(c *gin.Context) {
	params := parsePagination(c)
	result, err := h.svc.GetProducts(params)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

func (h *Handler) CreateProduct(c *gin.Context) {
	var product models.Product
	if err := c.ShouldBindJSON(&product); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := h.svc.CreateProduct(&product); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"message": "Product created successfully", "product": product})
}

func (h *Handler) UpdateProduct(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	var updates map[string]interface{}
	if err := c.ShouldBindJSON(&updates); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := h.svc.UpdateProduct(uint(id), updates); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

func (h *Handler) GetMesas(c *gin.Context) {
	params := parsePagination(c)
	result, err := h.svc.GetMesas(params)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

func (h *Handler) GetCategories(c *gin.Context) {
	params := parsePagination(c)
	result, err := h.svc.GetCategories(params)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

func (h *Handler) CreateCategory(c *gin.Context) {
	var cat models.Category
	if err := c.ShouldBindJSON(&cat); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := h.svc.CreateCategory(&cat); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, cat)
}

func (h *Handler) UpdateCategory(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	var updates map[string]interface{}
	if err := c.ShouldBindJSON(&updates); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := h.svc.UpdateCategory(uint(id), updates); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

func (h *Handler) GetTypePayments(c *gin.Context) {
	params := parsePagination(c)
	result, err := h.svc.GetTypePayments(params)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

func (h *Handler) GetClients(c *gin.Context) {
	params := parsePagination(c)
	result, err := h.svc.GetClients(params)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

func (h *Handler) GetOrders(c *gin.Context) {
	params := parsePagination(c)
	result, err := h.svc.GetOrders(params)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

func (h *Handler) CreateOrder(c *gin.Context) {
	var order models.Order
	if err := c.ShouldBindJSON(&order); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := h.svc.CreateOrder(&order); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, order)
}

func (h *Handler) UpdateOrder(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	var updates map[string]interface{}
	if err := c.ShouldBindJSON(&updates); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := h.svc.UpdateOrder(uint(id), updates); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

func (h *Handler) SetOrderPreparing(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	if err := h.svc.SetOrderPreparing(uint(id)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Order is now preparing"})
}

func (h *Handler) SetOrderFinished(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	if err := h.svc.SetOrderFinished(uint(id)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Order finished"})
}

func (h *Handler) SetOrderDelivered(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	if err := h.svc.SetOrderDelivered(uint(id)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Order delivered"})
}

func (h *Handler) SetOrderCanceled(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	if err := h.svc.SetOrderCanceled(uint(id)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"message": "Order canceled"})
}

func (h *Handler) GetPayments(c *gin.Context) {
	params := parsePagination(c)
	if c.Query("sort") == "" {
		params.Sort = "id DESC"
	}
	result, err := h.svc.GetPayments(params)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

func (h *Handler) CreateComanda(c *gin.Context) {
	var comanda models.Comanda
	if err := c.ShouldBindJSON(&comanda); err != nil {
		log.Printf("DEBUG: CreateComanda bind error: %v", err)
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	log.Printf("DEBUG: CreateComanda received: MesaID=%d, UserID=%d, ClientID=%v", comanda.MesaID, comanda.UserID, comanda.ClientID)

	if comanda.MesaID == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Mesa ID is required for sync consistency"})
		return
	}

	if err := h.svc.CreateComanda(&comanda); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusCreated, comanda)
}

func (h *Handler) AddItemToComanda(c *gin.Context) {
	var item models.ProductComanda
	if err := c.ShouldBindJSON(&item); err != nil {
		log.Printf("DEBUG: AddItem bind error: %v", err)
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	log.Printf("DEBUG: AddItem received: ComandaID=%d, ProductID=%d", item.ComandaID, item.ProductID)

	if item.ComandaID == 0 || item.ProductID == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "ComandaID and ProductID are required for sync"})
		return
	}

	if err := h.svc.AddItemToComandaRaw(&item); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusCreated, item)
}

func (h *Handler) DeleteItemFromComanda(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	if err := h.svc.DeleteItem(uint(id)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

func (h *Handler) ClearComanda(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	if err := h.svc.ClearComanda(uint(id)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Comanda cleared and closed"})
}

func (h *Handler) UpdateComanda(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	var updates map[string]interface{}
	if err := c.ShouldBindJSON(&updates); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := h.svc.UpdateComanda(uint(id), updates); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

func (h *Handler) PagarComanda(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	var rawData map[string]interface{}
	if err := c.ShouldBindJSON(&rawData); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	log.Printf("DEBUG: PagarComanda RAW JSON: %v", rawData)

	var payment models.Payment
	if v, ok := rawData["value"].(float64); ok {
		payment.Value = models.Price(v)
	}
	if v, ok := rawData["type_pay"].(float64); ok {
		payment.TypePayID = uint(v)
	} else if v, ok := rawData["id_type_pay"].(float64); ok {
		payment.TypePayID = uint(v)
	}
	if v, ok := rawData["client"].(float64); ok {
		clientId := uint(v)
		payment.ClientID = &clientId
	} else if v, ok := rawData["client_id"].(float64); ok {
		clientId := uint(v)
		payment.ClientID = &clientId
	}
	if v, ok := rawData["description"].(string); ok {
		payment.Description = v
	}

	status := "CLOSED"
	if v, ok := rawData["status"].(string); ok {
		status = v
	}

	if err := h.svc.PagarComanda(uint(id), &payment, status); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Payment registered and comanda updated to " + status})
}

func (h *Handler) GetComandas(c *gin.Context) {
	params := parsePagination(c)
	if c.Query("sort") == "" {
		params.Sort = "id DESC"
	}
	result, err := h.svc.GetComandas(params)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

func (h *Handler) GetComandaByID(c *gin.Context) {
	idStr := c.Param("id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id format"})
		return
	}

	comanda, err := h.svc.GetComandaByID(uint(id))
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "comanda not found"})
		return
	}
	c.JSON(http.StatusOK, comanda)
}

func (h *Handler) Login(c *gin.Context) {
	var input struct {
		Username string `json:"username" binding:"required"`
		Password string `json:"password" binding:"required"`
	}

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

	user, err := h.svc.Login(input.Username, input.Password)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "Login successful",
		"user":    user,
	})
}

func (h *Handler) GetCurrentUser(c *gin.Context) {
	userID, exists := c.Get("userID")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"user_id": userID})
}

func (h *Handler) ResyncProducts(c *gin.Context) {
	if h.syncer == nil {
		c.JSON(http.StatusServiceUnavailable, gin.H{"error": "syncer not configured"})
		return
	}
	go h.syncer.SyncProductsOnly()
	c.JSON(http.StatusOK, gin.H{"message": "Product resync started in background"})
}
