<?php

namespace DisableTrackbacksPingbacks;

use WP_PowerSuite\Core\AbstractModule;

class Module extends AbstractModule {

	private const MODULE_ID = 'disable-trackbacks-pingbacks';
	private const MODULE_VERSION = '1.1.3';
	private const MODULE_XMLRPC_ID = 'disable-xmlrpc';

	public function getId(): string {
		return self::MODULE_ID;
	}

	public function getName(): string {
		return __( 'Disable Trackbacks/Pingbacks', 'wp-powersuite' );
	}

	public function getVersion(): string {
		return self::MODULE_VERSION;
	}

	public function getDescription(): string {
		return __( 'Stops old-style trackbacks and pingbacks that often bring spam or junk alerts.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return 'both';
	}

	protected function registerHooks(): void {
		if ( $this->isDirectWpTrackbackPhpRequest() ) {
			$this->sendTrackbacksForbiddenXml();
		}

		$xmlrpc_disabled = \WP_PowerSuite\Core\OptionStoreModuleSettingsRepository::isModuleEnabled( self::MODULE_XMLRPC_ID );

		// pre_ping is fired via do_action_ref_array(); return values are ignored — clear links by reference.
		add_action( 'pre_ping', [ $this, 'clearOutboundPingTargets' ], 999, 3 );
		add_filter( 'pings_open', '__return_false', 999, 2 );
		add_filter( 'discover_pingback_server_uri', '__return_false', 999 );

		if ( ! $xmlrpc_disabled ) {
			add_filter( 'xmlrpc_methods', [ $this, 'removePingbackMethods' ], \PHP_INT_MAX, 1 );
			add_filter( 'wp_headers', [ $this, 'removePingbackHeader' ], \PHP_INT_MAX, 1 );
		}

		add_action( 'init', [ $this, 'removeTrackbackSupport' ], 999 );
	}

	/**
	 * @param array<int, string> $post_links URLs WordPress would ping (by reference).
	 * @param array<int, string> $pung       Already pinged (by reference).
	 */
	public function clearOutboundPingTargets( array &$post_links, array &$pung, int $post_id ): void {
		$post_links = [];
	}

	private function isDirectWpTrackbackPhpRequest(): bool {
		if ( isset( $_SERVER['SCRIPT_FILENAME'] ) ) {
			$script = wp_basename( wp_unslash( $_SERVER['SCRIPT_FILENAME'] ) );
			if ( 'wp-trackback.php' === $script ) {
				return true;
			}
		}

		if ( isset( $_SERVER['REQUEST_URI'] ) ) {
			$uri  = wp_unslash( $_SERVER['REQUEST_URI'] );
			$path = strtok( $uri, '?' );
			if ( is_string( $path ) && preg_match( '#/wp-trackback\.php(?:$|[?/])#', $path ) ) {
				return true;
			}
		}

		return false;
	}

	private function sendTrackbacksForbiddenXml(): void {
		status_header( 403 );
		nocache_headers();

		$charset = (string) get_option( 'blog_charset' );
		if ( '' === $charset ) {
			$charset = 'utf-8';
		}
		header( 'Content-Type: text/xml; charset=' . $charset );

		$message = htmlspecialchars(
			__( 'Trackbacks are disabled.', 'wp-powersuite' ),
			ENT_XML1 | ENT_COMPAT,
			'UTF-8'
		);

		echo '<?xml version="1.0" encoding="utf-8"?' . ">\n";
		echo "<response>\n";
		echo "<error>1</error>\n";
		echo '<message>' . $message . "</message>\n";
		echo "</response>\n";
		exit;
	}

	public function removePingbackMethods( array $methods ): array {
		unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'] );
		return $methods;
	}

	public function removePingbackHeader( array $headers ): array {
		unset( $headers['X-Pingback'], $headers['x-pingback'] );
		return $headers;
	}

	public function removeTrackbackSupport(): void {
		foreach ( get_post_types( [], 'names' ) as $post_type ) {
			if ( post_type_supports( $post_type, 'trackbacks' ) ) {
				remove_post_type_support( $post_type, 'trackbacks' );
			}
		}
	}
}
