package usecase

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/gofrs/uuid/v5"

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

// AddItemToCart validates stock, applies the buyer fee and persists the cart item,
// then returns the refreshed cart summary.
func (s *Service) AddItemToCart(ctx context.Context, buyerID, productID uuid.UUID, quantity int64) (*domain.CartSummary, error) {
	if quantity <= 0 {
		return nil, errors.New("quantity must be greater than zero")
	}

	product, err := s.repo.GetProduct(ctx, productID)
	if err != nil {
		return nil, err
	}

	unitPrice := product.PriceCents
	if s.buyerFeeRate > 0 {
		unitPrice = int64(float64(unitPrice) * (1 + s.buyerFeeRate))
	}

	_, err = s.repo.AddCartItem(ctx, &domain.CartItem{
		ID:        uuid.Must(uuid.NewV7()),
		BuyerID:   buyerID,
		ProductID: productID,
		Quantity:  quantity,
		UnitCents: unitPrice,
	})
	if err != nil {
		return nil, err
	}

	return s.cartSummary(ctx, buyerID)
}

// ReplaceCart atomically replaces all cart items for a buyer with a new set.
func (s *Service) ReplaceCart(ctx context.Context, buyerID uuid.UUID, reqItems []domain.CartItem) (*domain.CartSummary, error) {
	var validItems []domain.CartItem

	for _, item := range reqItems {
		product, err := s.repo.GetProduct(ctx, item.ProductID)
		if err != nil {
			continue // Skip unavailable products silently
		}

		unitPrice := product.PriceCents
		if s.buyerFeeRate > 0 {
			unitPrice = int64(float64(unitPrice) * (1 + s.buyerFeeRate))
		}

		validItems = append(validItems, domain.CartItem{
			ID:        uuid.Must(uuid.NewV7()),
			BuyerID:   buyerID,
			ProductID: item.ProductID,
			Quantity:  item.Quantity,
			UnitCents: unitPrice,
			CreatedAt: time.Now().UTC(),
			UpdatedAt: time.Now().UTC(),
		})
	}

	if err := s.repo.ReplaceCart(ctx, buyerID, validItems); err != nil {
		return nil, err
	}

	return s.cartSummary(ctx, buyerID)
}

// ListCart returns the current cart with B2B discounts applied.
func (s *Service) ListCart(ctx context.Context, buyerID uuid.UUID) (*domain.CartSummary, error) {
	return s.cartSummary(ctx, buyerID)
}

// RemoveCartItem deletes a cart row by its ID and returns the refreshed summary.
func (s *Service) RemoveCartItem(ctx context.Context, buyerID, cartItemID uuid.UUID) (*domain.CartSummary, error) {
	if err := s.repo.DeleteCartItem(ctx, cartItemID, buyerID); err != nil {
		return nil, err
	}
	return s.cartSummary(ctx, buyerID)
}

// RemoveCartItemByProduct removes all cart rows for a given product and returns the refreshed summary.
func (s *Service) RemoveCartItemByProduct(ctx context.Context, buyerID, productID uuid.UUID) (*domain.CartSummary, error) {
	if err := s.repo.DeleteCartItemByProduct(ctx, buyerID, productID); err != nil {
		return nil, err
	}
	return s.cartSummary(ctx, buyerID)
}

// ClearCart removes all cart items for a buyer and returns the empty summary.
func (s *Service) ClearCart(ctx context.Context, buyerID uuid.UUID) (*domain.CartSummary, error) {
	if err := s.repo.ClearCart(ctx, buyerID); err != nil {
		return nil, err
	}
	return s.cartSummary(ctx, buyerID)
}

// Reorder re-adds items from a past order into the cart, warning for unavailable items.
func (s *Service) Reorder(ctx context.Context, buyerID, orderID uuid.UUID) (*domain.CartSummary, []string, error) {
	order, err := s.repo.GetOrder(ctx, orderID)
	if err != nil {
		return nil, nil, err
	}

	if order.BuyerID != buyerID {
		return nil, nil, errors.New("order does not belong to buyer")
	}

	var warnings []string
	for _, item := range order.Items {
		if _, err := s.AddItemToCart(ctx, buyerID, item.ProductID, int64(item.Quantity)); err != nil {
			warnings = append(warnings, fmt.Sprintf("Item %s not added: %v", item.ProductID, err))
		}
	}

	summary, err := s.cartSummary(ctx, buyerID)
	return summary, warnings, err
}

// cartSummary assembles the CartSummary DTO, applying volume discounts.
func (s *Service) cartSummary(ctx context.Context, buyerID uuid.UUID) (*domain.CartSummary, error) {
	items, err := s.repo.ListCartItems(ctx, buyerID)
	if err != nil {
		return nil, err
	}

	var subtotal int64
	for i := range items {
		subtotal += items[i].UnitCents * items[i].Quantity
	}

	summary := &domain.CartSummary{
		ID:            buyerID,
		Items:         items,
		SubtotalCents: subtotal,
	}

	// Apply 5% B2B volume discount for baskets ≥ R$1.000,00
	if subtotal >= 100000 {
		summary.DiscountCents = int64(float64(subtotal) * 0.05)
		summary.DiscountReason = "5% B2B volume discount"
	}
	summary.TotalCents = subtotal - summary.DiscountCents
	return summary, nil
}
