Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

package com.spice.profitmandi.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@Service
public class GeocodingService {

        private static final Logger LOGGER = LogManager.getLogger(GeocodingService.class);
        private static final String GOOGLE_GEOCODE_URL = "https://maps.googleapis.com/maps/api/geocode/json";
        private static final String API_KEY = "AIzaSyAckO0y4Z6WhBOuMjNjioWLSYZDhGEvGBc";

        private final ObjectMapper objectMapper = new ObjectMapper();

        /**
         * Build a clean geocoding query from address parts.
         * Only includes: line1, city, state, pincode — no phone, no landmark prefix, no shop numbers.
         */
        public static String buildGeoAddress(String line1, String city, String state, String pinCode) {
                StringBuilder sb = new StringBuilder();
                if (city != null && !city.isEmpty()) sb.append(city).append(", ");
                if (state != null && !state.isEmpty()) sb.append(state).append(", ");
                if (pinCode != null && !pinCode.isEmpty()) sb.append(pinCode).append(", ");
                sb.append("India");
                return sb.toString().trim();
        }

        /**
         * Geocode an address string to [latitude, longitude].
         * Cached in Redis forever to avoid repeated API calls.
         * Returns null if geocoding fails.
         */
        @Cacheable(value = "partnerGeocode", key = "#address", cacheManager = "redisEternalCacheManager")
        public double[] geocodeAddress(String address) {
                if (address == null || address.trim().isEmpty()) {
                        return null;
                }
                try {
                        String cleanAddress = sanitizeForGeocoding(address);
                        String encodedAddress = URLEncoder.encode(cleanAddress, StandardCharsets.UTF_8.toString());
                        String urlStr = GOOGLE_GEOCODE_URL + "?address=" + encodedAddress
                                        + "&key=" + API_KEY + "&components=country:IN";

                        URL url = new URL(urlStr);
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        conn.setRequestMethod("GET");
                        conn.setConnectTimeout(5000);
                        conn.setReadTimeout(5000);

                        int responseCode = conn.getResponseCode();
                        if (responseCode != 200) {
                                LOGGER.warn("Geocoding HTTP error for '{}': {}", address, responseCode);
                                return null;
                        }

                        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                        StringBuilder sb = new StringBuilder();
                        String line;
                        while ((line = reader.readLine()) != null) {
                                sb.append(line);
                        }
                        reader.close();
                        conn.disconnect();

                        JsonNode root = objectMapper.readTree(sb.toString());
                        String status = root.path("status").asText();

                        if (!"OK".equals(status)) {
                                LOGGER.warn("Geocoding failed for '{}': status={}", address, status);
                                return null;
                        }

                        JsonNode location = root.path("results").get(0).path("geometry").path("location");
                        double lat = location.path("lat").asDouble();
                        double lng = location.path("lng").asDouble();

                        LOGGER.info("Geocoded '{}' -> [{}, {}]", address, lat, lng);
                        return new double[]{lat, lng};

                } catch (Exception e) {
                        LOGGER.error("Geocoding error for '{}': {}", address, e.getMessage());
                        return null;
                }
        }

        /**
         * Remove noise from address: phone numbers, PIN- prefix, Landmark:, Shop No. etc.
         * Keep only location-relevant parts for better geocoding accuracy.
         */
        private String sanitizeForGeocoding(String address) {
                String clean = address;
                // Remove phone numbers (Ph: XXXXXXXXXX)
                clean = clean.replaceAll("(?i),?\\s*Ph:\\s*\\d+", "");
                // Remove PIN- prefix but keep the number
                clean = clean.replaceAll("(?i)PIN-", "");
                // Remove Landmark: prefix
                clean = clean.replaceAll("(?i)Landmark:\\s*", "");
                // Remove Shop No. / Ward No. patterns (too specific for geocoding)
                clean = clean.replaceAll("(?i)Shop\\s*No\\.?\\s*[\\d/]+,?\\s*", "");
                clean = clean.replaceAll("(?i)Ward\\s*No\\.?\\s*[\\d/]+,?\\s*", "");
                // Clean up double commas and trailing commas
                clean = clean.replaceAll(",\\s*,", ",");
                clean = clean.replaceAll("^[,\\s]+|[,\\s]+$", "");
                return clean.trim();
        }
}