<?php
/**
 * Sitemap Router
 *
 * Registers rewrite rules, query vars, and dispatches sitemap requests.
 *
 * @package SEOvaultSEO
 */

namespace SEOvaultSEO\Sitemap;

use SEOvaultSEO\Core\Options;

/**
 * Routes custom sitemap requests
 */
class Router {

	/**
	 * Query var name.
	 *
	 * @var string
	 */
	const QUERY_VAR = 'seovault_sitemap';

	/**
	 * Page query var name.
	 *
	 * @var string
	 */
	const PAGE_QUERY_VAR = 'seovault_sitemap_page';

	/**
	 * Register rewrite rules and query vars.
	 */
	public static function register() {
		add_rewrite_rule( 'seovault-sitemap\.xsl$', 'index.php?' . self::QUERY_VAR . '=xsl', 'top' );
		add_rewrite_rule( 'seovault-sitemap\.xml$', 'index.php?' . self::QUERY_VAR . '=index', 'top' );
		add_rewrite_rule( 'seovault-sitemap-([a-z0-9_-]+)-(\d+)\.xml$', 'index.php?' . self::QUERY_VAR . '=$matches[1]&' . self::PAGE_QUERY_VAR . '=$matches[2]', 'top' );
		add_rewrite_rule( 'seovault-sitemap-([a-z0-9_-]+)\.xml$', 'index.php?' . self::QUERY_VAR . '=$matches[1]&' . self::PAGE_QUERY_VAR . '=1', 'top' );

		add_filter( 'query_vars', array( __CLASS__, 'add_query_vars' ) );
		add_action( 'template_redirect', array( __CLASS__, 'redirect_core_sitemap' ), 0 );
		add_action( 'template_redirect', array( __CLASS__, 'output' ), 1 );
	}

	/**
	 * Add custom query vars.
	 *
	 * @param array $vars Query vars.
	 * @return array
	 */
	public static function add_query_vars( $vars ) {
		$vars[] = self::QUERY_VAR;
		$vars[] = self::PAGE_QUERY_VAR;
		return $vars;
	}

	/**
	 * Redirect WordPress core sitemap requests to our custom sitemap.
	 */
	public static function redirect_core_sitemap() {
		if ( ! Options::is_sitemap_enabled() ) {
			return;
		}

		if ( ! is_object( $GLOBALS['wp'] ) ) {
			return;
		}

		$request = $GLOBALS['wp']->request;
		if ( ! is_string( $request ) ) {
			return;
		}

		if ( 'wp-sitemap.xml' === $request || 0 === strpos( $request, 'wp-sitemap' ) ) {
			wp_safe_redirect( Manager::get_index_url(), 301 );
			exit;
		}
	}

	/**
	 * Output the sitemap if a sitemap request is detected.
	 */
	public static function output() {
		if ( ! Options::is_sitemap_enabled() ) {
			return;
		}

		$slug = get_query_var( self::QUERY_VAR );
		$page = (int) get_query_var( self::PAGE_QUERY_VAR );

		if ( '' === $slug ) {
			$matched_request = self::match_request_path( self::get_current_request_path() );
			if ( null === $matched_request ) {
				return;
			}

			$slug = $matched_request['slug'];
			$page = $matched_request['page'];
		}

		if ( isset( $GLOBALS['wp_query'] ) && is_object( $GLOBALS['wp_query'] ) ) {
			$GLOBALS['wp_query']->is_404 = false;
		}

		status_header( 200 );
		self::send_headers();

		if ( $page < 1 ) {
			$page = 1;
		}

		switch ( $slug ) {
			case 'index':
				Index::output();
				break;
			case 'xsl':
				Stylesheet::output();
				break;
			default:
				self::dispatch_sub_sitemap( $slug, $page );
				break;
		}

		exit;
	}

	/**
	 * Get the current request path from WordPress.
	 *
	 * @return string
	 */
	private static function get_current_request_path() {
		if ( ! isset( $GLOBALS['wp'] ) || ! is_object( $GLOBALS['wp'] ) ) {
			return '';
		}

		$request = $GLOBALS['wp']->request;
		return is_string( $request ) ? trim( $request, '/' ) : '';
	}

	/**
	 * Match a sitemap request path without relying on rewrite precedence.
	 *
	 * @param string $request Request path.
	 * @return array<string,int|string>|null
	 */
	private static function match_request_path( $request ) {
		if ( 'seovault-sitemap.xml' === $request ) {
			return array(
				'slug' => 'index',
				'page' => 1,
			);
		}

		if ( 'seovault-sitemap.xsl' === $request ) {
			return array(
				'slug' => 'xsl',
				'page' => 1,
			);
		}

		if ( preg_match( '/^seovault-sitemap-([a-z0-9_-]+)-(\d+)\.xml$/', $request, $matches ) ) {
			return array(
				'slug' => $matches[1],
				'page' => (int) $matches[2],
			);
		}

		if ( preg_match( '/^seovault-sitemap-([a-z0-9_-]+)\.xml$/', $request, $matches ) ) {
			return array(
				'slug' => $matches[1],
				'page' => 1,
			);
		}

		return null;
	}

	/**
	 * Dispatch a sub-sitemap request.
	 *
	 * @param string $slug Sitemap slug.
	 * @param int    $page Page number.
	 */
	private static function dispatch_sub_sitemap( $slug, $page ) {
		$slug = Sanitizer::slug( $slug );
		if ( '' === $slug ) {
			self::send_404();
			return;
		}

		if ( 'taxonomy' === $slug || 0 === strpos( $slug, 'taxonomy-' ) ) {
			Taxonomy::output( $slug, $page );
			return;
		}

		if ( 'users' === $slug || 0 === strpos( $slug, 'users-' ) ) {
			User::output( $slug, $page );
			return;
		}

		if ( Archives::SLUG === $slug || 0 === strpos( $slug, Archives::SLUG . '-' ) ) {
			Archives::output( $slug, $page );
			return;
		}

		PostType::output( $slug, $page );
	}

	/**
	 * Send XML headers.
	 */
	public static function send_headers() {
		if ( ! headers_sent() ) {
			header( 'Content-Type: text/xml; charset=UTF-8' );
			header( 'X-Robots-Tag: noindex, follow' );
		}
	}

	/**
	 * Send a 404 response.
	 */
	public static function send_404() {
		global $wp_query;
		$wp_query->set_404();
		status_header( 404 );
		self::send_headers();
		echo '<?xml version="1.0" encoding="UTF-8"?><error>Not found</error>';
	}
}
