package handler

import (
	"context"
	"errors"
	"net/http"
	"strconv"
	"strings"
	"time"

	jsoniter "github.com/json-iterator/go"

	"github.com/gofrs/uuid/v5"

	"github.com/saveinmed/backend-go/internal/domain"
	"github.com/saveinmed/backend-go/internal/http/middleware"
	"github.com/saveinmed/backend-go/internal/usecase"
)

var json = jsoniter.ConfigCompatibleWithStandardLibrary

type Handler struct {
	svc *usecase.Service
}

func New(svc *usecase.Service) *Handler {
	return &Handler{svc: svc}
}

// Register godoc
// @Summary Cadastro de usuário
// @Description Cria um usuário e opcionalmente uma empresa, retornando token JWT.
// @Tags Autenticação
// @Accept json
// @Produce json
// @Param payload body registerAuthRequest true "Dados do usuário e empresa"
// @Success 201 {object} authResponse
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/auth/register [post]
func (h *Handler) Register(w http.ResponseWriter, r *http.Request) {
	var req registerAuthRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	var company *domain.Company
	if req.Company != nil {
		company = &domain.Company{
			ID:            req.Company.ID,
			Role:          req.Company.Role,
			CNPJ:          req.Company.CNPJ,
			CorporateName: req.Company.CorporateName,
			LicenseNumber: req.Company.LicenseNumber,
		}
	}

	var companyID uuid.UUID
	if req.CompanyID != nil {
		companyID = *req.CompanyID
	}

	user := &domain.User{
		CompanyID: companyID,
		Role:      req.Role,
		Name:      req.Name,
		Email:     req.Email,
	}

	if user.CompanyID == uuid.Nil && company == nil {
		writeError(w, http.StatusBadRequest, errors.New("company_id or company payload is required"))
		return
	}

	if err := h.svc.RegisterAccount(r.Context(), company, user, req.Password); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	token, exp, err := h.svc.Authenticate(r.Context(), user.Email, req.Password)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, authResponse{Token: token, ExpiresAt: exp})
}

// Login godoc
// @Summary Login
// @Description Autentica usuário e retorna token JWT.
// @Tags Autenticação
// @Accept json
// @Produce json
// @Param payload body loginRequest true "Credenciais"
// @Success 200 {object} authResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Router /api/v1/auth/login [post]
func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
	var req loginRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	token, exp, err := h.svc.Authenticate(r.Context(), req.Email, req.Password)
	if err != nil {
		writeError(w, http.StatusUnauthorized, err)
		return
	}

	writeJSON(w, http.StatusOK, authResponse{Token: token, ExpiresAt: exp})
}

// CreateCompany godoc
// @Summary Registro de empresas
// @Description Cadastra farmácia, distribuidora ou administrador com CNPJ e licença sanitária.
// @Tags Empresas
// @Accept json
// @Produce json
// @Param company body registerCompanyRequest true "Dados da empresa"
// @Success 201 {object} domain.Company
// @Router /api/companies [post]
// @Router /api/v1/companies [post]
func (h *Handler) CreateCompany(w http.ResponseWriter, r *http.Request) {
	var req registerCompanyRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	company := &domain.Company{
		Role:          req.Role,
		CNPJ:          req.CNPJ,
		CorporateName: req.CorporateName,
		LicenseNumber: req.LicenseNumber,
	}

	if err := h.svc.RegisterCompany(r.Context(), company); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, company)
}

// ListCompanies godoc
// @Summary Lista empresas
// @Tags Empresas
// @Produce json
// @Success 200 {array} domain.Company
// @Router /api/companies [get]
// @Router /api/v1/companies [get]
func (h *Handler) ListCompanies(w http.ResponseWriter, r *http.Request) {
	companies, err := h.svc.ListCompanies(r.Context())
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}
	writeJSON(w, http.StatusOK, companies)
}

