<?php
/**
 * Detects when multiple CAPTCHA modules protect the same surface.
 *
 * @package WP_PowerSuite\Captcha\Shared
 * @since 1.5.2
 */

namespace WP_PowerSuite\Captcha\Shared;

use WP_PowerSuite\Core\ModuleRegistry;
use WP_PowerSuite\Core\OptionStoreModuleSettingsRepository;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Scans enabled CAPTCHA modules for overlapping protection toggles.
 */
final class CaptchaOverlapDetector {

	/** @var list<string> */
	public const MODULE_IDS = [
		'google-recaptcha',
		'cloudflare-turnstile',
		'simple-captcha',
	];

	/**
	 * Protection surfaces shared across CAPTCHA modules.
	 *
	 * @var array<string, array{label: string, keys: list<string>}>
	 */
	private const SURFACES = [
		'protect_login'              => [
			'label' => 'WordPress login',
			'keys'  => [ 'protect_login' ],
		],
		'protect_registration'       => [
			'label' => 'WordPress registration',
			'keys'  => [ 'protect_registration' ],
		],
		'protect_password_reset'     => [
			'label' => 'Password reset',
			'keys'  => [ 'protect_password_reset' ],
		],
		'comments'                   => [
			'label' => 'Comments & product reviews',
			'keys'  => [ 'protect_comments', 'woo_reviews' ],
		],
		'woo_login'                  => [
			'label' => 'WooCommerce login',
			'keys'  => [ 'woo_login' ],
		],
		'woo_registration'           => [
			'label' => 'WooCommerce registration',
			'keys'  => [ 'woo_registration' ],
		],
		'woo_lost_password'          => [
			'label' => 'WooCommerce lost password',
			'keys'  => [ 'woo_lost_password' ],
		],
		'woo_checkout'               => [
			'label' => 'WooCommerce checkout',
			'keys'  => [ 'woo_checkout' ],
		],
		'cf7'                        => [
			'label' => 'Contact Form 7',
			'keys'  => [ 'cf7' ],
		],
		'wpforms'                    => [
			'label' => 'WPForms',
			'keys'  => [ 'wpforms' ],
		],
		'formidable'                 => [
			'label' => 'Formidable Forms',
			'keys'  => [ 'formidable' ],
		],
		'fluent_forms'               => [
			'label' => 'Fluent Forms',
			'keys'  => [ 'fluent_forms' ],
		],
		'elementor_forms'          => [
			'label' => 'Elementor Pro Forms',
			'keys'  => [ 'elementor_forms' ],
		],
		'integration_gravity'        => [
			'label' => 'Gravity Forms',
			'keys'  => [ 'integration_gravity' ],
		],
		'integration_jetpack'        => [
			'label' => 'Jetpack forms',
			'keys'  => [ 'integration_jetpack' ],
		],
		'integration_bbpress'        => [
			'label' => 'bbPress',
			'keys'  => [ 'integration_bbpress' ],
		],
		'integration_buddypress'     => [
			'label' => 'BuddyPress',
			'keys'  => [ 'integration_buddypress' ],
		],
		'integration_ultimate_member' => [
			'label' => 'Ultimate Member',
			'keys'  => [ 'integration_ultimate_member' ],
		],
		'integration_memberpress'    => [
			'label' => 'MemberPress',
			'keys'  => [ 'integration_memberpress' ],
		],
		'integration_edd'          => [
			'label' => 'Easy Digital Downloads',
			'keys'  => [ 'integration_edd' ],
		],
		'integration_pmp'            => [
			'label' => 'Paid Memberships Pro',
			'keys'  => [ 'integration_pmp' ],
		],
		'integration_mc4wp'          => [
			'label' => 'MC4WP (Mailchimp)',
			'keys'  => [ 'integration_mc4wp' ],
		],
	];

	/**
	 * All surfaces where two or more enabled modules have protection on.
	 *
	 * @return list<array{surface_id: string, label: string, modules: array<string, string>}>
	 */
	public static function getOverlaps(): array {
		$active = self::getActiveModulesBySurface();
		$overlaps = [];

		foreach ( self::SURFACES as $surface_id => $surface ) {
			$module_ids = array_keys( $active[ $surface_id ] ?? [] );
			if ( count( $module_ids ) < 2 ) {
				continue;
			}

			$modules = [];
			foreach ( $module_ids as $module_id ) {
				$modules[ $module_id ] = self::getModuleLabel( $module_id );
			}

			$overlaps[] = [
				'surface_id' => $surface_id,
				'label'      => $surface['label'],
				'modules'    => $modules,
			];
		}

		return $overlaps;
	}

	/**
	 * Overlaps relevant to one CAPTCHA module (only when this module also protects that surface).
	 *
	 * @return list<array{surface_id: string, label: string, modules: array<string, string>}>
	 */
	public static function getOverlapsForModule( string $module_id ): array {
		$module_id = sanitize_key( $module_id );
		if ( ! in_array( $module_id, self::MODULE_IDS, true ) ) {
			return [];
		}

		if ( ! self::isModuleEnabled( $module_id ) ) {
			return [];
		}

		$settings = self::getModuleSettings( $module_id );
		$overlaps = [];

		foreach ( self::getOverlaps() as $overlap ) {
			if ( ! isset( $overlap['modules'][ $module_id ] ) ) {
				continue;
			}
			if ( ! self::isSurfaceActive( $settings, self::SURFACES[ $overlap['surface_id'] ] ) ) {
				continue;
			}
			$overlaps[] = $overlap;
		}

		return $overlaps;
	}

	/**
	 * @return array<string, array<string, true>> surface_id => [ module_id => true, ... ]
	 */
	private static function getActiveModulesBySurface(): array {
		$active = [];
		foreach ( array_keys( self::SURFACES ) as $surface_id ) {
			$active[ $surface_id ] = [];
		}

		foreach ( self::MODULE_IDS as $module_id ) {
			if ( ! self::isModuleEnabled( $module_id ) ) {
				continue;
			}

			$settings = self::getModuleSettings( $module_id );
			foreach ( self::SURFACES as $surface_id => $surface ) {
				if ( self::isSurfaceActive( $settings, $surface ) ) {
					$active[ $surface_id ][ $module_id ] = true;
				}
			}
		}

		return $active;
	}

	/**
	 * @param array<string, mixed>        $settings
	 * @param array{label: string, keys: list<string>} $surface
	 */
	private static function isSurfaceActive( array $settings, array $surface ): bool {
		foreach ( $surface['keys'] as $key ) {
			if ( ! empty( $settings[ $key ] ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * @return array<string, mixed>
	 */
	private static function getModuleSettings( string $module_id ): array {
		return OptionStoreModuleSettingsRepository::forModule( $module_id )->all( [] );
	}

	private static function isModuleEnabled( string $module_id ): bool {
		return OptionStoreModuleSettingsRepository::isModuleEnabled( $module_id );
	}

	private static function getModuleLabel( string $module_id ): string {
		static $cache = [];

		if ( isset( $cache[ $module_id ] ) ) {
			return $cache[ $module_id ];
		}

		$registry = ModuleRegistry::getInstance();
		$registry->init();
		$meta = $registry->getModuleMetadata( $module_id );
		if ( ! empty( $meta['name'] ) && is_string( $meta['name'] ) ) {
			$cache[ $module_id ] = $meta['name'];
			return $cache[ $module_id ];
		}

		$cache[ $module_id ] = $module_id;
		return $cache[ $module_id ];
	}
}
