<?php
/**
 * Admin UI: lat/lng meta box, list-table column, help screen.
 */

defined( 'ABSPATH' ) || exit;

class BW_Map_Magnet_Admin {

	private static $instance = null;

	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	public function boot() {
		add_action( 'add_meta_boxes', [ $this, 'register_meta_box' ] );
		add_action( 'save_post_' . BW_MAP_MAGNET_CPT, [ $this, 'save_meta_box' ], 10, 2 );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin' ] );
		add_action( 'wp_ajax_bw_map_magnet_gmaps_lookup', [ $this, 'ajax_gmaps_lookup' ] );
		add_filter( 'manage_' . BW_MAP_MAGNET_CPT . '_posts_columns', [ $this, 'add_columns' ] );
		add_action( 'manage_' . BW_MAP_MAGNET_CPT . '_posts_custom_column', [ $this, 'render_column' ], 10, 2 );
		add_action( 'admin_menu', [ $this, 'register_help_page' ] );

		// Taxonomy term icon picker.
		add_action( BW_MAP_MAGNET_TAX . '_add_form_fields', [ $this, 'render_term_add_fields' ] );
		add_action( BW_MAP_MAGNET_TAX . '_edit_form_fields', [ $this, 'render_term_edit_fields' ], 10, 2 );
		add_action( 'created_' . BW_MAP_MAGNET_TAX, [ $this, 'save_term_meta' ] );
		add_action( 'edited_' . BW_MAP_MAGNET_TAX, [ $this, 'save_term_meta' ] );

		add_filter( 'manage_edit-' . BW_MAP_MAGNET_TAX . '_columns', [ $this, 'add_term_columns' ] );
		add_filter( 'manage_' . BW_MAP_MAGNET_TAX . '_custom_column', [ $this, 'render_term_column' ], 10, 3 );
	}

	public function register_meta_box() {
		add_meta_box(
			'bw_map_magnet_location',
			__( 'Map Location', 'bw-map-magnet' ),
			[ $this, 'render_meta_box' ],
			BW_MAP_MAGNET_CPT,
			'normal',
			'high'
		);
	}

