<?php
/**
 * Shortcode + frontend asset enqueueing for BW Map Magnet.
 */

defined( 'ABSPATH' ) || exit;

class BW_Map_Magnet_Shortcode {

	private static $instance = null;

	private $assets_needed = false;

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

	public function boot() {
		add_shortcode( 'bw_map_magnet', [ $this, 'render' ] );
		add_action( 'wp_enqueue_scripts', [ $this, 'register_assets' ] );
		add_action( 'wp_footer', [ $this, 'maybe_enqueue_assets' ] );
	}

	public function register_assets() {
		wp_register_style(
			'bw-mm-leaflet',
			'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css',
			[],
			'1.9.4'
		);
		wp_register_script(
			'bw-mm-leaflet',
			'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',
			[],
			'1.9.4',
			true
		);
		wp_register_style(
			'bw-map-magnet',
			BW_MAP_MAGNET_URL . 'assets/css/bw-map-magnet.css',
			[ 'bw-mm-leaflet' ],
			BW_MAP_MAGNET_VERSION
		);
		wp_register_script(
			'bw-map-magnet',
			BW_MAP_MAGNET_URL . 'assets/js/bw-map-magnet.js',
			[ 'bw-mm-leaflet' ],
			BW_MAP_MAGNET_VERSION,
			true
		);
		wp_localize_script( 'bw-map-magnet', 'BwMapMagnetIcons', BW_Map_Magnet_Icons::js_map() );
	}

	public function maybe_enqueue_assets() {
		if ( ! $this->assets_needed ) {
			return;
		}
		wp_enqueue_style( 'bw-map-magnet' );
		wp_enqueue_script( 'bw-map-magnet' );
	}

	/**
	 * Mark assets as needed (called by the block renderer too).
	 */
	public function require_assets() {
		$this->assets_needed = true;
	}

	public function render( $atts ) {
		$default_zoom  = (int) BW_Map_Magnet_Settings::get( 'default_zoom' );
		$anim_duration = (float) BW_Map_Magnet_Settings::get( 'anim_duration' );

		$atts = shortcode_atts(
			[
				'category'   => '',
				'height'     => '600',
				'zoom'       => '',
				'focus_zoom' => (string) $default_zoom,
				'limit'      => '-1',
				'filter'     => 'true',
			],
			$atts,
			'bw_map_magnet'
		);

		$query_args = [
			'post_type'      => BW_MAP_MAGNET_CPT,
			'posts_per_page' => (int) $atts['limit'],
			'orderby'        => [ 'menu_order' => 'ASC', 'title' => 'ASC' ],
			'meta_query'     => [
				'relation' => 'AND',
				[
					'key'     => '_bw_map_lat',
					'compare' => 'EXISTS',
				],
				[
					'key'     => '_bw_map_lng',
					'compare' => 'EXISTS',
				],
			],
		];

		if ( ! empty( $atts['category'] ) ) {
			$slugs                  = array_filter( array_map( 'sanitize_title', array_map( 'trim', explode( ',', $atts['category'] ) ) ) );
			$query_args['tax_query'] = [
				[
					'taxonomy' => BW_MAP_MAGNET_TAX,
					'field'    => 'slug',
					'terms'    => $slugs,
				],
			];
		}

		$query = new WP_Query( $query_args );

		if ( ! $query->have_posts() ) {
			return '<div class="bw-mm-empty">' . esc_html__( 'No map items have been added yet.', 'bw-map-magnet' ) . '</div>';
		}

		$items_by_category = [];
		$categories_index  = [];
		$all_items         = [];

		while ( $query->have_posts() ) {
			$query->the_post();
			$post_id = get_the_ID();
			$lat     = get_post_meta( $post_id, '_bw_map_lat', true );
			$lng     = get_post_meta( $post_id, '_bw_map_lng', true );
			if ( '' === $lat || '' === $lng ) {
				continue;
			}

			$terms     = get_the_terms( $post_id, BW_MAP_MAGNET_TAX );
			$cat_name  = __( 'Locations', 'bw-map-magnet' );
			$cat_slug  = 'uncategorised';
			$cat_icon  = BW_Map_Magnet_Icons::DEFAULT_KEY;
			$cat_color = '';
			if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
				$cat_name  = $terms[0]->name;
				$cat_slug  = $terms[0]->slug;
				$cat_icon  = BW_Map_Magnet_Icons::get_term_icon( $terms[0]->term_id );
				$cat_color = get_term_meta( $terms[0]->term_id, '_bw_map_color', true );
			}
			if ( '' === $cat_color ) {
				$cat_color = '#2563eb';
			}

			$image_url = get_post_meta( $post_id, '_bw_map_image_url', true );
			if ( ! $image_url && has_post_thumbnail( $post_id ) ) {
				$image_url = get_the_post_thumbnail_url( $post_id, 'medium' );
			}

			$excerpt = has_excerpt( $post_id ) ? get_the_excerpt( $post_id ) : wp_trim_words( get_the_content(), 24, '…' );

			$item_zoom = get_post_meta( $post_id, '_bw_map_focus_zoom', true );

			// Decode HTML entities (wptexturize turns straight apostrophes into &#8217; etc.) before
			// emitting to JSON — the frontend's escapeHtml() will re-escape on insertion. Without this,
			// popup titles render as literal "Smith&#8217;s" because the leading & gets double-escaped.
			$item = [
				'id'       => $post_id,
				'title'    => html_entity_decode( get_the_title(), ENT_QUOTES, 'UTF-8' ),
				'lat'      => (float) $lat,
				'lng'      => (float) $lng,
				'excerpt'  => html_entity_decode( wp_strip_all_tags( $excerpt ), ENT_QUOTES, 'UTF-8' ),
				'thumb'    => $image_url ? $image_url : '',
				'category' => $cat_slug,
				'icon'     => $cat_icon,
				'color'    => $cat_color,
			];
			if ( '' !== $item_zoom && is_numeric( $item_zoom ) ) {
				$item['focusZoom'] = (float) $item_zoom;
			}

			$all_items[] = $item;

			if ( ! isset( $items_by_category[ $cat_slug ] ) ) {
				$items_by_category[ $cat_slug ] = [
					'name'  => $cat_name,
					'slug'  => $cat_slug,
					'icon'  => $cat_icon,
					'color' => $cat_color,
					'items' => [],
				];
			}
			$items_by_category[ $cat_slug ]['items'][] = $item;

			if ( ! isset( $categories_index[ $cat_slug ] ) ) {
				$categories_index[ $cat_slug ] = [
					'slug'  => $cat_slug,
					'name'  => $cat_name,
					'icon'  => $cat_icon,
					'color' => $cat_color,
					'count' => 0,
				];
			}
			$categories_index[ $cat_slug ]['count']++;
		}
		wp_reset_postdata();

