<?php
namespace MMP;

use MMP\Maps_Marker_Pro as MMP;

class Geocoding {
	/**
	 * Registers the hooks
	 *
	 * @since 4.24
	 */
	public function init() {
		add_action('wp_ajax_mmp_geocoding', array($this, 'geocoding'));
		add_action('wp_ajax_nopriv_mmp_geocoding', array($this, 'geocoding'));
		add_action('wp_ajax_mmp_google_places', array($this, 'googlePlaces'));
		add_action('wp_ajax_nopriv_mmp_google_places', array($this, 'googlePlaces'));
	}

	/**
	 * AJAX request for geocoding
	 *
	 * @since 4.24
	 */
	public function geocoding() {
		$provider = (isset($_POST['provider'])) ? $_POST['provider'] : null;
		$query = (isset($_POST['query'])) ? $_POST['query'] : null;

		$results = $this->getResults($provider, $query);

		wp_send_json($results);
	}

	/**
	 * AJAX request for Google Places
	 *
	 * @since 4.24
	 */
	public function googlePlaces() {
		$place_id = (isset($_POST['placeId'])) ? $_POST['placeId'] : null;
		$legacy = (isset($_POST['legacy']) && $_POST['legacy'] === 'true');

		if ($legacy) {
			$result = $this->placesLegacyToLatLng($place_id);
		} else {
			$result = $this->placesToLatLng($place_id);
		}

		wp_send_json($result);
	}

	/**
	 * Geocodes an address
	 *
	 * @since 4.0
	 * @since 4.20 $use_cache parameter added
	 *
	 * @param string $address Address to geocode
	 * @param string $provider Provider to geocode with
	 * @param bool $use_cache (optional) Whether to use the geocoding cache
	 */
	public function getLatLng($address, $provider, $use_cache = true) {
		$db = MMP::get_instance('MMP\DB');

		if ($use_cache) {
			$cache = $db->get_cached_address($address);
			if ($cache !== null) {
				return array(
					'success' => true,
					'cached'  => true,
					'lat'     => $cache->lat,
					'lon'     => $cache->lng,
					'address' => $cache->address
				);
			}
		}

		$response = $this->getResults($provider, $address, 1);

		if (!$response['success']) {
			return $response;
		}

		if (!count($response['results'])) {
			return array(
				'success' => false,
				'message' => esc_html__('No results', 'mmp')
			);
		}

		if (isset($response['results'][0]['placeId'])) {
			if ($provider === 'googlelegacy') {
				$result = $this->placesLegacyToLatLng($response['results'][0]['placeId']);
			} else {
				$result = $this->placesToLatLng($response['results'][0]['placeId']);
			}

			if ($result['success'] === false) {
				return $result;
			}

			$response['results'][0]['lat'] = $result['lat'];
			$response['results'][0]['lon'] = $result['lon'];
		}

		$db->cache_address(
			$address,
			$response['results'][0]['address'],
			$response['results'][0]['lat'],
			$response['results'][0]['lon']
		);

		return array(
			'success' => true,
			'lat'     => $response['results'][0]['lat'],
			'lon'     => $response['results'][0]['lon'],
			'address' => $response['results'][0]['address']
		);
	}

	/**
	 * Gets results from a geocoding provider
	 *
	 * @since 4.24
	 *
	 * @param string $provider Provider to query
	 * @param string $query Search query
	 * @param int $limit (optional) Maximum number of results to retrieve
	 */
	private function getResults($provider, $query, $limit = 10) {
		$query = remove_accents($query);

		switch ($provider) {
			case 'locationiq':
				$results = $this->locationiq($query, $limit);
				break;
			case 'mapquest':
				$results = $this->mapquest($query, $limit);
				break;
			case 'google':
				$results = $this->google($query, $limit);
				break;
			case 'googlelegacy':
				$results = $this->googlelegacy($query, $limit);
				break;
			case 'tomtom':
				$results = $this->tomtom($query, $limit);
				break;
			case 'stadia':
				$results = $this->stadia($query, $limit);
				break;
			default:
				$results = array(
					'success' => false,
					'message' => esc_html__('Invalid provider', 'mmp')
				);
				break;
		}

		return $results;
	}