// GetCompany godoc
// @Summary Obter empresa
// @Tags Empresas
// @Produce json
// @Param id path string true "Company ID"
// @Success 200 {object} domain.Company
// @Failure 404 {object} map[string]string
// @Router /api/companies/{id} [get]
// @Router /api/v1/companies/{id} [get]
func (h *Handler) GetCompany(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	company, err := h.svc.GetCompany(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	writeJSON(w, http.StatusOK, company)
}

// UpdateCompany godoc
// @Summary Atualizar empresa
// @Tags Empresas
// @Accept json
// @Produce json
// @Param id path string true "Company ID"
// @Param payload body updateCompanyRequest true "Campos para atualização"
// @Success 200 {object} domain.Company
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/companies/{id} [patch]
// @Router /api/v1/companies/{id} [patch]
func (h *Handler) UpdateCompany(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	var req updateCompanyRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	company, err := h.svc.GetCompany(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	if req.Role != nil {
		company.Role = *req.Role
	}
	if req.CNPJ != nil {
		company.CNPJ = *req.CNPJ
	}
	if req.CorporateName != nil {
		company.CorporateName = *req.CorporateName
	}
	if req.LicenseNumber != nil {
		company.LicenseNumber = *req.LicenseNumber
	}
	if req.IsVerified != nil {
		company.IsVerified = *req.IsVerified
	}

	if err := h.svc.UpdateCompany(r.Context(), company); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, company)
}

// DeleteCompany godoc
// @Summary Remover empresa
// @Tags Empresas
// @Param id path string true "Company ID"
// @Success 204 ""
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/companies/{id} [delete]
// @Router /api/v1/companies/{id} [delete]
func (h *Handler) DeleteCompany(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	if err := h.svc.DeleteCompany(r.Context(), id); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

// VerifyCompany godoc
// @Summary Verificar empresa
// @Tags Empresas
// @Security BearerAuth
// @Param id path string true "Company ID"
// @Success 200 {object} domain.Company
// @Router /api/v1/companies/{id}/verify [patch]
// VerifyCompany toggles the verification flag for a company (admin only).
func (h *Handler) VerifyCompany(w http.ResponseWriter, r *http.Request) {
	if !strings.HasSuffix(r.URL.Path, "/verify") {
		http.NotFound(w, r)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	company, err := h.svc.VerifyCompany(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, company)
}

// GetMyCompany godoc
// @Summary Obter minha empresa
// @Tags Empresas
// @Security BearerAuth
// @Produce json
// @Success 200 {object} domain.Company
// @Router /api/v1/companies/me [get]
// GetMyCompany returns the company linked to the authenticated user.
func (h *Handler) GetMyCompany(w http.ResponseWriter, r *http.Request) {
	claims, ok := middleware.GetClaims(r.Context())
	if !ok || claims.CompanyID == nil {
		writeError(w, http.StatusBadRequest, errors.New("missing company context"))
		return
	}

	company, err := h.svc.GetCompany(r.Context(), *claims.CompanyID)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	writeJSON(w, http.StatusOK, company)
}

// GetCompanyRating godoc
// @Summary Obter avaliação da empresa
// @Tags Empresas
// @Produce json
// @Param id path string true "Company ID"
// @Success 200 {object} domain.CompanyRating
// @Router /api/v1/companies/{id}/rating [get]
// GetCompanyRating exposes the average score for a company.
func (h *Handler) GetCompanyRating(w http.ResponseWriter, r *http.Request) {
	if !strings.HasSuffix(r.URL.Path, "/rating") {
		http.NotFound(w, r)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	rating, err := h.svc.GetCompanyRating(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, rating)
}

// CreateProduct godoc
// @Summary Cadastro de produto com rastreabilidade de lote
// @Tags Produtos
// @Accept json
// @Produce json
// @Param product body registerProductRequest true "Produto"
// @Success 201 {object} domain.Product
// @Router /api/products [post]
// @Router /api/v1/products [post]
func (h *Handler) CreateProduct(w http.ResponseWriter, r *http.Request) {
	var req registerProductRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	product := &domain.Product{
		SellerID:    req.SellerID,
		Name:        req.Name,
		Description: req.Description,
		Batch:       req.Batch,
		ExpiresAt:   req.ExpiresAt,
		PriceCents:  req.PriceCents,
		Stock:       req.Stock,
	}

	if err := h.svc.RegisterProduct(r.Context(), product); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, product)
}

// ListProducts godoc
// @Summary Lista catálogo com lote e validade
// @Tags Produtos
// @Produce json
// @Success 200 {array} domain.Product
// @Router /api/products [get]
// @Router /api/v1/products [get]
func (h *Handler) ListProducts(w http.ResponseWriter, r *http.Request) {
	products, err := h.svc.ListProducts(r.Context())
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}
	writeJSON(w, http.StatusOK, products)
}

// GetProduct godoc
// @Summary Obter produto
// @Tags Produtos
// @Produce json
// @Param id path string true "Product ID"
// @Success 200 {object} domain.Product
// @Failure 404 {object} map[string]string
// @Router /api/products/{id} [get]
// @Router /api/v1/products/{id} [get]
func (h *Handler) GetProduct(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	product, err := h.svc.GetProduct(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	writeJSON(w, http.StatusOK, product)
}

// UpdateProduct godoc
// @Summary Atualizar produto
// @Tags Produtos
// @Accept json
// @Produce json
// @Param id path string true "Product ID"
// @Param payload body updateProductRequest true "Campos para atualização"
// @Success 200 {object} domain.Product
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/products/{id} [patch]
// @Router /api/v1/products/{id} [patch]
func (h *Handler) UpdateProduct(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	var req updateProductRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	product, err := h.svc.GetProduct(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	if req.SellerID != nil {
		product.SellerID = *req.SellerID
	}
	if req.Name != nil {
		product.Name = *req.Name
	}
	if req.Description != nil {
		product.Description = *req.Description
	}
	if req.Batch != nil {
		product.Batch = *req.Batch
	}
	if req.ExpiresAt != nil {
		product.ExpiresAt = *req.ExpiresAt
	}
	if req.PriceCents != nil {
		product.PriceCents = *req.PriceCents
	}
	if req.Stock != nil {
		product.Stock = *req.Stock
	}

	if err := h.svc.UpdateProduct(r.Context(), product); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, product)
}

// DeleteProduct godoc
// @Summary Remover produto
// @Tags Produtos
// @Param id path string true "Product ID"
// @Success 204 ""
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/products/{id} [delete]
// @Router /api/v1/products/{id} [delete]
func (h *Handler) DeleteProduct(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	if err := h.svc.DeleteProduct(r.Context(), id); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

// ListInventory godoc
// @Summary Listar estoque
// @Tags Estoque
// @Security BearerAuth
// @Produce json
// @Param expires_in_days query int false "Dias para expiração"
// @Success 200 {array} domain.InventoryItem
// @Router /api/v1/inventory [get]
// ListInventory exposes stock with expiring batch filters.
func (h *Handler) ListInventory(w http.ResponseWriter, r *http.Request) {
	var filter domain.InventoryFilter
	if days := r.URL.Query().Get("expires_in_days"); days != "" {
		n, err := strconv.Atoi(days)
		if err != nil || n < 0 {
			writeError(w, http.StatusBadRequest, errors.New("invalid expires_in_days"))
			return
		}
		expires := time.Now().Add(time.Duration(n) * 24 * time.Hour)
		filter.ExpiringBefore = &expires
	}

	inventory, err := h.svc.ListInventory(r.Context(), filter)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, inventory)
}

// AdjustInventory godoc
// @Summary Ajustar estoque
// @Tags Estoque
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param payload body inventoryAdjustRequest true "Ajuste de estoque"
// @Success 200 {object} domain.InventoryItem
// @Failure 400 {object} map[string]string
// @Router /api/v1/inventory/adjust [post]
// AdjustInventory handles manual stock corrections.
func (h *Handler) AdjustInventory(w http.ResponseWriter, r *http.Request) {
	var req inventoryAdjustRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	if req.Delta == 0 {
		writeError(w, http.StatusBadRequest, errors.New("delta must be non-zero"))
		return
	}

	item, err := h.svc.AdjustInventory(r.Context(), req.ProductID, req.Delta, req.Reason)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	writeJSON(w, http.StatusOK, item)
}

// CreateOrder godoc
// @Summary Criação de pedido com split
// @Tags Pedidos
// @Accept json
// @Produce json
// @Param order body createOrderRequest true "Pedido"
// @Success 201 {object} domain.Order
// @Router /api/orders [post]
// @Router /api/v1/orders [post]
func (h *Handler) CreateOrder(w http.ResponseWriter, r *http.Request) {
	var req createOrderRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	order := &domain.Order{
		BuyerID:  req.BuyerID,
		SellerID: req.SellerID,
		Items:    req.Items,
		Shipping: req.Shipping,
	}

	var total int64
	for _, item := range req.Items {
		total += item.UnitCents * item.Quantity
	}
	order.TotalCents = total

	if err := h.svc.CreateOrder(r.Context(), order); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, order)
}

// ListOrders godoc
// @Summary Listar pedidos
// @Tags Pedidos
// @Security BearerAuth
// @Produce json
// @Success 200 {array} domain.Order
// @Router /api/orders [get]
// @Router /api/v1/orders [get]
func (h *Handler) ListOrders(w http.ResponseWriter, r *http.Request) {
	orders, err := h.svc.ListOrders(r.Context())
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, orders)
}

// GetOrder godoc
// @Summary Consulta pedido
// @Tags Pedidos
// @Security BearerAuth
// @Produce json
// @Param id path string true "Order ID"
// @Success 200 {object} domain.Order
// @Router /api/orders/{id} [get]
// @Router /api/v1/orders/{id} [get]
func (h *Handler) GetOrder(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	order, err := h.svc.GetOrder(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	writeJSON(w, http.StatusOK, order)
}

// UpdateOrderStatus godoc
// @Summary Atualiza status do pedido
// @Tags Pedidos
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param id path string true "Order ID"
// @Param status body updateStatusRequest true "Novo status"
// @Success 204 ""
// @Router /api/orders/{id}/status [patch]
// @Router /api/v1/orders/{id}/status [patch]
func (h *Handler) UpdateOrderStatus(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	var req updateStatusRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	if !isValidStatus(req.Status) {
		writeError(w, http.StatusBadRequest, errors.New("invalid status"))
		return
	}

	if err := h.svc.UpdateOrderStatus(r.Context(), id, domain.OrderStatus(req.Status)); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

// DeleteOrder godoc
// @Summary Remover pedido
// @Tags Pedidos
// @Security BearerAuth
// @Param id path string true "Order ID"
// @Success 204 ""
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/orders/{id} [delete]
// @Router /api/v1/orders/{id} [delete]
func (h *Handler) DeleteOrder(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	if err := h.svc.DeleteOrder(r.Context(), id); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

// CreateReview godoc
// @Summary Criar avaliação
// @Tags Avaliações
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param payload body createReviewRequest true "Dados da avaliação"
// @Success 201 {object} domain.Review
// @Failure 400 {object} map[string]string
// @Router /api/v1/reviews [post]
// CreateReview allows buyers to rate the seller after delivery.
func (h *Handler) CreateReview(w http.ResponseWriter, r *http.Request) {
	claims, ok := middleware.GetClaims(r.Context())
	if !ok || claims.CompanyID == nil {
		writeError(w, http.StatusBadRequest, errors.New("missing buyer context"))
		return
	}

	var req createReviewRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	review, err := h.svc.CreateReview(r.Context(), *claims.CompanyID, req.OrderID, req.Rating, req.Comment)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	writeJSON(w, http.StatusCreated, review)
}

// AddToCart godoc
// @Summary Adicionar item ao carrinho
// @Tags Carrinho
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param payload body addCartItemRequest true "Item do carrinho"
// @Success 201 {object} domain.CartSummary
// @Failure 400 {object} map[string]string
// @Router /api/v1/cart [post]
// AddToCart appends an item to the authenticated buyer cart respecting stock.
func (h *Handler) AddToCart(w http.ResponseWriter, r *http.Request) {
	claims, ok := middleware.GetClaims(r.Context())
	if !ok || claims.CompanyID == nil {
		writeError(w, http.StatusBadRequest, errors.New("missing buyer context"))
		return
	}

	var req addCartItemRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	summary, err := h.svc.AddItemToCart(r.Context(), *claims.CompanyID, req.ProductID, req.Quantity)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	writeJSON(w, http.StatusCreated, summary)
}

// GetCart godoc
// @Summary Obter carrinho
// @Tags Carrinho
// @Security BearerAuth
// @Produce json
// @Success 200 {object} domain.CartSummary
// @Router /api/v1/cart [get]
// GetCart returns cart contents and totals for the authenticated buyer.
func (h *Handler) GetCart(w http.ResponseWriter, r *http.Request) {
	claims, ok := middleware.GetClaims(r.Context())
	if !ok || claims.CompanyID == nil {
		writeError(w, http.StatusBadRequest, errors.New("missing buyer context"))
		return
	}

	summary, err := h.svc.ListCart(r.Context(), *claims.CompanyID)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}
	writeJSON(w, http.StatusOK, summary)
}

// DeleteCartItem godoc
// @Summary Remover item do carrinho
// @Tags Carrinho
// @Security BearerAuth
// @Param id path string true "Cart item ID"
// @Success 200 {object} domain.CartSummary
// @Failure 400 {object} map[string]string
// @Router /api/v1/cart/{id} [delete]
// DeleteCartItem removes a product from the cart and returns the updated totals.
func (h *Handler) DeleteCartItem(w http.ResponseWriter, r *http.Request) {
	claims, ok := middleware.GetClaims(r.Context())
	if !ok || claims.CompanyID == nil {
		writeError(w, http.StatusBadRequest, errors.New("missing buyer context"))
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	summary, err := h.svc.RemoveCartItem(r.Context(), *claims.CompanyID, id)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	writeJSON(w, http.StatusOK, summary)
}

// CreatePaymentPreference godoc
// @Summary Cria preferência de pagamento Mercado Pago com split nativo
// @Tags Pagamentos
// @Security BearerAuth
// @Produce json
// @Param id path string true "Order ID"
// @Success 201 {object} domain.PaymentPreference
// @Router /api/orders/{id}/payment [post]
// @Router /api/v1/orders/{id}/payment [post]
func (h *Handler) CreatePaymentPreference(w http.ResponseWriter, r *http.Request) {
	if !strings.HasSuffix(r.URL.Path, "/payment") {
		http.NotFound(w, r)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	pref, err := h.svc.CreatePaymentPreference(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, pref)
}

// CreateShipment godoc
// @Summary Gera guia de postagem/transporte
// @Tags Logistica
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param shipment body createShipmentRequest true "Dados de envio"
// @Success 201 {object} domain.Shipment
// @Router /api/v1/shipments [post]
func (h *Handler) CreateShipment(w http.ResponseWriter, r *http.Request) {
	var req createShipmentRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	shipment := &domain.Shipment{
		OrderID:          req.OrderID,
		Carrier:          req.Carrier,
		TrackingCode:     req.TrackingCode,
		ExternalTracking: req.ExternalTracking,
	}

	if err := h.svc.CreateShipment(r.Context(), shipment); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, shipment)
}

// GetShipmentByOrderID godoc
// @Summary Rastreia entrega
// @Tags Logistica
// @Security BearerAuth
// @Produce json
// @Param order_id path string true "Order ID"
// @Success 200 {object} domain.Shipment
// @Router /api/v1/shipments/{order_id} [get]
func (h *Handler) GetShipmentByOrderID(w http.ResponseWriter, r *http.Request) {
	orderID, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	shipment, err := h.svc.GetShipmentByOrderID(r.Context(), orderID)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	writeJSON(w, http.StatusOK, shipment)
}

// HandlePaymentWebhook godoc
// @Summary Recebe notificações do Mercado Pago
// @Tags Pagamentos
// @Accept json
// @Produce json
// @Param notification body domain.PaymentWebhookEvent true "Evento do gateway"
// @Success 200 {object} domain.PaymentSplitResult
// @Router /api/v1/payments/webhook [post]
func (h *Handler) HandlePaymentWebhook(w http.ResponseWriter, r *http.Request) {
	var event domain.PaymentWebhookEvent
	if err := decodeJSON(r.Context(), r, &event); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	summary, err := h.svc.HandlePaymentWebhook(r.Context(), event)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, summary)
}

// GetSellerDashboard aggregates KPIs for the authenticated seller or the requested company.
// @Summary Dashboard do vendedor
// @Tags Dashboard
// @Security BearerAuth
// @Produce json
// @Param seller_id query string false "Seller ID"
// @Success 200 {object} domain.SellerDashboard
// @Router /api/v1/dashboard/seller [get]
func (h *Handler) GetSellerDashboard(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	sellerID := requester.CompanyID
	if sid := r.URL.Query().Get("seller_id"); sid != "" {
		id, err := uuid.FromString(sid)
		if err != nil {
			writeError(w, http.StatusBadRequest, errors.New("invalid seller_id"))
			return
		}
		sellerID = &id
	}

	if sellerID == nil {
		writeError(w, http.StatusBadRequest, errors.New("seller context is required"))
		return
	}

	if !strings.EqualFold(requester.Role, "Admin") && requester.CompanyID != nil && *sellerID != *requester.CompanyID {
		writeError(w, http.StatusForbidden, errors.New("not allowed to view other sellers"))
		return
	}

	dashboard, err := h.svc.GetSellerDashboard(r.Context(), *sellerID)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, dashboard)
}

// GetAdminDashboard exposes platform-wide aggregated metrics.
// @Summary Dashboard do administrador
// @Tags Dashboard
// @Security BearerAuth
// @Produce json
// @Success 200 {object} domain.AdminDashboard
// @Router /api/v1/dashboard/admin [get]
func (h *Handler) GetAdminDashboard(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	if !strings.EqualFold(requester.Role, "Admin") {
		writeError(w, http.StatusForbidden, errors.New("admin role required"))
		return
	}

	dashboard, err := h.svc.GetAdminDashboard(r.Context())
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, dashboard)
}

// CreateUser godoc
// @Summary Criar usuário
// @Tags Usuários
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param payload body createUserRequest true "Novo usuário"
// @Success 201 {object} domain.User
// @Failure 400 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/users [post]
func (h *Handler) CreateUser(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	var req createUserRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil {
			writeError(w, http.StatusBadRequest, errors.New("seller must include X-Company-ID header"))
			return
		}
		if req.CompanyID != *requester.CompanyID {
			writeError(w, http.StatusForbidden, errors.New("seller can only manage their own company users"))
			return
		}
	}

	user := &domain.User{
		CompanyID: req.CompanyID,
		Role:      req.Role,
		Name:      req.Name,
		Email:     req.Email,
	}

	if err := h.svc.CreateUser(r.Context(), user, req.Password); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, user)
}

