<?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
namespace Yoast\WP\SEO\Schema_Aggregator\User_Interface;

use WP_REST_Request;
use WP_REST_Response;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\Schema_Aggregator\Infrastructure\Schema_Aggregator_Conditional;
use Yoast\WP\SEO\Schema_Aggregator\Infrastructure\Schema_Map\Schema_Map_Header_Adapter;

/**
 * Integration to set proper response headers for Site Schema endpoints.
 */
class Site_Schema_Response_Header_Integration implements Integration_Interface {

	/**
	 * The schema map header adapter.
	 *
	 * @var Schema_Map_Header_Adapter
	 */
	private $schema_map_header_adapter;

	/**
	 * Returns the conditional for this route.
	 *
	 * @return array<string> The conditionals that must be met to load this.
	 */
	public static function get_conditionals() {
		return [ Schema_Aggregator_Conditional::class ];
	}

	/**
	 * Constructor.
	 *
	 * @param Schema_Map_Header_Adapter $schema_map_header_adapter The schema map header adapter.
	 */
	public function __construct( Schema_Map_Header_Adapter $schema_map_header_adapter ) {
		$this->schema_map_header_adapter = $schema_map_header_adapter;
	}

	/**
	 * Registers the hooks for the integration.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_filter( 'rest_pre_serve_request', [ $this, 'serve_custom_response' ], 10, 4 );
	}

	/**
	 * Serve custom responses (XML or JSON) for schemamap endpoints
	 *
	 * Intercepts schemamap index endpoints to serve either XML or JSON with
	 * proper content types and formatting. For XML responses (from /schema),
	 * outputs raw XML. For JSON responses (from /schema.json or post-type endpoints),
	 * outputs JSON with unescaped slashes for cleaner URLs.
	 *
	 * Only affects /yoast/v1/schema-aggregator endpoints. Other endpoints are unaffected.
	 *
	 * @param bool             $served  Whether the request has already been served.
	 * @param WP_REST_Response $result  Result to send to the client.
	 * @param WP_REST_Request  $request Request object.
	 *
	 * @return bool True if we served the request, false otherwise.
	 * @codeCoverageIgnore ignore this since its needs to rely on headers being sent. Which does not work in integration tests.
	 */
	public function serve_custom_response( $served, $result, $request ): bool {
		if ( ! $request instanceof WP_REST_Request || \strpos( $request->get_route(), '/yoast/v1/schema-aggregator' ) !== 0 ) {
			return (bool) $served;
		}

		if ( ! $result instanceof WP_REST_Response || $result->is_error() ) {
			return (bool) $served;
		}

		$this->schema_map_header_adapter->set_header_for_request( $result );

		return true;
	}
}
