package usecase import ( "context" "time" "github.com/gofrs/uuid/v5" "github.com/saveinmed/backend-go/internal/domain" "github.com/saveinmed/backend-go/internal/infrastructure/mapbox" "github.com/saveinmed/backend-go/internal/infrastructure/notifications" ) // Repository defines the persistence contract for all core entities. type Repository interface { CreateCompany(ctx context.Context, company *domain.Company) error ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, error) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) UpdateCompany(ctx context.Context, company *domain.Company) error DeleteCompany(ctx context.Context, id uuid.UUID) error CreateProduct(ctx context.Context, product *domain.Product) error BatchCreateProducts(ctx context.Context, products []domain.Product) error ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error) SearchProducts(ctx context.Context, filter domain.ProductSearchFilter) ([]domain.ProductWithDistance, int64, error) ListRecords(ctx context.Context, filter domain.RecordSearchFilter) ([]domain.Product, int64, error) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) UpdateProduct(ctx context.Context, product *domain.Product) error DeleteProduct(ctx context.Context, id uuid.UUID) error AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error) CreateInventoryItem(ctx context.Context, item *domain.InventoryItem) error GetInventoryItem(ctx context.Context, id uuid.UUID) (*domain.InventoryItem, error) UpdateInventoryItem(ctx context.Context, item *domain.InventoryItem) error CreateOrder(ctx context.Context, order *domain.Order) error ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, error) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error DeleteOrder(ctx context.Context, id uuid.UUID) error UpdateOrderItems(ctx context.Context, orderID uuid.UUID, items []domain.OrderItem, totalCents int64) error CreateShipment(ctx context.Context, shipment *domain.Shipment) error GetShipmentByOrderID(ctx context.Context, orderID uuid.UUID) (*domain.Shipment, error) CreateUser(ctx context.Context, user *domain.User) error ListUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) GetUser(ctx context.Context, id uuid.UUID) (*domain.User, error) GetUserByUsername(ctx context.Context, username string) (*domain.User, error) GetUserByEmail(ctx context.Context, email string) (*domain.User, error) UpdateUser(ctx context.Context, user *domain.User) error DeleteUser(ctx context.Context, id uuid.UUID) error AddCartItem(ctx context.Context, item *domain.CartItem) (*domain.CartItem, error) ListCartItems(ctx context.Context, buyerID uuid.UUID) ([]domain.CartItem, error) DeleteCartItem(ctx context.Context, id uuid.UUID, buyerID uuid.UUID) error DeleteCartItemByProduct(ctx context.Context, buyerID, productID uuid.UUID) error ClearCart(ctx context.Context, buyerID uuid.UUID) error ReplaceCart(ctx context.Context, buyerID uuid.UUID, items []domain.CartItem) error CreateReview(ctx context.Context, review *domain.Review) error GetCompanyRating(ctx context.Context, companyID uuid.UUID) (*domain.CompanyRating, error) ListReviews(ctx context.Context, filter domain.ReviewFilter) ([]domain.Review, int64, error) SellerDashboard(ctx context.Context, sellerID uuid.UUID) (*domain.SellerDashboard, error) AdminDashboard(ctx context.Context, since time.Time) (*domain.AdminDashboard, error) GetShippingSettings(ctx context.Context, vendorID uuid.UUID) (*domain.ShippingSettings, error) UpsertShippingSettings(ctx context.Context, settings *domain.ShippingSettings) error ListShipments(ctx context.Context, filter domain.ShipmentFilter) ([]domain.Shipment, int64, error) CreateDocument(ctx context.Context, doc *domain.CompanyDocument) error ListDocuments(ctx context.Context, companyID uuid.UUID) ([]domain.CompanyDocument, error) RecordLedgerEntry(ctx context.Context, entry *domain.LedgerEntry) error GetLedger(ctx context.Context, companyID uuid.UUID, limit, offset int) ([]domain.LedgerEntry, int64, error) GetBalance(ctx context.Context, companyID uuid.UUID) (int64, error) CreateWithdrawal(ctx context.Context, withdrawal *domain.Withdrawal) error ListWithdrawals(ctx context.Context, companyID uuid.UUID) ([]domain.Withdrawal, error) // Stock Reservations ReserveStock(ctx context.Context, res *domain.StockReservation) error CompleteReservation(ctx context.Context, reservationID uuid.UUID) error ExpireReservations(ctx context.Context) error GetActiveReservations(ctx context.Context, inventoryItemID uuid.UUID) (int64, error) GetPaymentGatewayConfig(ctx context.Context, provider string) (*domain.PaymentGatewayConfig, error) UpsertPaymentGatewayConfig(ctx context.Context, config *domain.PaymentGatewayConfig) error GetSellerPaymentAccount(ctx context.Context, sellerID uuid.UUID) (*domain.SellerPaymentAccount, error) UpsertSellerPaymentAccount(ctx context.Context, account *domain.SellerPaymentAccount) error CreateAddress(ctx context.Context, address *domain.Address) error ListAddresses(ctx context.Context, entityID uuid.UUID) ([]domain.Address, error) ListAllAddresses(ctx context.Context) ([]domain.Address, error) GetAddress(ctx context.Context, id uuid.UUID) (*domain.Address, error) UpdateAddress(ctx context.Context, address *domain.Address) error DeleteAddress(ctx context.Context, id uuid.UUID) error GeocodeAllAddresses(ctx context.Context) (int, error) StartStockCleanupWorker(ctx context.Context) ListManufacturers(ctx context.Context) ([]string, error) ListCategories(ctx context.Context) ([]string, error) GetProductByEAN(ctx context.Context, ean string) (*domain.Product, error) } // PaymentGateway abstracts the payment provider (Mercado Pago, Asaas, etc.). type PaymentGateway interface { CreatePreference(ctx context.Context, order *domain.Order, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentPreference, error) CreatePayment(ctx context.Context, order *domain.Order, token, issuerID, paymentMethodID string, installments int, payer *domain.User, sellerAcc *domain.SellerPaymentAccount) (*domain.PaymentResult, error) CreatePixPayment(ctx context.Context, order *domain.Order) (*domain.PixPaymentResult, error) CreateBoletoPayment(ctx context.Context, order *domain.Order, payer *domain.User) (*domain.BoletoPaymentResult, error) GetPaymentStatus(ctx context.Context, paymentID string) (*domain.PaymentWebhookEvent, error) } // Service orchestrates all business use cases. type Service struct { repo Repository pay PaymentGateway mapbox *mapbox.Client notify notifications.NotificationService marketplaceCommission float64 buyerFeeRate float64 jwtSecret []byte tokenTTL time.Duration passwordPepper string } const ( // passwordResetTTL is the validity window for password-reset JWTs. passwordResetTTL = 30 * time.Minute ) // NewService wires all dependencies and returns a ready-to-use Service. func NewService( repo Repository, pg PaymentGateway, mb *mapbox.Client, notify notifications.NotificationService, commission, buyerFeeRate float64, jwtSecret string, tokenTTL time.Duration, pepper string, ) *Service { return &Service{ repo: repo, pay: pg, mapbox: mb, notify: notify, marketplaceCommission: commission, buyerFeeRate: buyerFeeRate, jwtSecret: []byte(jwtSecret), tokenTTL: tokenTTL, passwordPepper: pepper, } } // GetNotificationService exposes the notification service for push handlers. func (s *Service) GetNotificationService() notifications.NotificationService { return s.notify } // DeleteAddress handles address removal logic. func (s *Service) DeleteAddress(ctx context.Context, id uuid.UUID) error { return s.repo.DeleteAddress(ctx, id) } // ListManufacturers returns manufacturers from the repo. func (s *Service) ListManufacturers(ctx context.Context) ([]string, error) { return s.repo.ListManufacturers(ctx) } // ListCategories returns categories from the repo. func (s *Service) ListCategories(ctx context.Context) ([]string, error) { return s.repo.ListCategories(ctx) } // GetProductByEAN finds a product by its EAN code. func (s *Service) GetProductByEAN(ctx context.Context, ean string) (*domain.Product, error) { return s.repo.GetProductByEAN(ctx, ean) }