// ListUsers godoc
// @Summary Listar usuários
// @Tags Usuários
// @Security BearerAuth
// @Produce json
// @Param page query int false "Página"
// @Param page_size query int false "Tamanho da página"
// @Param company_id query string false "Filtro por empresa"
// @Success 200 {object} domain.UserPage
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/users [get]
func (h *Handler) ListUsers(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	page, pageSize := parsePagination(r)

	var companyFilter *uuid.UUID
	if cid := r.URL.Query().Get("company_id"); cid != "" {
		id, err := uuid.FromString(cid)
		if err != nil {
			writeError(w, http.StatusBadRequest, errors.New("invalid company_id"))
			return
		}
		companyFilter = &id
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil {
			writeError(w, http.StatusBadRequest, errors.New("seller must include X-Company-ID header"))
			return
		}
		companyFilter = requester.CompanyID
	}

	pageResult, err := h.svc.ListUsers(r.Context(), domain.UserFilter{CompanyID: companyFilter}, page, pageSize)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, pageResult)
}

// GetUser godoc
// @Summary Obter usuário
// @Tags Usuários
// @Security BearerAuth
// @Produce json
// @Param id path string true "User ID"
// @Success 200 {object} domain.User
// @Failure 400 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /api/v1/users/{id} [get]
func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	user, err := h.svc.GetUser(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil || user.CompanyID != *requester.CompanyID {
			writeError(w, http.StatusForbidden, errors.New("seller can only view users from their company"))
			return
		}
	}

	writeJSON(w, http.StatusOK, user)
}