		if ( empty( $all_items ) ) {
			return '<div class="bw-mm-empty">' . esc_html__( 'No map items with coordinates have been added yet.', 'bw-map-magnet' ) . '</div>';
		}

		$this->assets_needed = true;

		$instance_id = 'bw-mm-' . wp_unique_id();
		$height      = max( 300, (int) $atts['height'] );
		$show_filter = filter_var( $atts['filter'], FILTER_VALIDATE_BOOLEAN ) && count( $categories_index ) > 1;

		$config = [
			'items'        => $all_items,
			'categories'   => array_values( $categories_index ),
			'focusZoom'    => (float) $atts['focus_zoom'],
			'animDuration' => $anim_duration,
			'zoom'         => '' === $atts['zoom'] ? null : (float) $atts['zoom'],
		];

		if ( BW_Map_Magnet_Settings::get( 'central_enabled' ) ) {
			$c_lat = (float) BW_Map_Magnet_Settings::get( 'central_lat' );
			$c_lng = (float) BW_Map_Magnet_Settings::get( 'central_lng' );
			if ( $c_lat !== 0.0 || $c_lng !== 0.0 ) {
				$icon_mode = (string) BW_Map_Magnet_Settings::get( 'central_icon_mode' );
				$image_url = '';

				if ( 'logo' === $icon_mode ) {
					$image_url = BW_Map_Magnet_Settings::resolve_logo_url();
				} elseif ( 'custom' === $icon_mode ) {
					$image_id = (int) BW_Map_Magnet_Settings::get( 'central_custom_image_id' );
					if ( $image_id ) {
						$image_url = wp_get_attachment_image_url( $image_id, 'medium' );
						if ( ! $image_url ) {
							$image_url = '';
						}
					}
				}

				// Fall back to pin if the chosen image mode resolves to nothing.
				if ( ( 'logo' === $icon_mode || 'custom' === $icon_mode ) && '' === $image_url ) {
					$icon_mode = 'pin';
				}

				$config['central'] = [
					'lat'      => $c_lat,
					'lng'      => $c_lng,
					'title'    => html_entity_decode( (string) BW_Map_Magnet_Settings::get( 'central_title' ), ENT_QUOTES, 'UTF-8' ),
					'iconMode' => $icon_mode,
					'imageUrl' => $image_url,
					'color'    => (string) BW_Map_Magnet_Settings::get( 'central_color' ),
				];
				$config['showDistance']    = (bool) BW_Map_Magnet_Settings::get( 'show_distance' );
				$config['distanceUnit']    = (string) BW_Map_Magnet_Settings::get( 'distance_unit' );
				$config['directionsLabel'] = html_entity_decode( (string) BW_Map_Magnet_Settings::get( 'directions_label' ), ENT_QUOTES, 'UTF-8' );
			}
		}