	public function render_meta_box( $post ) {
		wp_nonce_field( 'bw_map_magnet_save_location', 'bw_map_magnet_location_nonce' );
		$lat       = get_post_meta( $post->ID, '_bw_map_lat', true );
		$lng       = get_post_meta( $post->ID, '_bw_map_lng', true );
		$image_url = get_post_meta( $post->ID, '_bw_map_image_url', true );
		?>
		<p class="description">
			<?php esc_html_e( 'Click on the map to set the location, or paste latitude/longitude coordinates below. Drag the marker to fine-tune.', 'bw-map-magnet' ); ?>
		</p>
		<div class="bw-mm-admin-fields">
			<label>
				<span><?php esc_html_e( 'Latitude', 'bw-map-magnet' ); ?></span>
				<input type="text" name="bw_map_lat" id="bw-mm-lat" value="<?php echo esc_attr( $lat ); ?>" placeholder="49.2828" />
			</label>
			<label>
				<span><?php esc_html_e( 'Longitude', 'bw-map-magnet' ); ?></span>
				<input type="text" name="bw_map_lng" id="bw-mm-lng" value="<?php echo esc_attr( $lng ); ?>" placeholder="-124.6691" />
			</label>
			<label class="bw-mm-search-wrap">
				<span><?php esc_html_e( 'Search a place', 'bw-map-magnet' ); ?></span>
				<input type="search" id="bw-mm-search" placeholder="<?php esc_attr_e( 'e.g. Grace Bay, Turks and Caicos', 'bw-map-magnet' ); ?>" />
				<button type="button" class="button" id="bw-mm-search-btn"><?php esc_html_e( 'Find', 'bw-map-magnet' ); ?></button>
			</label>
		</div>
		<div id="bw-mm-admin-map" style="width:100%;height:380px;margin-top:10px;border:1px solid #ccd0d4;border-radius:4px;"></div>
		<p class="description" style="margin-top:6px;">
			<?php esc_html_e( 'Tip: the most accurate way to set a location is to paste a Google Maps URL below. Open the place in Google Maps, click "Share" → "Copy link", and paste it here.', 'bw-map-magnet' ); ?>
		</p>
		<div class="bw-mm-gmaps-row">
			<label class="bw-mm-gmaps-label">
				<span><?php esc_html_e( 'Fetch by Google Maps URL', 'bw-map-magnet' ); ?></span>
				<input type="url" id="bw-mm-gmaps-url" placeholder="https://maps.app.goo.gl/... or https://www.google.com/maps/place/..." />
			</label>
			<button type="button" class="button button-secondary" id="bw-mm-gmaps-btn"><?php esc_html_e( 'Fetch location', 'bw-map-magnet' ); ?></button>
			<span id="bw-mm-gmaps-status" class="bw-mm-gmaps-status" aria-live="polite"></span>
		</div>
		<p style="margin-top:14px;">
			<label style="display:block;font-weight:600;margin-bottom:4px;">
				<?php esc_html_e( 'Image URL (optional, overrides featured image)', 'bw-map-magnet' ); ?>
			</label>
			<input type="url" name="bw_map_image_url" value="<?php echo esc_attr( $image_url ); ?>" placeholder="https://example.com/photo.jpg" style="width:100%;max-width:560px;" />
			<span class="description" style="display:block;margin-top:4px;">
				<?php esc_html_e( 'Use this to point at an external image (CDN, stock photo) without uploading. Leave blank to use the featured image.', 'bw-map-magnet' ); ?>
			</span>
		</p>
		<p style="margin-top:14px;">
			<?php
			$focus_zoom_meta = get_post_meta( $post->ID, '_bw_map_focus_zoom', true );
			$default_zoom    = (int) BW_Map_Magnet_Settings::get( 'default_zoom' );
			?>
			<label style="display:block;font-weight:600;margin-bottom:4px;">
				<?php esc_html_e( 'Override hover zoom level (optional)', 'bw-map-magnet' ); ?>
			</label>
			<input type="number" name="bw_map_focus_zoom" value="<?php echo esc_attr( $focus_zoom_meta ); ?>" min="6" max="19" step="1" style="width:120px;" placeholder="<?php echo esc_attr( $default_zoom ); ?>" />
			<span class="description" style="display:block;margin-top:4px;">
				<?php
				printf(
					/* translators: %d: current site-wide default */
					esc_html__( 'Leave blank to use the site default (currently %d). Use a higher number for tight spots (a specific restaurant) or lower for spread-out places (a long beach).', 'bw-map-magnet' ),
					(int) $default_zoom
				);
				?>
			</span>
		</p>
		<?php
	}

