<?php
/**
 * Email Obfuscator — no-settings frontend module.
 *
 * Developer hooks (not shown in admin UI):
 * - `wp_powersuite_email_obfuscator_should_process` (bool, string $content, string $filter)
 * - `wp_powersuite_email_obfuscator_should_obfuscate` (bool, string $email, string $context)
 * - `wp_powersuite_email_obfuscator_output` (string $content, string $filter)
 * - `wp_powersuite_email_obfuscator_content_filters` (array<string, int> $filters)
 *
 * RSS/feed output is intentionally excluded (is_feed) so syndicated content stays readable
 * in feed readers. Reduces basic email harvesting on public HTML; advanced scrapers may
 * still decode entities.
 *
 * @package WP_PowerSuite\Modules\EmailObfuscator
 */

namespace EmailObfuscator;

use WP_PowerSuite\Core\AbstractModule;

require_once __DIR__ . '/includes/class-content-obfuscator.php';

class Module extends AbstractModule {

	private const MODULE_ID               = 'email-obfuscator';
	private const MODULE_VERSION          = '1.0.1';
	private const CONTENT_FILTER_PRIORITY = 999;

	private ?ContentObfuscator $obfuscator = null;

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

	public function getName(): string {
		return __( 'Email Obfuscator', 'wp-powersuite' );
	}

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

	public function getDescription(): string {
		return __( 'Automatically protects visible email addresses and mailto links from basic spam bots by safely encoding them while keeping them clickable for visitors.', 'wp-powersuite' );
	}

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

	protected function registerHooks(): void {
		if ( is_admin() || is_feed() ) {
			return;
		}

		$filters = $this->getContentFilters();

		foreach ( $filters as $hook => $priority ) {
			add_filter( $hook, [ $this, 'filterContent' ], $priority );
		}

		add_filter( 'nav_menu_link_attributes', [ $this, 'filterNavMenuLinkAttributes' ], self::CONTENT_FILTER_PRIORITY, 4 );
	}

	/**
	 * @return array<string, int>
	 */
	private function getContentFilters(): array {
		$filters = [
			'the_content'           => self::CONTENT_FILTER_PRIORITY,
			'the_excerpt'           => self::CONTENT_FILTER_PRIORITY,
			'comment_text'          => self::CONTENT_FILTER_PRIORITY,
			'widget_text'           => self::CONTENT_FILTER_PRIORITY,
			'widget_text_content'   => self::CONTENT_FILTER_PRIORITY,
			'widget_block_content'  => self::CONTENT_FILTER_PRIORITY,
			'walker_nav_menu_start_el' => self::CONTENT_FILTER_PRIORITY,
			'render_block'          => self::CONTENT_FILTER_PRIORITY,
		];

		if ( class_exists( 'WooCommerce' ) ) {
			$filters['woocommerce_short_description'] = self::CONTENT_FILTER_PRIORITY;
		}

		/**
		 * Filter which WordPress content hooks receive email obfuscation.
		 *
		 * @param array<string, int> $filters Hook => priority pairs.
		 */
		$filters = apply_filters( 'wp_powersuite_email_obfuscator_content_filters', $filters );

		$normalized = [];
		foreach ( $filters as $hook => $priority ) {
			$hook_name = sanitize_key( (string) $hook );
			if ( $hook_name === '' ) {
				continue;
			}

			$normalized[ $hook_name ] = max( 1, min( 9999, (int) $priority ) );
		}

		return $normalized;
	}

	public function filterContent( string $content ): string {
		if ( $content === '' || ! str_contains( $content, '@' ) ) {
			return $content;
		}

		$filter = current_filter();
		if ( ! is_string( $filter ) || $filter === '' ) {
			$filter = 'content';
		}

		/**
		 * Whether email obfuscation should run for this content string.
		 *
		 * @param bool   $should_process Default true.
		 * @param string $content        Raw content passed to the filter.
		 * @param string $filter         Current filter hook name.
		 */
		if ( ! apply_filters( 'wp_powersuite_email_obfuscator_should_process', true, $content, $filter ) ) {
			return $content;
		}

		$processed = $this->obfuscator()->obfuscate( $content, $filter );

		/**
		 * Final obfuscated content before it is returned to WordPress.
		 *
		 * @param string $processed Obfuscated HTML.
		 * @param string $filter    Content filter hook name.
		 */
		return (string) apply_filters( 'wp_powersuite_email_obfuscator_output', $processed, $filter );
	}

	/**
	 * @param array<string, mixed> $atts
	 * @param mixed                $item
	 * @param mixed                $args
	 */
	public function filterNavMenuLinkAttributes( array $atts, $item, $args, int $depth ): array {
		unset( $item, $args, $depth );

		if ( empty( $atts['href'] ) || ! is_string( $atts['href'] ) ) {
			return $atts;
		}

		if ( ! str_contains( strtolower( $atts['href'] ), 'mailto:' ) ) {
			return $atts;
		}

		$atts['href'] = $this->obfuscator()->obfuscateMailtoHrefValue( $atts['href'], 'nav_menu_link_attributes' );

		return $atts;
	}

	private function obfuscator(): ContentObfuscator {
		if ( $this->obfuscator === null ) {
			$this->obfuscator = new ContentObfuscator();
		}

		return $this->obfuscator;
	}
}