// UpdateUser godoc
// @Summary Atualizar usuário
// @Tags Usuários
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param id path string true "User ID"
// @Param payload body updateUserRequest true "Campos para atualização"
// @Success 200 {object} domain.User
// @Failure 400 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/users/{id} [put]
func (h *Handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	var req updateUserRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	user, err := h.svc.GetUser(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil || user.CompanyID != *requester.CompanyID {
			writeError(w, http.StatusForbidden, errors.New("seller can only update their company users"))
			return
		}
	}

	if req.CompanyID != nil {
		user.CompanyID = *req.CompanyID
	}
	if req.Role != nil {
		user.Role = *req.Role
	}
	if req.Name != nil {
		user.Name = *req.Name
	}
	if req.Email != nil {
		user.Email = *req.Email
	}

	newPassword := ""
	if req.Password != nil {
		newPassword = *req.Password
	}

	if err := h.svc.UpdateUser(r.Context(), user, newPassword); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, user)
}

// DeleteUser godoc
// @Summary Excluir usuário
// @Tags Usuários
// @Security BearerAuth
// @Param id path string true "User ID"
// @Success 204 {string} string "No Content"
// @Failure 400 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/users/{id} [delete]
func (h *Handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
	requester, err := getRequester(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	user, err := h.svc.GetUser(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	if strings.EqualFold(requester.Role, "Seller") {
		if requester.CompanyID == nil || user.CompanyID != *requester.CompanyID {
			writeError(w, http.StatusForbidden, errors.New("seller can only delete their company users"))
			return
		}
	}

	if err := h.svc.DeleteUser(r.Context(), id); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

type createUserRequest struct {
	CompanyID uuid.UUID `json:"company_id"`
	Role      string    `json:"role"`
	Name      string    `json:"name"`
	Email     string    `json:"email"`
	Password  string    `json:"password"`
}

type registerAuthRequest struct {
	CompanyID *uuid.UUID             `json:"company_id,omitempty"`
	Company   *registerCompanyTarget `json:"company,omitempty"`
	Role      string                 `json:"role"`
	Name      string                 `json:"name"`
	Email     string                 `json:"email"`
	Password  string                 `json:"password"`
}

type registerCompanyTarget struct {
	ID            uuid.UUID `json:"id,omitempty"`
	Role          string    `json:"role"`
	CNPJ          string    `json:"cnpj"`
	CorporateName string    `json:"corporate_name"`
	LicenseNumber string    `json:"license_number"`
}

type loginRequest struct {
	Email    string `json:"email"`
	Password string `json:"password"`
}

type authResponse struct {
	Token     string    `json:"token"`
	ExpiresAt time.Time `json:"expires_at"`
}

type inventoryAdjustRequest struct {
	ProductID uuid.UUID `json:"product_id"`
	Delta     int64     `json:"delta"`
	Reason    string    `json:"reason"`
}

type addCartItemRequest struct {
	ProductID uuid.UUID `json:"product_id"`
	Quantity  int64     `json:"quantity"`
}

type createReviewRequest struct {
	OrderID uuid.UUID `json:"order_id"`
	Rating  int       `json:"rating"`
	Comment string    `json:"comment"`
}

type updateUserRequest struct {
	CompanyID *uuid.UUID `json:"company_id,omitempty"`
	Role      *string    `json:"role,omitempty"`
	Name      *string    `json:"name,omitempty"`
	Email     *string    `json:"email,omitempty"`
	Password  *string    `json:"password,omitempty"`
}

type requester struct {
	Role      string
	CompanyID *uuid.UUID
}

func parsePagination(r *http.Request) (int, int) {
	page := 1
	pageSize := 20

	if v := r.URL.Query().Get("page"); v != "" {
		if p, err := strconv.Atoi(v); err == nil && p > 0 {
			page = p
		}
	}

	if v := r.URL.Query().Get("page_size"); v != "" {
		if ps, err := strconv.Atoi(v); err == nil && ps > 0 {
			pageSize = ps
		}
	}

	return page, pageSize
}

func getRequester(r *http.Request) (requester, error) {
	if claims, ok := middleware.GetClaims(r.Context()); ok {
		return requester{Role: claims.Role, CompanyID: claims.CompanyID}, nil
	}
	role := r.Header.Get("X-User-Role")
	if role == "" {
		role = "Admin"
	}

	var companyID *uuid.UUID
	if cid := r.Header.Get("X-Company-ID"); cid != "" {
		id, err := uuid.FromString(cid)
		if err != nil {
			return requester{}, errors.New("invalid X-Company-ID header")
		}
		companyID = &id
	}

	return requester{Role: role, CompanyID: companyID}, nil
}

type registerCompanyRequest struct {
	Role          string `json:"role"`
	CNPJ          string `json:"cnpj"`
	CorporateName string `json:"corporate_name"`
	LicenseNumber string `json:"license_number"`
}

type updateCompanyRequest struct {
	Role          *string `json:"role,omitempty"`
	CNPJ          *string `json:"cnpj,omitempty"`
	CorporateName *string `json:"corporate_name,omitempty"`
	LicenseNumber *string `json:"license_number,omitempty"`
	IsVerified    *bool   `json:"is_verified,omitempty"`
}

type registerProductRequest struct {
	SellerID    uuid.UUID `json:"seller_id"`
	Name        string    `json:"name"`
	Description string    `json:"description"`
	Batch       string    `json:"batch"`
	ExpiresAt   time.Time `json:"expires_at"`
	PriceCents  int64     `json:"price_cents"`
	Stock       int64     `json:"stock"`
}

type updateProductRequest struct {
	SellerID    *uuid.UUID `json:"seller_id,omitempty"`
	Name        *string    `json:"name,omitempty"`
	Description *string    `json:"description,omitempty"`
	Batch       *string    `json:"batch,omitempty"`
	ExpiresAt   *time.Time `json:"expires_at,omitempty"`
	PriceCents  *int64     `json:"price_cents,omitempty"`
	Stock       *int64     `json:"stock,omitempty"`
}

type createOrderRequest struct {
	BuyerID  uuid.UUID              `json:"buyer_id"`
	SellerID uuid.UUID              `json:"seller_id"`
	Items    []domain.OrderItem     `json:"items"`
	Shipping domain.ShippingAddress `json:"shipping"`
}

type createShipmentRequest struct {
	OrderID          uuid.UUID `json:"order_id"`
	Carrier          string    `json:"carrier"`
	TrackingCode     string    `json:"tracking_code"`
	ExternalTracking string    `json:"external_tracking"`
}

type updateStatusRequest struct {
	Status string `json:"status"`
}

func writeJSON(w http.ResponseWriter, status int, v any) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	_ = json.NewEncoder(w).Encode(v)
}

func writeError(w http.ResponseWriter, status int, err error) {
	writeJSON(w, status, map[string]string{"error": err.Error()})
}

func decodeJSON(ctx context.Context, r *http.Request, v any) error {
	ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
	defer cancel()

	dec := json.NewDecoder(r.Body)
	dec.DisallowUnknownFields()
	if err := dec.Decode(v); err != nil {
		return err
	}
	return ctx.Err()
}

func parseUUIDFromPath(path string) (uuid.UUID, error) {
	parts := splitPath(path)
	for i := len(parts) - 1; i >= 0; i-- {
		if id, err := uuid.FromString(parts[i]); err == nil {
			return id, nil
		}
	}
	return uuid.UUID{}, errors.New("missing resource id")
}

func splitPath(p string) []string {
	var parts []string
	start := 0
	for i := 0; i < len(p); i++ {
		if p[i] == '/' {
			if i > start {
				parts = append(parts, p[start:i])
			}
			start = i + 1
		}
	}
	if start < len(p) {
		parts = append(parts, p[start:])
	}
	return parts
}

func isValidStatus(status string) bool {
	switch domain.OrderStatus(status) {
	case domain.OrderStatusPending, domain.OrderStatusPaid, domain.OrderStatusInvoiced, domain.OrderStatusDelivered:
		return true
	default:
		return false
	}
}
