package usecase

import (
	"context"
	"math"
	"strings"

	"github.com/gofrs/uuid/v5"

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

// RegisterProduct generates an ID and persists a new product.
func (s *Service) RegisterProduct(ctx context.Context, product *domain.Product) error {
	product.ID = uuid.Must(uuid.NewV7())
	return s.repo.CreateProduct(ctx, product)
}

// ListProducts returns a paginated list of products matching the filter.
func (s *Service) ListProducts(ctx context.Context, filter domain.ProductFilter, page, pageSize int) (*domain.ProductPage, error) {
	if pageSize <= 0 {
		pageSize = 20
	}
	if page <= 0 {
		page = 1
	}
	filter.Limit = pageSize
	filter.Offset = (page - 1) * pageSize
	products, total, err := s.repo.ListProducts(ctx, filter)
	if err != nil {
		return nil, err
	}
	return &domain.ProductPage{Products: products, Total: total, Page: page, PageSize: pageSize}, nil
}

// SearchProducts returns products with distance, ordered by expiration date.
// Seller info is anonymised until checkout.
func (s *Service) SearchProducts(ctx context.Context, filter domain.ProductSearchFilter, page, pageSize int) (*domain.ProductSearchPage, error) {
	if pageSize <= 0 {
		pageSize = 20
	}
	if page <= 0 {
		page = 1
	}
	filter.Limit = pageSize
	filter.Offset = (page - 1) * pageSize
	products, total, err := s.repo.SearchProducts(ctx, filter)
	if err != nil {
		return nil, err
	}
	return &domain.ProductSearchPage{Products: products, Total: total, Page: page, PageSize: pageSize}, nil
}

// ListRecords provides advanced search for marketplace listings.
func (s *Service) ListRecords(ctx context.Context, req domain.SearchRequest) (*domain.PaginationResponse[domain.Product], error) {
	page := req.Page
	pageSize := req.PageSize
	if pageSize <= 0 {
		pageSize = 20
	}
	if page <= 0 {
		page = 1
	}

	sortBy := strings.TrimSpace(req.SortBy)
	if sortBy == "" {
		sortBy = "updated_at"
	}
	sortOrder := strings.ToLower(strings.TrimSpace(req.SortOrder))
	if sortOrder == "" {
		sortOrder = "desc"
	}

	filter := domain.RecordSearchFilter{
		Query:         strings.TrimSpace(req.Query),
		SortBy:        sortBy,
		SortOrder:     sortOrder,
		CreatedAfter:  req.CreatedAfter,
		CreatedBefore: req.CreatedBefore,
		Limit:         pageSize,
		Offset:        (page - 1) * pageSize,
	}

	items, total, err := s.repo.ListRecords(ctx, filter)
	if err != nil {
		return nil, err
	}

	totalPages := int(math.Ceil(float64(total) / float64(pageSize)))
	return &domain.PaginationResponse[domain.Product]{
		Items:       items,
		TotalCount:  total,
		CurrentPage: page,
		TotalPages:  totalPages,
	}, nil
}

// GetProduct retrieves a product by ID.
func (s *Service) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) {
	return s.repo.GetProduct(ctx, id)
}

// UpdateProduct persists changes to a product.
func (s *Service) UpdateProduct(ctx context.Context, product *domain.Product) error {
	return s.repo.UpdateProduct(ctx, product)
}

// DeleteProduct removes a product by ID.
func (s *Service) DeleteProduct(ctx context.Context, id uuid.UUID) error {
	return s.repo.DeleteProduct(ctx, id)
}

// ListInventory returns a paginated list of inventory items for a seller.
func (s *Service) ListInventory(ctx context.Context, filter domain.InventoryFilter, page, pageSize int) (*domain.InventoryPage, error) {
	if pageSize <= 0 {
		pageSize = 20
	}
	if page <= 0 {
		page = 1
	}
	filter.Limit = pageSize
	filter.Offset = (page - 1) * pageSize
	items, total, err := s.repo.ListInventory(ctx, filter)
	if err != nil {
		return nil, err
	}
	return &domain.InventoryPage{Items: items, Total: total, Page: page, PageSize: pageSize}, nil
}

// AdjustInventory increments or decrements the stock of a product.
func (s *Service) AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error) {
	return s.repo.AdjustInventory(ctx, productID, delta, reason)
}

// ListManufacturers returns all distinct manufacturer names in the catalogue.
func (s *Service) ListManufacturers(ctx context.Context) ([]string, error) {
	return s.repo.ListManufacturers(ctx)
}
