package service import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "time" ) type GeocodingService interface { GetAddressFromCoordinates(latitude, longitude float64) (string, error) } type nominatimGeocoder struct { client *http.Client } func NewGeocodingService() GeocodingService { client := &http.Client{ Timeout: 10 * time.Second, } return &nominatimGeocoder{ client: client, } } type NominatimResponse struct { DisplayName string `json:"display_name"` Error string `json:"error"` } func (g *nominatimGeocoder) GetAddressFromCoordinates(latitude, longitude float64) (string, error) { if latitude < -90 || latitude > 90 || longitude < -180 || longitude > 180 { errMsg := fmt.Sprintf("Invalid coordinates: lat=%f, lon=%f", latitude, longitude) return "", fmt.Errorf(errMsg) } url := fmt.Sprintf( "https://nominatim.openstreetmap.org/reverse?format=json&lat=%f&lon=%f&zoom=18&addressdetails=1", latitude, longitude, ) req, err := http.NewRequest("GET", url, nil) if err != nil { log.Printf("Request creation error: %v", err) return "", err } req.Header.Set("User-Agent", "AssetManagementApp") resp, err := g.client.Do(req) if err != nil { log.Printf("HTTP request error: %v", err) return "", err } defer resp.Body.Close() // Read full response body bodyBytes, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) return "", err } var result NominatimResponse if err := json.Unmarshal(bodyBytes, &result); err != nil { log.Printf("JSON unmarshal error: %v", err) return "", err } // Detailed error checking if result.Error != "" { log.Printf("Nominatim API Error: %s", result.Error) return "", fmt.Errorf("geocoding error: %s", result.Error) } // Check for empty display name if result.DisplayName == "" { log.Printf("No address found for coordinates: %f, %f", latitude, longitude) return "", fmt.Errorf("no address found for these coordinates") } return result.DisplayName, nil }