
// geodist is a package created by jftuga
// Repository: github.com/jftuga/geodist
// It is used to calculate distance between latitude/longitude points

package geodist

import "seekia/internal/helpers"
import "errors"

import "math"

// The below function is adapted from github.com/jftuga/geodist

// HaversineDistance returns the distance (in miles) between two points of
//	 a given longitude and latitude relatively accurately (using a spherical
//	 approximation of the Earth) through the Haversin Distance Formula for
//	 great arc distance on a sphere with accuracy for small distances
//
// Point coordinates are supplied in degrees and converted into rad.
//
// https://en.wikipedia.org/wiki/Haversine_formula

//Outputs:
//	-float64: Distance in kilometers
//	-error
func GetDistanceBetweenCoordinates(aCoordinateLatitude float64, aCoordinateLongitude float64, bCoordinateLatitude float64, bCoordinateLongitude float64) (float64, error) {

	aLatitudeIsValid := helpers.VerifyLatitude(aCoordinateLatitude)
	if (aLatitudeIsValid == false){
		return 0, errors.New("GetDistanceBetweenCoordinates called with invalid aCoordinateLatitude.")
	}
	aLongitudeIsValid := helpers.VerifyLongitude(aCoordinateLongitude)
	if (aLongitudeIsValid == false){
		return 0, errors.New("GetDistanceBetweenCoordinates called with invalid aCoordinateLongitude.")
	}

	bLatitudeIsValid := helpers.VerifyLatitude(bCoordinateLatitude)
	if (bLatitudeIsValid == false){
		return 0, errors.New("GetDistanceBetweenCoordinates called with invalid bCoordinateLatitude.")
	}
	bLongitudeIsValid := helpers.VerifyLongitude(bCoordinateLongitude)
	if (bLongitudeIsValid == false){
		return 0, errors.New("GetDistanceBetweenCoordinates called with invalid bCoordinateLongitude.")
	}

	// Convert to radians

	piRad := math.Pi / 180

	la1 := aCoordinateLatitude * piRad
	lo1 := aCoordinateLongitude * piRad
	la2 := bCoordinateLatitude * piRad
	lo2 := bCoordinateLongitude * piRad

	r := float64(6378100) // Earth radius in meters

	// haversin(θ) function
	hsin := func(theta float64) float64 {
		result := math.Pow(math.Sin(theta/2), 2)
		return result
	}

	h := hsin(la2-la1) + math.Cos(la1) * math.Cos(la2) * hsin(lo2-lo1)

	meters := 2 * r * math.Asin(math.Sqrt(h))
	kilometers := meters / 1000
	
	return kilometers, nil
}