	public function save_meta_box( $post_id, $post ) {
		if ( ! isset( $_POST['bw_map_magnet_location_nonce'] ) ) {
			return;
		}
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['bw_map_magnet_location_nonce'] ) ), 'bw_map_magnet_save_location' ) ) {
			return;
		}
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}

		foreach ( [ 'lat' => '_bw_map_lat', 'lng' => '_bw_map_lng' ] as $field => $meta_key ) {
			$key = 'bw_map_' . $field;
			if ( isset( $_POST[ $key ] ) ) {
				$raw = sanitize_text_field( wp_unslash( $_POST[ $key ] ) );
				if ( '' === $raw ) {
					delete_post_meta( $post_id, $meta_key );
				} else {
					$value = (float) $raw;
					update_post_meta( $post_id, $meta_key, $value );
				}
			}
		}

		if ( isset( $_POST['bw_map_image_url'] ) ) {
			$raw = esc_url_raw( wp_unslash( $_POST['bw_map_image_url'] ) );
			if ( '' === $raw ) {
				delete_post_meta( $post_id, '_bw_map_image_url' );
			} else {
				update_post_meta( $post_id, '_bw_map_image_url', $raw );
			}
		}

		if ( isset( $_POST['bw_map_focus_zoom'] ) ) {
			$raw = sanitize_text_field( wp_unslash( $_POST['bw_map_focus_zoom'] ) );
			if ( '' === $raw ) {
				delete_post_meta( $post_id, '_bw_map_focus_zoom' );
			} else {
				$z = (int) $raw;
				$z = max( 6, min( 19, $z ) );
				update_post_meta( $post_id, '_bw_map_focus_zoom', $z );
			}
		}
	}

	public function render_term_add_fields() {
		wp_nonce_field( 'bw_map_magnet_save_term', 'bw_map_magnet_term_nonce' );
		?>
		<div class="form-field bw-mm-term-icon-field">
			<label><?php esc_html_e( 'Icon', 'bw-map-magnet' ); ?></label>
			<?php $this->render_icon_picker( '' ); ?>
			<p><?php esc_html_e( 'Choose an icon for this category. Used on the map markers and the filter buttons.', 'bw-map-magnet' ); ?></p>
		</div>
		<div class="form-field bw-mm-term-color-field">
			<label for="bw-mm-term-color-input"><?php esc_html_e( 'Color', 'bw-map-magnet' ); ?></label>
			<input type="text" class="bw-mm-color-picker" id="bw-mm-term-color-input" name="bw_map_color" value="" data-default-color="#2563eb" />
			<p><?php esc_html_e( 'Marker, chip, and accent color for this category. Leave blank for the default blue.', 'bw-map-magnet' ); ?></p>
		</div>
		<?php
	}

	public function render_term_edit_fields( $term ) {
		wp_nonce_field( 'bw_map_magnet_save_term', 'bw_map_magnet_term_nonce' );
		$current_icon  = BW_Map_Magnet_Icons::get_term_icon( $term->term_id );
		$current_color = get_term_meta( $term->term_id, '_bw_map_color', true );
		?>
		<tr class="form-field bw-mm-term-icon-field">
			<th scope="row"><label><?php esc_html_e( 'Icon', 'bw-map-magnet' ); ?></label></th>
			<td>
				<?php $this->render_icon_picker( $current_icon ); ?>
				<p class="description"><?php esc_html_e( 'Choose an icon for this category. Used on the map markers and the filter buttons.', 'bw-map-magnet' ); ?></p>
			</td>
		</tr>
		<tr class="form-field bw-mm-term-color-field">
			<th scope="row"><label for="bw-mm-term-color-input"><?php esc_html_e( 'Color', 'bw-map-magnet' ); ?></label></th>
			<td>
				<input type="text" class="bw-mm-color-picker" id="bw-mm-term-color-input" name="bw_map_color" value="<?php echo esc_attr( $current_color ); ?>" data-default-color="#2563eb" />
				<p class="description"><?php esc_html_e( 'Marker, chip, and accent color for this category. Leave blank for the default blue.', 'bw-map-magnet' ); ?></p>
			</td>
		</tr>
		<?php
	}

	private function render_icon_picker( $current_key ) {
		$library = BW_Map_Magnet_Icons::library();
		echo '<input type="hidden" name="bw_map_icon" id="bw-mm-term-icon-input" value="' . esc_attr( $current_key ) . '" />';
		echo '<div class="bw-mm-icon-grid" role="radiogroup" aria-label="' . esc_attr__( 'Category icon', 'bw-map-magnet' ) . '">';
		foreach ( $library as $key => $entry ) {
			$active = ( $key === $current_key ) ? ' is-active' : '';
			echo '<button type="button" class="bw-mm-icon-tile' . esc_attr( $active ) . '" data-bw-mm-icon-key="' . esc_attr( $key ) . '" aria-label="' . esc_attr( $entry['label'] ) . '" title="' . esc_attr( $entry['label'] ) . '">';
			echo BW_Map_Magnet_Icons::render( $key, 22, 'bw-mm-icon' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo '<span class="bw-mm-icon-tile-label">' . esc_html( $entry['label'] ) . '</span>';
			echo '</button>';
		}
		echo '</div>';
	}

	public function save_term_meta( $term_id ) {
		if ( ! isset( $_POST['bw_map_magnet_term_nonce'] ) ) {
			return;
		}
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['bw_map_magnet_term_nonce'] ) ), 'bw_map_magnet_save_term' ) ) {
			return;
		}
		if ( ! current_user_can( 'manage_categories' ) ) {
			return;
		}

		if ( isset( $_POST['bw_map_icon'] ) ) {
			$raw = sanitize_key( wp_unslash( $_POST['bw_map_icon'] ) );
			if ( '' === $raw ) {
				delete_term_meta( $term_id, '_bw_map_icon' );
			} elseif ( BW_Map_Magnet_Icons::exists( $raw ) ) {
				update_term_meta( $term_id, '_bw_map_icon', $raw );
			}
		}

		if ( isset( $_POST['bw_map_color'] ) ) {
			$raw   = sanitize_text_field( wp_unslash( $_POST['bw_map_color'] ) );
			$valid = ( '' === $raw ) ? '' : sanitize_hex_color( $raw );
			if ( '' === $valid ) {
				delete_term_meta( $term_id, '_bw_map_color' );
			} else {
				update_term_meta( $term_id, '_bw_map_color', $valid );
			}
		}
	}

	public function add_term_columns( $columns ) {
		$new = [];
		foreach ( $columns as $k => $v ) {
			if ( 'name' === $k ) {
				$new['bw_mm_icon'] = __( 'Icon', 'bw-map-magnet' );
			}
			$new[ $k ] = $v;
		}
		return $new;
	}

	public function render_term_column( $content, $column, $term_id ) {
		if ( 'bw_mm_icon' !== $column ) {
			return $content;
		}
		return BW_Map_Magnet_Icons::render( BW_Map_Magnet_Icons::get_term_icon( $term_id ), 20 );
	}

	public function enqueue_admin( $hook ) {
		$screen = get_current_screen();
		if ( ! $screen ) {
			return;
		}

		$is_edit_screen     = ( BW_MAP_MAGNET_CPT === $screen->post_type ) && in_array( $hook, [ 'post.php', 'post-new.php' ], true );
		$is_help_screen     = ( strpos( $hook, 'bw-map-magnet-help' ) !== false );
		$is_term_screen     = isset( $screen->taxonomy ) && BW_MAP_MAGNET_TAX === $screen->taxonomy;
		$is_settings_screen = ( strpos( $hook, 'bw-map-magnet-settings' ) !== false );

		if ( ! $is_edit_screen && ! $is_help_screen && ! $is_term_screen && ! $is_settings_screen ) {
			return;
		}

		wp_enqueue_style(
			'bw-mm-admin',
			BW_MAP_MAGNET_URL . 'assets/css/bw-map-magnet-admin.css',
			[],
			BW_MAP_MAGNET_VERSION
		);

		if ( $is_edit_screen ) {
			wp_enqueue_style(
				'bw-mm-leaflet',
				'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css',
				[],
				'1.9.4'
			);
			wp_enqueue_script(
				'bw-mm-leaflet',
				'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',
				[],
				'1.9.4',
				true
			);
			wp_enqueue_script(
				'bw-mm-admin',
				BW_MAP_MAGNET_URL . 'assets/js/bw-map-magnet-admin.js',
				[ 'bw-mm-leaflet', 'jquery' ],
				BW_MAP_MAGNET_VERSION,
				true
			);
			wp_localize_script( 'bw-mm-admin', 'BwMapMagnetAdmin', [
				'ajaxurl'    => admin_url( 'admin-ajax.php' ),
				'gmapsNonce' => wp_create_nonce( 'bw_map_magnet_gmaps' ),
				'i18n'       => [
					'fetching'  => __( 'Looking up…', 'bw-map-magnet' ),
					'success'   => __( 'Location set.', 'bw-map-magnet' ),
					'no_url'    => __( 'Please paste a Google Maps URL first.', 'bw-map-magnet' ),
					'network'   => __( 'Network error.', 'bw-map-magnet' ),
				],
			] );
		}

		if ( $is_term_screen ) {
			wp_enqueue_style( 'wp-color-picker' );
			wp_enqueue_script(
				'bw-mm-taxonomy',
				BW_MAP_MAGNET_URL . 'assets/js/bw-map-magnet-taxonomy.js',
				[ 'jquery', 'wp-color-picker' ],
				BW_MAP_MAGNET_VERSION,
				true
			);
		}

		if ( $is_settings_screen ) {
			wp_enqueue_media();
			wp_enqueue_style( 'wp-color-picker' );
			wp_enqueue_style(
				'bw-mm-leaflet',
				'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css',
				[],
				'1.9.4'
			);
			wp_enqueue_script(
				'bw-mm-leaflet',
				'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',
				[],
				'1.9.4',
				true
			);
			wp_enqueue_script(
				'bw-mm-settings',
				BW_MAP_MAGNET_URL . 'assets/js/bw-map-magnet-settings.js',
				[ 'jquery', 'wp-color-picker', 'bw-mm-leaflet' ],
				BW_MAP_MAGNET_VERSION,
				true
			);
			wp_localize_script( 'bw-mm-settings', 'BwMapMagnetAdmin', [
				'ajaxurl'    => admin_url( 'admin-ajax.php' ),
				'gmapsNonce' => wp_create_nonce( 'bw_map_magnet_gmaps' ),
				'i18n'       => [
					'fetching' => __( 'Looking up…', 'bw-map-magnet' ),
					'success'  => __( 'Location set.', 'bw-map-magnet' ),
					'no_url'   => __( 'Please paste a Google Maps URL first.', 'bw-map-magnet' ),
					'network'  => __( 'Network error.', 'bw-map-magnet' ),
				],
			] );
		}
	}

	public function add_columns( $columns ) {
		$new = [];
		foreach ( $columns as $key => $label ) {
			$new[ $key ] = $label;
			if ( 'title' === $key ) {
				$new['bw_mm_coords'] = __( 'Coordinates', 'bw-map-magnet' );
			}
		}
		return $new;
	}

	public function render_column( $column, $post_id ) {
		if ( 'bw_mm_coords' !== $column ) {
			return;
		}
		$lat = get_post_meta( $post_id, '_bw_map_lat', true );
		$lng = get_post_meta( $post_id, '_bw_map_lng', true );
		if ( '' === $lat || '' === $lng ) {
			echo '<em style="color:#a00;">' . esc_html__( 'not set', 'bw-map-magnet' ) . '</em>';
		} else {
			echo esc_html( number_format( (float) $lat, 4 ) . ', ' . number_format( (float) $lng, 4 ) );
		}
	}

	public function register_help_page() {
		add_submenu_page(
			'edit.php?post_type=' . BW_MAP_MAGNET_CPT,
			__( 'Map Magnet Help', 'bw-map-magnet' ),
			__( 'Help & Demo Data', 'bw-map-magnet' ),
			'manage_options',
			'bw-map-magnet-help',
			[ $this, 'render_help_page' ]
		);
	}

	public function render_help_page() {
		$seeded = (bool) get_option( 'bw_map_magnet_demo_seeded', false );
		?>
		<div class="wrap">
			<h1><?php esc_html_e( 'BW Map Magnet — Help', 'bw-map-magnet' ); ?></h1>

			<h2><?php esc_html_e( 'Using the shortcode', 'bw-map-magnet' ); ?></h2>
			<p><?php esc_html_e( 'Embed a map anywhere with the shortcode:', 'bw-map-magnet' ); ?></p>
			<p><code>[bw_map_magnet]</code></p>
			<p><?php esc_html_e( 'Optional attributes:', 'bw-map-magnet' ); ?></p>
			<ul style="list-style: disc; margin-left: 20px;">
				<li><code>category="best-restaurants,free-outdoor-activities"</code> — <?php esc_html_e( 'comma-separated category slugs to filter', 'bw-map-magnet' ); ?></li>
				<li><code>height="600"</code> — <?php esc_html_e( 'map height in pixels (default 600)', 'bw-map-magnet' ); ?></li>
				<li><code>zoom="9"</code> — <?php esc_html_e( 'fallback default zoom (default uses fit-bounds)', 'bw-map-magnet' ); ?></li>
				<li><code>focus_zoom="14"</code> — <?php esc_html_e( 'zoom level when an item is hovered (default 14)', 'bw-map-magnet' ); ?></li>
			</ul>

			<h2><?php esc_html_e( 'Demo data', 'bw-map-magnet' ); ?></h2>
			<p><?php esc_html_e( 'Seed example map items for Vancouver Island (Free Outdoor Activities and Best Restaurants). Use this to evaluate the plugin or as a template for your own content.', 'bw-map-magnet' ); ?></p>
			<form method="post">
				<?php wp_nonce_field( 'bw_map_magnet_seed', 'bw_map_magnet_seed_nonce' ); ?>
				<input type="hidden" name="bw_map_magnet_action" value="seed" />
				<?php submit_button(
					$seeded ? __( 'Re-seed Vancouver Island demo data', 'bw-map-magnet' ) : __( 'Seed Vancouver Island demo data', 'bw-map-magnet' ),
					'primary',
					'submit',
					false
				); ?>
				<?php if ( $seeded ) : ?>
					<p class="description" style="margin-top:8px;">
						<?php esc_html_e( 'Demo data has been seeded before. Re-seeding skips items that already exist (matched by title).', 'bw-map-magnet' ); ?>
					</p>
				<?php endif; ?>
			</form>

			<h2><?php esc_html_e( 'How the hover interaction works', 'bw-map-magnet' ); ?></h2>
			<ol style="list-style: decimal; margin-left: 20px;">
				<li><?php esc_html_e( 'On load, the map fits to show every item.', 'bw-map-magnet' ); ?></li>
				<li><?php esc_html_e( 'Hovering an item in the list flies to that marker.', 'bw-map-magnet' ); ?></li>
				<li><?php esc_html_e( 'When you stop hovering, the map smoothly zooms back out to fit all items.', 'bw-map-magnet' ); ?></li>
				<li><?php esc_html_e( 'Clicking an item opens its popup and stays focused until clicked again.', 'bw-map-magnet' ); ?></li>
			</ol>
		</div>
		<?php
	}

	/**
	 * AJAX: extract lat/lng from a pasted Google Maps URL.
	 * Returns { lat, lng, source } on success.
	 */
	public function ajax_gmaps_lookup() {
		if ( ! check_ajax_referer( 'bw_map_magnet_gmaps', 'nonce', false ) ) {
			wp_send_json_error( [ 'message' => __( 'Security check failed. Reload the page and try again.', 'bw-map-magnet' ) ], 403 );
		}
		if ( ! current_user_can( 'edit_posts' ) ) {
			wp_send_json_error( [ 'message' => __( 'Permission denied.', 'bw-map-magnet' ) ], 403 );
		}

		$url = isset( $_POST['url'] ) ? esc_url_raw( wp_unslash( $_POST['url'] ) ) : '';
		if ( '' === $url ) {
			wp_send_json_error( [ 'message' => __( 'No URL provided.', 'bw-map-magnet' ) ] );
		}

		$host = wp_parse_url( $url, PHP_URL_HOST );
		$allowed_hosts = [ 'maps.app.goo.gl', 'goo.gl', 'g.co', 'maps.google.com', 'www.google.com', 'google.com' ];
		if ( ! $host || ! in_array( strtolower( $host ), $allowed_hosts, true ) ) {
			wp_send_json_error( [ 'message' => __( 'That doesn\'t look like a Google Maps URL. Paste a link copied from Google Maps "Share".', 'bw-map-magnet' ) ] );
		}

		$coords = $this->extract_gmaps_coords( $url );
		if ( ! $coords ) {
			wp_send_json_error( [ 'message' => __( 'Could not extract coordinates from that URL. Try opening the place in Google Maps, clicking Share → Copy link, and pasting that.', 'bw-map-magnet' ) ] );
		}

		wp_send_json_success( $coords );
	}

	/**
	 * Try parsing the URL directly first; if that fails, fetch the URL and parse the response body
	 * (handles maps.app.goo.gl short URLs that redirect through HTML).
	 */
	private function extract_gmaps_coords( $url ) {
		$direct = $this->parse_gmaps_text( $url );
		if ( $direct ) {
			return $direct;
		}

		$response = wp_safe_remote_get( $url, [
			'timeout'     => 12,
			'redirection' => 5,
			'user-agent'  => 'Mozilla/5.0 (compatible; BW-Map-Magnet/' . BW_MAP_MAGNET_VERSION . ')',
		] );
		if ( is_wp_error( $response ) ) {
			return null;
		}

		$body = wp_remote_retrieve_body( $response );
		if ( ! $body ) {
			return null;
		}

		return $this->parse_gmaps_text( $body );
	}

	/**
	 * Pull lat/lng out of a Google Maps URL or response body.
	 * Tries the most accurate patterns first.
	 */
	private function parse_gmaps_text( $text ) {
		// !3dLAT!4dLNG — the actual placed-pin position. Most accurate.
		if ( preg_match( '/!3d(-?\d+\.\d+)!4d(-?\d+\.\d+)/', $text, $m ) ) {
			$c = $this->normalise_coords( $m[1], $m[2] );
			if ( $c ) {
				$c['source'] = 'pin';
				return $c;
			}
		}
		// @LAT,LNG — map center.
		if ( preg_match( '/@(-?\d+\.\d+),(-?\d+\.\d+)(?:,|$|\?|&|\/)/', $text, $m ) ) {
			$c = $this->normalise_coords( $m[1], $m[2] );
			if ( $c ) {
				$c['source'] = 'center';
				return $c;
			}
		}
		// ?q=LAT,LNG or &q=LAT,LNG (URL-encoded comma %2C too).
		if ( preg_match( '/[?&]q=(-?\d+\.\d+)(?:,|%2[Cc])(-?\d+\.\d+)/', $text, $m ) ) {
			$c = $this->normalise_coords( $m[1], $m[2] );
			if ( $c ) {
				$c['source'] = 'query';
				return $c;
			}
		}
		// /search/LAT,LNG (some Google Maps URLs)
		if ( preg_match( '/\/search\/(-?\d+\.\d+)(?:,|%2[Cc]|\+)(-?\d+\.\d+)/', $text, $m ) ) {
			$c = $this->normalise_coords( $m[1], $m[2] );
			if ( $c ) {
				$c['source'] = 'search';
				return $c;
			}
		}
		return null;
	}

	private function normalise_coords( $lat, $lng ) {
		$lat = (float) $lat;
		$lng = (float) $lng;
		if ( $lat < -90 || $lat > 90 || $lng < -180 || $lng > 180 ) {
			return null;
		}
		if ( 0.0 === $lat && 0.0 === $lng ) {
			return null;
		}
		return [ 'lat' => $lat, 'lng' => $lng ];
	}
}