	/**
	 * Geocodes an address using LocationIQ
	 *
	 * @since 4.0
	 * @since 4.24 $limit parameter added
	 *
	 * @param string $address Address to geocode
	 * @param int $limit (optional) Maximum number of results to retrieve
	 */
	private function locationiq($address, $limit = 10) {
		$params = array(
			'key'             => (MMP::$settings['geocodingLocationIqApiKey']) ? MMP::$settings['geocodingLocationIqApiKey'] : 'pk.7c187d868c07782a63a0057cdf68cf42',
			'q'               => $address,
			'limit'           => $limit,
			'normalizecity'   => 1,
			'accept-language' => (MMP::$settings['geocodingLocationIqLanguage']) ? MMP::$settings['geocodingLocationIqLanguage'] : substr(get_locale(), 0, 2),
			'countrycodes'    => MMP::$settings['geocodingLocationIqCountries']
		);
		if (MMP::$settings['geocodingLocationIqBounds']) {
			$params['viewbox'] = implode(',', array(
				MMP::$settings['geocodingLocationIqBoundsLon1'],
				MMP::$settings['geocodingLocationIqBoundsLat1'],
				MMP::$settings['geocodingLocationIqBoundsLon2'],
				MMP::$settings['geocodingLocationIqBoundsLat2']
			));
		}
		$url = 'https://api.locationiq.com/v1/autocomplete.php?' . http_build_query($params, '', '&');

		$response = wp_remote_get($url, array(
			'timeout' => 10,
			'headers' => array('Referer' => home_url())
		));

		if (is_wp_error($response)) {
			return array(
				'success' => false,
				'message' => $response->get_error_message()
			);
		}

		if ($response['response']['code'] !== 200) {
			return array(
				'success' => false,
				'message' => $response['response']['code'] . ' ' . $response['response']['message']
			);
		}

		$body = json_decode($response['body'], true);
		if (!is_array($body)) {
			return array(
				'success' => false,
				'message' => esc_html__('Invalid response', 'mmp')
			);
		}

		$results = array();
		foreach ($body as $suggestion) {
			$results[] = array(
				'address' => $suggestion['display_name'],
				'lat'     => floatval($suggestion['lat']),
				'lon'     => floatval($suggestion['lon'])
			);
		}

		return array(
			'success' => true,
			'results' => $results
		);
	}

	/**
	 * Geocodes an address using MapQuest
	 *
	 * @since 4.0
	 * @since 4.24 $limit parameter added
	 *
	 * @param string $address Address to geocode
	 * @param int $limit (optional) Maximum number of results to retrieve
	 */
	private function mapquest($address, $limit = 10) {
		if (!MMP::$settings['geocodingMapQuestApiKey']) {
			return array(
				'success' => false,
				'message' => esc_html__('API key missing', 'mmp')
			);
		}

		$params = array(
			'key'        => MMP::$settings['geocodingMapQuestApiKey'],
			'location'   => $address,
			'maxResults' => $limit
		);
		if (MMP::$settings['geocodingMapQuestBounds']) {
			$params['boundingBox'] = implode(',', array(
				MMP::$settings['geocodingMapQuestBoundsLat1'],
				MMP::$settings['geocodingMapQuestBoundsLon1'],
				MMP::$settings['geocodingMapQuestBoundsLat2'],
				MMP::$settings['geocodingMapQuestBoundsLon2']
			));
		}
		$url = 'https://www.mapquestapi.com/geocoding/v1/address?' . http_build_query($params, '', '&');

		$response = wp_remote_get($url, array(
			'timeout' => 10,
			'headers' => array('Referer' => home_url())
		));

		if (is_wp_error($response)) {
			return array(
				'success' => false,
				'message' => $response->get_error_message()
			);
		}

		if ($response['response']['code'] !== 200) {
			return array(
				'success' => false,
				'message' => $response['response']['code'] . ' ' . $response['response']['message']
			);
		}

		$body = json_decode($response['body'], true);
		if (!isset($body['results'][0]['locations']) || !is_array($body['results'][0]['locations'])) {
			return array(
				'success' => false,
				'message' => esc_html__('Invalid response', 'mmp')
			);
		}

		$results = array();
		foreach ($body['results'][0]['locations'] as $suggestion) {
			$out = '';
			$out .= (isset($suggestion['street']) && $suggestion['street']) ? $suggestion['street'] . ', ' : '';
			$out .= (isset($suggestion['adminArea5']) && $suggestion['adminArea5']) ? $suggestion['adminArea5'] . ', ' : '';
			$out .= (isset($suggestion['adminArea4']) && $suggestion['adminArea4']) ? $suggestion['adminArea4'] . ', ' : '';
			$out .= (isset($suggestion['adminArea3']) && $suggestion['adminArea3']) ? $suggestion['adminArea3'] . ', ' : '';
			$out .= (isset($suggestion['adminArea2']) && $suggestion['adminArea2']) ? $suggestion['adminArea2'] . ', ' : '';
			$out .= (isset($suggestion['adminArea1']) && $suggestion['adminArea1']) ? $suggestion['adminArea1'] : '';
			$results[] = array(
				'address' => $out,
				'lat'     => floatval($suggestion['displayLatLng']['lat']),
				'lon'     => floatval($suggestion['displayLatLng']['lng'])
			);
		}

		return array(
			'success' => true,
			'results' => $results
		);
	}

