<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class Modula_Image_Sitemaps
 *
 * Enhances SEO by adding gallery images to XML sitemaps generated by Yoast SEO, Rank Math, SEOPress
 *
 * @package Modula
 */
class Modula_Image_Sitemaps {

	/**
	 * Cache group for transient keys
	 *
	 * @var string
	 */
	private $cache_group = 'modula_sitemap_images';

	/**
	 * Constructor
	 */
	public function __construct() {
		add_action( 'init', array( $this, 'init' ) );
	}

	/**
	 * Initialize hooks for Yoast SEO, Rank Math, SEOPress
	 */
	public function init() {
		add_filter(
			'wpseo_sitemap_urlimages',
			array( $this, 'add_images_to_sitemap' ),
			10,
			2
		);
		add_filter(
			'rank_math/sitemap/urlimages',
			array( $this, 'add_images_to_sitemap' ),
			10,
			2
		);
		add_filter(
			'seopress_sitemaps_xml_single',
			array( $this, 'add_images_to_seopress_sitemap' )
		);
	}

	/**
	 * Add gallery images to sitemap
	 *
	 * @param array $images Array of image entries
	 * @param int   $post_id Post ID
	 * @return array Modified array of image entries
	 */
	public function add_images_to_sitemap( $images, $post_id ) {
		if ( ! $post_id ) {
			return $images;
		}

		$post = get_post( $post_id );
		if ( ! $post ) {
			return $images;
		}

		$gallery_ids = $this->get_gallery_ids_from_post( $post );

		if ( empty( $gallery_ids ) ) {
			return $images;
		}

		$gallery_images = array();
		foreach ( $gallery_ids as $gallery_id ) {
			$images_from_gallery = $this->get_gallery_images( $gallery_id );
			if ( ! empty( $images_from_gallery ) ) {
				$gallery_images = array_merge( $gallery_images, $images_from_gallery );
			}
		}

		if ( ! empty( $gallery_images ) ) {
			$images = array_merge( $images, $gallery_images );
		}

		return $images;
	}

	/**
	 * Extract gallery IDs from post content (shortcode and Gutenberg block)
	 *
	 * @param WP_Post $post Post object
	 * @return array Array of gallery IDs
	 */
	private function get_gallery_ids_from_post( $post ) {
		$gallery_ids = array();

		if ( has_shortcode( $post->post_content, 'modula' ) || has_shortcode( $post->post_content, 'Modula' ) ) {
			$shortcode_ids = $this->extract_shortcode_gallery_ids( $post->post_content );
			$gallery_ids   = array_merge( $gallery_ids, $shortcode_ids );
		}

		if ( function_exists( 'has_block' ) && has_block( 'modula/gallery', $post ) ) {
			$block_ids   = $this->extract_block_gallery_ids( $post->post_content );
			$gallery_ids = array_merge( $gallery_ids, $block_ids );
		}

		$gallery_ids = array_unique( array_filter( array_map( 'absint', $gallery_ids ) ) );

		return $gallery_ids;
	}

	/**
	 * Extract gallery IDs from shortcode attributes
	 *
	 * @param string $content Post content
	 * @return array Array of gallery IDs
	 */
	private function extract_shortcode_gallery_ids( $content ) {
		$gallery_ids = array();

		$pattern = '/\[modula[^\]]*id=["\']?(\d+)["\']?[^\]]*\]/i';

		if ( preg_match_all( $pattern, $content, $matches ) ) {
			$gallery_ids = $matches[1];
		}

		return $gallery_ids;
	}

	/**
	 * Extract gallery IDs from Gutenberg block attributes
	 *
	 * @param string $content Post content
	 * @return array Array of gallery IDs
	 */
	private function extract_block_gallery_ids( $content ) {
		$gallery_ids = array();

		if ( ! function_exists( 'parse_blocks' ) ) {
			return $gallery_ids;
		}

		$blocks = parse_blocks( $content );

		foreach ( $blocks as $block ) {
			if ( 'modula/gallery' === $block['blockName'] ) {
				if ( isset( $block['attrs']['id'] ) && $block['attrs']['id'] > 0 ) {
					$gallery_ids[] = $block['attrs']['id'];
				} elseif ( isset( $block['attrs']['galleryId'] ) && $block['attrs']['galleryId'] > 0 ) {
					$gallery_ids[] = $block['attrs']['galleryId'];
				}
			}

			if ( ! empty( $block['innerBlocks'] ) ) {
				foreach ( $block['innerBlocks'] as $inner_block ) {
					if ( 'modula/gallery' === $inner_block['blockName'] ) {
						if ( isset( $inner_block['attrs']['id'] ) && $inner_block['attrs']['id'] > 0 ) {
							$gallery_ids[] = $inner_block['attrs']['id'];
						} elseif ( isset( $inner_block['attrs']['galleryId'] ) && $inner_block['attrs']['galleryId'] > 0 ) {
							$gallery_ids[] = $inner_block['attrs']['galleryId'];
						}
					}
				}
			}
		}

		return $gallery_ids;
	}

