<?php
/**
 * Sitemap Index
 *
 * Builds and renders the sitemap index document.
 *
 * @package SEOvaultSEO
 */

namespace SEOvaultSEO\Sitemap;

use SEOvaultSEO\Core\Options;

/**
 * Builds the sitemap index
 */
class Index {

	/**
	 * Output the index.
	 */
	public static function output() {
		$index = Cache::read_index();

		if ( empty( $index ) ) {
			$index = self::build();
		}

		$entries = array();
		foreach ( $index as $url => $lastmod ) {
			$entries[] = array(
				'loc'     => $url,
				'lastmod' => $lastmod,
			);
		}

		if ( empty( $entries ) ) {
			self::send_empty_index();
			return;
		}

		Renderer::set_stylesheet_url( home_url( '/seovault-sitemap.xsl' ) );
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Pre-built XML sitemap index.
		echo Renderer::index( $entries );
	}

	/**
	 * Build the index from current settings.
	 *
	 * @return array
	 */
	public static function build() {
		$index    = array();
		$lastmod  = gmdate( 'Y-m-d' );
		$per_page = Options::get_sitemap_entries_per_page();
		$base_url = home_url( '/' );

		$post_types = Options::get_sitemap_post_types();
		foreach ( $post_types as $post_type ) {
			$post_type = Sanitizer::slug( $post_type );
			if ( '' === $post_type ) {
				continue;
			}
			$count = Query::get_post_type_count( $post_type );
			$pages = max( 1, (int) ceil( $count / $per_page ) );
			for ( $page = 1; $page <= $pages; $page++ ) {
				$url           = $base_url . 'seovault-sitemap-' . $post_type . '-' . $page . '.xml';
				$index[ $url ] = $lastmod;
			}
		}

		$taxonomies = Options::get_sitemap_taxonomies();
		foreach ( $taxonomies as $taxonomy ) {
			$taxonomy = Sanitizer::slug( $taxonomy );
			if ( '' === $taxonomy ) {
				continue;
			}
			$count = Query::get_term_count( $taxonomy );
			$pages = max( 1, (int) ceil( $count / $per_page ) );
			for ( $page = 1; $page <= $pages; $page++ ) {
				$url           = $base_url . 'seovault-sitemap-taxonomy-' . $taxonomy . '-' . $page . '.xml';
				$index[ $url ] = $lastmod;
			}
		}

		if ( Options::is_sitemap_users_enabled() ) {
			$count = Query::get_user_count();
			$pages = max( 1, (int) ceil( $count / $per_page ) );
			for ( $page = 1; $page <= $pages; $page++ ) {
				$url           = $base_url . 'seovault-sitemap-users-' . $page . '.xml';
				$index[ $url ] = $lastmod;
			}
		}

		if ( Archives::has_entries() ) {
			$url           = $base_url . 'seovault-sitemap-' . Archives::SLUG . '-1.xml';
			$index[ $url ] = $lastmod;
		}

		/**
		 * Allow integrations (e.g. the Pro Video SEO module) to add sub-sitemap
		 * entries to the main sitemap index. Each entry is `URL => lastmod`.
		 *
		 * @param array<string,string> $index  Map of sitemap URL => lastmod date.
		 * @param string               $lastmod Today's date (Y-m-d).
		 * @param string               $base_url Home URL with trailing slash.
		 */
		return apply_filters( 'seovaultseo_sitemap_index_entries', $index, $lastmod, $base_url );
	}

	/**
	 * Send an empty index with a 503 and Retry-After.
	 */
	private static function send_empty_index() {
		if ( ! headers_sent() ) {
			status_header( 503 );
			header( 'Retry-After: 3600' );
		}
		Renderer::set_stylesheet_url( home_url( '/seovault-sitemap.xsl' ) );
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Empty XML sitemap index during rebuild.
		echo Renderer::index( array() );
	}
}