	/**
	 * Geocodes an address using Google
	 *
	 * @since 4.30
	 *
	 * @param string $address Address to geocode
	 * @param int $limit (optional) Maximum number of results to retrieve
	 */
	private function google($address, $limit = 10) {
		if (!MMP::$settings['geocodingGoogleApiKey']) {
			return array(
				'success' => false,
				'message' => esc_html__('API key missing', 'mmp')
			);
		}

		$params = array(
			'input' => $address
		);
		if (MMP::$settings['geocodingGoogleLocationLat'] && MMP::$settings['geocodingGoogleLocationLon'] && MMP::$settings['geocodingGoogleRadius']) {
			$params['locationBias'] = array(
				'circle' => array(
					'center' => array(
						'latitude'   => MMP::$settings['geocodingGoogleLocationLat'],
						'longitutde' => MMP::$settings['geocodingGoogleLocationLon']
					)
				),
				'radius' => MMP::$settings['geocodingGoogleRadius']
			);
		}
		if (MMP::$settings['geocodingGoogleRegionCode']) {
			$params['regionCode'] = MMP::$settings['geocodingGoogleRegionCode'];
		}
		if (MMP::$settings['geocodingGoogleincludedRegionCodes']) {
			$params['includedRegionCodes'] = explode(',', MMP::$settings['geocodingGoogleincludedRegionCodes']);
		}
		if (MMP::$settings['geocodingGoogleLanguageCode']) {
			$params['languageCode'] = MMP::$settings['geocodingGoogleLanguageCode'];
		} else {
			$params['languageCode'] = substr(get_locale(), 0, 2);
		}

		$response = wp_remote_post('https://places.googleapis.com/v1/places:autocomplete', array(
			'timeout' => 10,
			'headers' => array(
				'Referer'        => home_url(),
				'Content-Type'   => 'application/json',
				'X-Goog-Api-Key' => MMP::$settings['geocodingGoogleApiKey']
			),
			'body'    => json_encode($params)
		));

		if (is_wp_error($response)) {
			return array(
				'success' => false,
				'message' => $response->get_error_message()
			);
		}

		if ($response['response']['code'] !== 200) {
			return array(
				'success' => false,
				'message' => $response['response']['code'] . ' ' . $response['response']['message']
			);
		}

		$body = json_decode($response['body'], true);
		if (!isset($body['suggestions']) || !is_array($body['suggestions'])) {
			return array(
				'success' => false,
				'message' => esc_html__('Invalid response', 'mmp')
			);
		}

		$results = array();
		foreach ($body['suggestions'] as $suggestion) {
			$results[] = array(
				'address' => $suggestion['placePrediction']['text']['text'],
				'placeId' => $suggestion['placePrediction']['placeId'],
			);
		}

		return array(
			'success' => true,
			'results' => $results
		);
	}

