saveinmed/backend-old/internal/domain/distance.go
2026-01-16 10:51:52 -03:00

68 lines
1.9 KiB
Go

package domain
import (
"math"
"time"
"github.com/gofrs/uuid/v5"
)
const earthRadiusKm = 6371.0
// HaversineDistance calculates the distance in kilometers between two points
// using the Haversine formula. The result is approximate (±5km for security).
func HaversineDistance(lat1, lng1, lat2, lng2 float64) float64 {
dLat := degreesToRadians(lat2 - lat1)
dLng := degreesToRadians(lng2 - lng1)
lat1Rad := degreesToRadians(lat1)
lat2Rad := degreesToRadians(lat2)
a := math.Sin(dLat/2)*math.Sin(dLat/2) +
math.Cos(lat1Rad)*math.Cos(lat2Rad)*
math.Sin(dLng/2)*math.Sin(dLng/2)
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
distance := earthRadiusKm * c
// Round to nearest km for approximate distance (security)
return math.Round(distance)
}
func degreesToRadians(degrees float64) float64 {
return degrees * math.Pi / 180
}
// ProductWithDistance extends Product with distance information for search results.
type ProductWithDistance struct {
Product
DistanceKm float64 `json:"distance_km"`
TenantCity string `json:"tenant_city,omitempty"`
TenantState string `json:"tenant_state,omitempty"`
// TenantID is hidden for anonymous browsing, revealed only at checkout
}
// ProductSearchFilter captures search constraints.
type ProductSearchFilter struct {
Search string
Category string
MinPriceCents *int64
MaxPriceCents *int64
ExpiresAfter *time.Time
ExpiresBefore *time.Time
MaxDistanceKm *float64
BuyerLat float64
BuyerLng float64
ExcludeSellerID *uuid.UUID // Exclude products from buyer's own company
Limit int
Offset int
}
// ProductSearchPage wraps search results with pagination.
type ProductSearchPage struct {
Products []ProductWithDistance `json:"products"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}