	/**
	 * Get gallery images formatted for sitemap
	 *
	 * @param int $gallery_id Gallery post ID
	 * @return array Array of image entries for sitemap
	 */
	private function get_gallery_images( $gallery_id ) {
		$cache_key = $this->get_cache_key( $gallery_id );
		$cached    = get_transient( $cache_key );

		if ( false !== $cached ) {
			return $cached;
		}

		$images = array();

		$post_type = get_post_type( $gallery_id );
		if ( ! $post_type || 'modula-gallery' !== $post_type ) {
			set_transient( $cache_key, array(), HOUR_IN_SECONDS );
			return array();
		}

		$post_status = get_post_status( $gallery_id );
		if ( ! $post_status || 'publish' !== $post_status ) {
			set_transient( $cache_key, array(), HOUR_IN_SECONDS );
			return array();
		}

		$meta_images = get_post_meta( $gallery_id, 'modula-images', true );

		if ( empty( $meta_images ) || ! is_array( $meta_images ) ) {
			set_transient( $cache_key, array(), HOUR_IN_SECONDS );
			return array();
		}

		foreach ( $meta_images as $image_data ) {
			if ( isset( $image_data['id'] ) && is_string( $image_data['id'] ) && strpos( $image_data['id'], 'video_' ) !== false ) {
				continue;
			}

			$image_id = isset( $image_data['id'] ) ? absint( $image_data['id'] ) : 0;
			if ( ! $image_id ) {
				continue;
			}

			$attachment = get_post( $image_id );
			if ( ! $attachment || 'attachment' !== get_post_type( $attachment ) ) {
				continue;
			}

			$mime_type = get_post_mime_type( $image_id );
			if ( 'image/heic' === $mime_type || 'image/heif' === $mime_type ) {
				$image_src = wp_get_attachment_image_src( $image_id, 'full' );
				$image_url = ( $image_src && isset( $image_src[0] ) ) ? $image_src[0] : false;
			} else {
				$image_url = wp_get_original_image_url( $image_id );
			}

			if ( ! $image_url ) {
				continue;
			}

			$image_url = esc_url_raw( $image_url );
			if ( ! filter_var( $image_url, FILTER_VALIDATE_URL ) ) {
				continue;
			}

			$image_entry = array(
				'src' => $image_url,
			);

			$image_title = get_the_title( $image_id );

			if ( ! empty( $image_title ) ) {
				$image_entry['title'] = $image_title;
			}

			$image_caption = wp_get_attachment_caption( $image_id );
			if ( ! empty( $image_caption ) ) {
				$image_entry['caption'] = $image_caption;
			}

			$image_alt = '';
			if ( isset( $image_data['alt'] ) && ! empty( $image_data['alt'] ) ) {
				$image_alt = sanitize_text_field( $image_data['alt'] );
			} else {
				$image_alt = get_post_meta( $image_id, '_wp_attachment_image_alt', true );
			}

			if ( ! empty( $image_alt ) ) {
				$image_entry['alt'] = $image_alt;
			}

			$images[] = $image_entry;
		}

		set_transient( $cache_key, $images, 12 * HOUR_IN_SECONDS );

		return $images;
	}

	/**
	 * Get cache key for gallery images
	 *
	 * @param int $gallery_id Gallery ID
	 * @return string Cache key
	 */
	private function get_cache_key( $gallery_id ) {
		return $this->cache_group . '_' . absint( $gallery_id );
	}

	/**
	 * Add gallery images to SEOPress sitemap XML
	 *
	 * @param string $xml XML sitemap content
	 * @return string Modified XML sitemap content
	 */
	public function add_images_to_seopress_sitemap( $xml ) {
		if ( preg_match_all( '/<url>(.*?)<\/url>/s', $xml, $url_matches ) ) {
			foreach ( $url_matches[0] as $url_entry ) {
				if ( preg_match( '/<loc>(.*?)<\/loc>/', $url_entry, $loc_matches ) ) {
					$url     = $loc_matches[1];
					$post_id = url_to_postid( $url );

					if ( ! $post_id ) {
						continue;
					}

					$post = get_post( $post_id );
					if ( ! $post ) {
						continue;
					}

					$gallery_ids = $this->get_gallery_ids_from_post( $post );

					if ( empty( $gallery_ids ) ) {
						continue;
					}

					$images_xml = '';
					foreach ( $gallery_ids as $gallery_id ) {
						$images_from_gallery = $this->get_gallery_images( $gallery_id );
						if ( ! empty( $images_from_gallery ) ) {
							foreach ( $images_from_gallery as $image ) {
								$images_xml .= '<image:image>';
								$images_xml .= '<image:loc>' . esc_url( $image['src'] ) . '</image:loc>';
								if ( ! empty( $image['title'] ) ) {
									$images_xml .= '<image:title>' . esc_html( $image['title'] ) . '</image:title>' . "\n";
								}
								if ( ! empty( $image['caption'] ) ) {
									$images_xml .= '<image:caption>' . esc_html( $image['caption'] ) . '</image:caption>' . "\n";
								}
								$images_xml .= '</image:image>' . "\n";
							}
						}
					}

					if ( ! empty( $images_xml ) ) {
						$updated_entry = str_replace( '</url>', $images_xml . '</url>', $url_entry );
						$xml           = str_replace( $url_entry, $updated_entry, $xml );
					}
				}
			}
		}

		return $xml;
	}

	/**
	 * Clear cache for a specific gallery
	 *
	 * @param int $gallery_id Gallery ID
	 */
	public function clear_cache( $gallery_id ) {
		$cache_key = $this->get_cache_key( $gallery_id );
		delete_transient( $cache_key );
	}
}