	/**
	 * Geocodes an address using Google (Legacy)
	 *
	 * @since 4.0
	 * @since 4.24 $limit parameter added
	 *
	 * @param string $address Address to geocode
	 * @param int $limit (optional) Maximum number of results to retrieve
	 */
	private function googlelegacy($address, $limit = 10) {
		if (MMP::$settings['geocodingGoogleLegacyAuthMethod'] === 'clientid-signature' && (!MMP::$settings['geocodingGoogleLegacyClient'] || !MMP::$settings['geocodingGoogleLegacySignature'] || !MMP::$settings['geocodingGoogleLegacyChannel'])) {
			return array(
				'success' => false,
				'message' => esc_html__('Credentials missing or incomplete', 'mmp')
			);
		} else if (!MMP::$settings['geocodingGoogleLegacyApiKey']) {
			return array(
				'success' => false,
				'message' => esc_html__('API key missing', 'mmp')
			);
		}

		$params = array(
			'input' => $address
		);
		if (MMP::$settings['geocodingGoogleLegacyAuthMethod'] === 'clientid-signature') {
			$params['client'] = MMP::$settings['geocodingGoogleLegacyClient'];
			$params['signature'] = MMP::$settings['geocodingGoogleLegacySignature'];
			$params['channel'] = MMP::$settings['geocodingGoogleLegacyChannel'];
		} else {
			$params['key'] = MMP::$settings['geocodingGoogleLegacyApiKey'];
		}
		if (MMP::$settings['geocodingGoogleLegacyLocation']) {
			$params['location'] = MMP::$settings['geocodingGoogleLegacyLocation'];
		}
		if (MMP::$settings['geocodingGoogleLegacyRadius']) {
			$params['radius'] = MMP::$settings['geocodingGoogleLegacyRadius'];
		}
		if (MMP::$settings['geocodingGoogleLegacyRegion']) {
			$params['region'] = MMP::$settings['geocodingGoogleLegacyRegion'];
		}
		if (MMP::$settings['geocodingGoogleLegacyComponents']) {
			$params['components'] = MMP::$settings['geocodingGoogleLegacyComponents'];
		}
		if (MMP::$settings['geocodingGoogleLegacyLanguage']) {
			$params['language'] = MMP::$settings['geocodingGoogleLegacyLanguage'];
		} else {
			$params['language'] = substr(get_locale(), 0, 2);
		}
		$url = 'https://maps.googleapis.com/maps/api/place/autocomplete/json?' . http_build_query($params, '', '&');

		$response = wp_remote_get($url, array(
			'timeout' => 10,
			'headers' => array('Referer' => home_url())
		));

		if (is_wp_error($response)) {
			return array(
				'success' => false,
				'message' => $response->get_error_message()
			);
		}

		if ($response['response']['code'] !== 200) {
			return array(
				'success' => false,
				'message' => $response['response']['code'] . ' ' . $response['response']['message']
			);
		}

		$body = json_decode($response['body'], true);
		if (!isset($body['status']) || !isset($body['predictions']) || !is_array($body['predictions'])) {
			return array(
				'success' => false,
				'message' => esc_html__('Invalid response', 'mmp')
			);
		}

		if ($body['status'] !== 'OK' && $body['status'] !== 'ZERO_RESULTS') {
			return array(
				'success' => false,
				'message' => $body['error_message']
			);
		}

		$results = array();
		foreach ($body['predictions'] as $suggestion) {
			$results[] = array(
				'address' => $suggestion['description'],
				'placeId' => $suggestion['place_id'],
			);
		}

		return array(
			'success' => true,
			'results' => $results
		);
	}

