package domain

import (
	"math"
	"time"
)

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
	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"`
}
