<?php
/**
 * Google Maps JavaScript API provider (Pro per ADR-11).
 *
 * Loads Maps JS API with the configured key + MarkerClusterer.
 * Renders a placeholder with JSON config; the boot script
 * (assets/js/maps-frontend.js) initialises both providers.
 *
 * @package ThemeREX\AutoDealer
 */

declare(strict_types=1);

namespace ThemeREX\AutoDealer\Integrations\Maps;

use ThemeREX\AutoDealer\Admin\AdminSettings;

final class GoogleMapsProvider implements MapProviderInterface {

	public const HANDLE_API     = 'trx-ad-google-maps';
	public const HANDLE_CLUSTER = 'trx-ad-google-markerclusterer';
	public const HANDLE_BOOT    = 'trx-ad-maps-frontend';

	private const API_VERSION     = 'weekly';
	private const CLUSTER_VERSION = '2.5.3';

	public function enqueueAssets(): void {
		if ( ! defined( 'TRX_AD_URL' ) || ! defined( 'TRX_AD_VERSION' ) ) {
			return;
		}

		$key = trim( (string) AdminSettings::get( 'google_maps_api_key', '' ) );
		if ( '' === $key ) {
			// Without a key the API will refuse to load — skip rather than
			// queueing a broken script tag. The render() output still emits
			// the placeholder so admins see exactly where the map *would* be.
			return;
		}

		$apiUrl = add_query_arg(
			array(
				'key'     => $key,
				'v'       => self::API_VERSION,
				'loading' => 'async',
			),
			'https://maps.googleapis.com/maps/api/js'
		);

		wp_register_script(
			self::HANDLE_API,
			$apiUrl,
			array(),
			null, // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter,WordPress.WP.EnqueuedResourceParameters.MissingVersion
			true
		);

		// Google's official MarkerClusterer (@googlemaps/markerclusterer)
		// is self-hosted under assets/js/vendor/ per WP.org plugin-handbook
		// rules — see assets/js/vendor/README.md for the upstream source.
		wp_register_script(
			self::HANDLE_CLUSTER,
			TRX_AD_URL . 'assets/js/vendor/markerclusterer.min.js',
			array( self::HANDLE_API ),
			self::CLUSTER_VERSION,
			true
		);

		wp_register_script(
			self::HANDLE_BOOT,
			TRX_AD_URL . 'assets/js/maps-frontend.js',
			array( self::HANDLE_API ),
			(string) TRX_AD_VERSION,
			true
		);

		wp_enqueue_script( self::HANDLE_API );

		if ( $this->clusterEnabled() ) {
			wp_enqueue_script( self::HANDLE_CLUSTER );
		}

		wp_enqueue_script( self::HANDLE_BOOT );
	}

	/**
	 * @param array<string, mixed> $args
	 */
	public function render( array $args ): string {
		$this->enqueueAssets();

		$pins   = isset( $args['pins'] ) && is_array( $args['pins'] ) ? array_values( array_filter( $args['pins'], array( $this, 'isValidPin' ) ) ) : array();
		$id     = isset( $args['id'] ) ? sanitize_html_class( (string) $args['id'] ) : 'trx-ad-map-' . wp_generate_uuid4();
		$height = isset( $args['height'] ) ? (string) $args['height'] : '400px';
		$zoom   = isset( $args['zoom'] ) ? (int) $args['zoom'] : (int) AdminSettings::get( 'map_default_zoom', 12 );

		$cluster = array_key_exists( 'cluster', $args )
			? (bool) $args['cluster']
			: $this->clusterEnabled();

		$center = array( 0.0, 0.0 );
		if ( isset( $args['center']['lat'], $args['center']['lng'] ) ) {
			$center = array( (float) $args['center']['lat'], (float) $args['center']['lng'] );
		} elseif ( ! empty( $pins ) ) {
			$center = array( (float) $pins[0]['lat'], (float) $pins[0]['lng'] );
		}

		$config = array(
			'provider' => 'google',
			'center'   => array(
				'lat' => $center[0],
				'lng' => $center[1],
			),
			'zoom'     => max( 1, min( 20, $zoom ) ),
			'cluster'  => $cluster,
			'pins'     => array_map( array( $this, 'normalizePin' ), $pins ),
		);

		$keyMissing = '' === trim( (string) AdminSettings::get( 'google_maps_api_key', '' ) );

		$placeholder = sprintf(
			'<div class="trx-ad-map trx-ad-map--google" id="%1$s" data-trx-ad-map="%2$s" style="height:%3$s;width:100%%;"></div>',
			esc_attr( $id ),
			esc_attr( (string) wp_json_encode( $config ) ),
			esc_attr( $height )
		);

		if ( $keyMissing && current_user_can( 'manage_options' ) ) {
			$placeholder .= sprintf(
				'<p class="trx-ad-map__notice"><em>%s</em></p>',
				esc_html__( 'Google Maps API key not configured. Set one in Settings → Maps to render the map.', 'trx-auto-dealer' )
			);
		}

		return $placeholder;
	}

	/**
	 * @param mixed $pin
	 */
	private function isValidPin( $pin ): bool {
		if ( ! is_array( $pin ) ) {
			return false;
		}
		if ( ! isset( $pin['lat'], $pin['lng'] ) ) {
			return false;
		}
		$lat = (float) $pin['lat'];
		$lng = (float) $pin['lng'];
		return $lat >= -90 && $lat <= 90 && $lng >= -180 && $lng <= 180 && ! ( 0.0 === $lat && 0.0 === $lng );
	}

	/**
	 * @param array<string, mixed> $pin
	 * @return array{lat:float,lng:float,title:string,content:string,url:string}
	 */
	private function normalizePin( array $pin ): array {
		return array(
			'lat'     => (float) $pin['lat'],
			'lng'     => (float) $pin['lng'],
			'title'   => isset( $pin['title'] ) ? wp_strip_all_tags( (string) $pin['title'] ) : '',
			'content' => isset( $pin['content'] ) ? wp_kses_post( (string) $pin['content'] ) : '',
			'url'     => isset( $pin['url'] ) ? esc_url_raw( (string) $pin['url'] ) : '',
		);
	}

	private function clusterEnabled(): bool {
		return (bool) AdminSettings::get( 'map_cluster', 1 );
	}
}