	/**
	 * Geocodes an address using TomTom
	 *
	 * @since 4.6
	 * @since 4.24 $limit parameter added
	 *
	 * @param string $address Address to geocode
	 * @param int $limit (optional) Maximum number of results to retrieve
	 */
	private function tomtom($address, $limit) {
		if (!MMP::$settings['geocodingTomTomApiKey']) {
			return array(
				'success' => false,
				'message' => esc_html__('API key missing', 'mmp')
			);
		}

		$params = array(
			'key'   => MMP::$settings['geocodingTomTomApiKey'],
			'limit' => $limit
		);
		if (MMP::$settings['geocodingTomTomLat']) {
			$params['lat'] = MMP::$settings['geocodingTomTomLat'];
		}
		if (MMP::$settings['geocodingTomTomLon']) {
			$params['lon'] = MMP::$settings['geocodingTomTomLon'];
		}
		if (MMP::$settings['geocodingTomTomRadius']) {
			$params['radius'] = MMP::$settings['geocodingTomTomRadius'];
		}
		$language = (MMP::$settings['geocodingTomTomLanguage']) ? MMP::$settings['geocodingTomTomLanguage'] : str_replace('_', '-', get_locale());
		if (in_array($language, array('NGT', 'NGT-Latn', 'af-ZA', 'ar', 'eu-ES', 'bg-BG', 'ca-ES', 'zh-CN', 'zh-TW', 'cs-CZ', 'da-DK', 'nl-BE', 'nl-NL', 'en-AU', 'en-NZ', 'en-GB', 'en-US', 'et-EE', 'fi-FI', 'fr-CA', 'fr-FR', 'gl-ES', 'de-DE', 'el-GR', 'hr-HR', 'he-IL', 'hu-HU', 'id-ID', 'it-IT', 'kk-KZ', 'lv-LV', 'lt-LT', 'ms-MY', 'No-NO', 'nb-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ro-RO', 'ru-RU', 'ru-Latn-RU', 'ru-Cyrl-RU', 'sr-RS', 'sk-SK', 'sl-SI', 'es-ES', 'es-419', 'sv-SE', 'th-TH', 'tr-TR', 'uk-UA', 'vi-VN'))) {
			$params['language'] = $language;
		}
		if (MMP::$settings['geocodingTomTomCountrySet']) {
			$params['countrySet'] = MMP::$settings['geocodingTomTomCountrySet'];
		}
		$url = "https://api.tomtom.com/search/2/geocode/{$address}.JSON?" . http_build_query($params, '', '&');

		$response = wp_remote_get($url, array(
			'timeout' => 10,
			'headers' => array('Referer' => home_url())
		));

		if (is_wp_error($response)) {
			return array(
				'success' => false,
				'message' => $response->get_error_message()
			);
		}

		if ($response['response']['code'] !== 200) {
			return array(
				'success' => false,
				'message' => $response['response']['code'] . ' ' . $response['response']['message']
			);
		}

		$body = json_decode($response['body'], true);
		if (!isset($body['results']) || !is_array($body['results'])) {
			return array(
				'success' => false,
				'message' => esc_html__('Invalid response', 'mmp')
			);
		}

		$results = array();
		foreach ($body['results'] as $suggestion) {
			$out = $suggestion['address']['freeformAddress'];
			$out .= (isset($suggestion['address']['country']) && $address !== $suggestion['address']['country']) ? ', ' . $suggestion['address']['country'] : '';
			$results[] = array(
				'address' => $out,
				'lat'     => floatval($suggestion['position']['lat']),
				'lon'     => floatval($suggestion['position']['lon'])
			);
		}

		return array(
			'success' => true,
			'results' => $results
		);
	}

	/**
	 * Geocodes an address using Stadia
	 *
	 * @since 4.29
	 *
	 * @param string $address Address to geocode
	 * @param int $limit (optional) Maximum number of results to retrieve
	 */
	private function stadia($address, $limit) {
		if (MMP::$settings['geocodingStadiaAuthentication'] === 'key' && !MMP::$settings['geocodingStadiaApiKey']) {
			return array(
				'success' => false,
				'message' => esc_html__('API key missing', 'mmp')
			);
		}

		$params = array(
			'text' => $address,
			'size' => $limit
		);
		if (MMP::$settings['geocodingStadiaAuthentication'] === 'key' && MMP::$settings['geocodingStadiaApiKey']) {
			$params['api_key'] = MMP::$settings['geocodingStadiaApiKey'];
		}
		if (MMP::$settings['geocodingStadiaLat']) {
			$params['focus.point.lat'] = MMP::$settings['geocodingStadiaLat'];
		}
		if (MMP::$settings['geocodingStadiaLon']) {
			$params['focus.point.lon'] = MMP::$settings['geocodingStadiaLon'];
		}
		if (MMP::$settings['geocodingStadiaCountry']) {
			$params['boundary.country'] = MMP::$settings['geocodingStadiaCountry'];
		}
		if (MMP::$settings['geocodingStadiaLanguage']) {
			$params['lang'] = MMP::$settings['geocodingStadiaLanguage'];
		} else {
			$params['lang'] = str_replace('_', '-', get_locale());
		}
		$url = "https://api.stadiamaps.com/geocoding/v1/autocomplete?" . http_build_query($params, '', '&');

		$response = wp_remote_get($url, array(
			'timeout' => 10,
			'headers' => array('Referer' => home_url())
		));

		if (is_wp_error($response)) {
			return array(
				'success' => false,
				'message' => $response->get_error_message()
			);
		}

		if ($response['response']['code'] !== 200) {
			return array(
				'success' => false,
				'message' => $response['response']['code'] . ' ' . $response['response']['message']
			);
		}

		$body = json_decode($response['body'], true);
		if (!isset($body['features']) || !is_array($body['features'])) {
			return array(
				'success' => false,
				'message' => esc_html__('Invalid response', 'mmp')
			);
		}

		$results = array();
		foreach ($body['features'] as $feature) {
			$results[] = array(
				'address' => $feature['properties']['label'],
				'lat'     => floatval($feature['geometry']['coordinates'][1]),
				'lon'     => floatval($feature['geometry']['coordinates'][0])
			);
		}

		return array(
			'success' => true,
			'results' => $results
		);
	}