		ob_start();
		?>
		<div class="bw-mm-wrap" id="<?php echo esc_attr( $instance_id ); ?>" style="--bw-mm-map-height: <?php echo esc_attr( $height ); ?>px;">
			<?php if ( $show_filter ) : ?>
				<div class="bw-mm-filter" data-bw-mm-filter-bar>
					<button type="button" class="bw-mm-filter-btn is-active" data-bw-mm-filter="all">
						<span class="bw-mm-filter-icon"><?php echo BW_Map_Magnet_Icons::render( 'pin', 16 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
						<span class="bw-mm-filter-label"><?php esc_html_e( 'All', 'bw-map-magnet' ); ?></span>
						<span class="bw-mm-filter-count"><?php echo esc_html( count( $all_items ) ); ?></span>
					</button>
					<?php foreach ( $categories_index as $cat ) : ?>
						<button type="button" class="bw-mm-filter-btn" data-bw-mm-filter="<?php echo esc_attr( $cat['slug'] ); ?>" style="--bw-mm-cat-color: <?php echo esc_attr( $cat['color'] ); ?>;">
							<span class="bw-mm-filter-icon"><?php echo BW_Map_Magnet_Icons::render( $cat['icon'], 16 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
							<span class="bw-mm-filter-label"><?php echo esc_html( $cat['name'] ); ?></span>
							<span class="bw-mm-filter-count"><?php echo esc_html( $cat['count'] ); ?></span>
						</button>
					<?php endforeach; ?>
				</div>
			<?php endif; ?>

			<div class="bw-mm-body">
				<div class="bw-mm-list" data-bw-mm-list>
					<?php foreach ( $items_by_category as $cat_slug => $group ) : ?>
						<section class="bw-mm-category" data-bw-mm-category="<?php echo esc_attr( $cat_slug ); ?>" style="--bw-mm-cat-color: <?php echo esc_attr( $group['color'] ); ?>;">
							<h3 class="bw-mm-category-title">
								<span class="bw-mm-category-icon"><?php echo BW_Map_Magnet_Icons::render( $group['icon'], 18 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
								<?php echo esc_html( $group['name'] ); ?>
							</h3>
							<ul class="bw-mm-items">
								<?php foreach ( $group['items'] as $item ) : ?>
									<li class="bw-mm-item" data-bw-mm-id="<?php echo esc_attr( $item['id'] ); ?>" data-bw-mm-item-category="<?php echo esc_attr( $cat_slug ); ?>" tabindex="0">
										<?php if ( $item['thumb'] ) : ?>
											<div class="bw-mm-item-thumb" style="background-image:url('<?php echo esc_url( $item['thumb'] ); ?>');" aria-hidden="true"></div>
										<?php else : ?>
											<div class="bw-mm-item-thumb bw-mm-item-thumb--empty" aria-hidden="true">
												<?php echo BW_Map_Magnet_Icons::render( $group['icon'], 28 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
											</div>
										<?php endif; ?>
										<div class="bw-mm-item-body">
											<h4 class="bw-mm-item-title"><?php echo esc_html( $item['title'] ); ?></h4>
											<?php if ( $item['excerpt'] ) : ?>
												<p class="bw-mm-item-excerpt"><?php echo esc_html( $item['excerpt'] ); ?></p>
											<?php endif; ?>
										</div>
									</li>
								<?php endforeach; ?>
							</ul>
						</section>
					<?php endforeach; ?>
				</div>
				<div class="bw-mm-map-col">
					<div class="bw-mm-map" data-bw-mm-map></div>
				</div>
			</div>
			<script type="application/json" data-bw-mm-config><?php echo wp_json_encode( $config ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></script>
		</div>
		<?php
		return ob_get_clean();
	}
}
