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.
// Implementations live in internal/repository/postgres/.
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)

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)
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

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.).
// Implementations live in internal/infrastructure/payments/.
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)
}

// Service orchestrates all business use cases.
// Methods are split across domain-specific files in this package:
//   - auth_usecase.go      – authentication, JWT, password reset
//   - company_usecase.go   – company registration, KYC, shipping options
//   - product_usecase.go   – catalogue, inventory management
//   - order_usecase.go     – order lifecycle and state machine
//   - shipping_usecase.go  – shipping calculation and configuration
//   - cart_usecase.go      – cart operations and B2B discounts
//   - payment_usecase.go   – payment preferences and webhook handling
//   - review_usecase.go    – buyer reviews and ratings
//   - user_usecase.go      – user CRUD
//   - address_usecase.go   – address management
//   - dashboard_usecase.go – seller and admin KPI dashboards
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
}