	/**
	 * Gets the coordinates for a Google Places ID
	 *
	 * @since 4.30
	 *
	 * @param string $place_id Place ID
	 */
	private function placesToLatLng($place_id) {
		if (!MMP::$settings['geocodingGoogleApiKey']) {
			return array(
				'success' => false,
				'message' => esc_html__('API key missing', 'mmp')
			);
		}

		$params = array(
			'key'    => MMP::$settings['geocodingGoogleApiKey'],
			'fields' => 'location,formattedAddress'
		);
		$url = "https://places.googleapis.com/v1/places/{$place_id}?" . http_build_query($params, '', '&');

		$response = wp_remote_get($url, array(
			'timeout' => 10,
			'headers' => array('Referer' => home_url())
		));

		if (is_wp_error($response)) {
			return array(
				'success' => false,
				'message' => $response->get_error_message()
			);
		}

		if ($response['response']['code'] !== 200) {
			return array(
				'success' => false,
				'message' => $response['response']['code'] . ' ' . $response['response']['message']
			);
		}

		$body = json_decode($response['body'], true);
		if (!isset($body['formattedAddress']) || !isset($body['location']) || !is_array($body['location'])) {
			return array(
				'success' => false,
				'message' => esc_html__('Invalid response', 'mmp')
			);
		}

		return array(
			'success' => true,
			'address' => $body['formattedAddress'],
			'lat'     => floatval($body['location']['latitude']),
			'lon'     => floatval($body['location']['longitude'])
		);
	}

	/**
	 * Gets the coordinates for a Google Places ID (Legacy)
	 *
	 * @since 4.24
	 *
	 * @param string $place_id Place ID
	 */
	private function placesLegacyToLatLng($place_id) {
		if (MMP::$settings['geocodingGoogleLegacyAuthMethod'] === 'clientid-signature' && (!MMP::$settings['geocodingGoogleLegacyClient'] || !MMP::$settings['geocodingGoogleLegacySignature'] || !MMP::$settings['geocodingGoogleLegacyChannel'])) {
			return array(
				'success' => false,
				'message' => esc_html__('Credentials missing or incomplete', 'mmp')
			);
		} else if (!MMP::$settings['geocodingGoogleLegacyApiKey']) {
			return array(
				'success' => false,
				'message' => esc_html__('API key missing', 'mmp')
			);
		}

		$params = array(
			'placeid' => $place_id
		);
		if (MMP::$settings['geocodingGoogleLegacyAuthMethod'] === 'clientid-signature') {
			$params['client'] = MMP::$settings['geocodingGoogleLegacyClient'];
			$params['signature'] = MMP::$settings['geocodingGoogleLegacySignature'];
			$params['channel'] = MMP::$settings['geocodingGoogleLegacyChannel'];
		} else {
			$params['key'] = MMP::$settings['geocodingGoogleLegacyApiKey'];
		}
		$url = 'https://maps.googleapis.com/maps/api/place/details/json?' . http_build_query($params, '', '&');

		$response = wp_remote_get($url, array(
			'timeout' => 10,
			'headers' => array('Referer' => home_url())
		));

		if (is_wp_error($response)) {
			return array(
				'success' => false,
				'message' => $response->get_error_message()
			);
		}

		if ($response['response']['code'] !== 200) {
			return array(
				'success' => false,
				'message' => $response['response']['code'] . ' ' . $response['response']['message']
			);
		}

		$body = json_decode($response['body'], true);
		if (!isset($body['status']) || $body['status'] !== 'OK' || !isset($body['result']) || !is_array($body['result'])) {
			return array(
				'success' => false,
				'message' => esc_html__('Invalid response', 'mmp')
			);
		}

		return array(
			'success' => true,
			'address' => $body['result']['formatted_address'],
			'lat'     => floatval($body['result']['geometry']['location']['lat']),
			'lon'     => floatval($body['result']['geometry']['location']['lng'])
		);
	}
}
