<?php
/**
 * Anti-spam service for managing anti-spam providers.
 *
 * @package Awesomemotive\Rewardswp\Services
 * @since 1.2.0
 */

namespace Awesomemotive\Rewardswp\Services;

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

use Awesomemotive\Rewardswp\Interfaces\AntiSpamProviderInterface;
use Awesomemotive\Rewardswp\Settings\Options\General\AntiSpamProviderOption;
use function Awesomemotive\Rewardswp\Helpers\get_option_value;

/**
 * AntiSpam Service.
 *
 * Manages anti-spam providers and provides a unified interface
 * for rendering and validating anti-spam protection.
 *
 * @since 1.2.0
 */
class AntiSpamService {
	/**
	 * Registered providers.
	 *
	 * @since 1.2.0
	 *
	 * @var array<string, AntiSpamProviderInterface>
	 */
	private array $providers = [];

	/**
	 * The last error message from validation.
	 *
	 * @since 1.2.0
	 *
	 * @var string
	 */
	private string $last_error = '';

	/**
	 * Constructor.
	 *
	 * Receives an array of anti-spam providers from the DI container.
	 * Providers are defined in BaseDefinitions/ProDefinitions under 'antispam_providers'.
	 *
	 * @since 1.2.0
	 *
	 * @param AntiSpamProviderInterface[] $antispam_providers Array of provider instances.
	 */
	public function __construct( array $antispam_providers = [] ) {
		foreach ( $antispam_providers as $provider ) {
			if ( $provider instanceof AntiSpamProviderInterface ) {
				$this->register_provider( $provider );
			}
		}
	}

	/**
	 * Register an anti-spam provider.
	 *
	 * @since 1.2.0
	 *
	 * @param AntiSpamProviderInterface $provider The provider instance.
	 *
	 * @return void
	 */
	public function register_provider( AntiSpamProviderInterface $provider ): void {
		$this->providers[ $provider->get_name() ] = $provider;
	}

	/**
	 * Get all registered providers.
	 *
	 * @since 1.2.0
	 *
	 * @return array<string, AntiSpamProviderInterface>
	 */
	public function get_providers(): array {
		return $this->providers;
	}

	/**
	 * Get available providers (those the user has access to and are configured).
	 *
	 * @since 1.2.0
	 *
	 * @return array<string, AntiSpamProviderInterface>
	 */
	public function get_available_providers(): array {
		return array_filter(
			$this->providers,
			fn( AntiSpamProviderInterface $provider ) => $provider->is_available()
		);
	}

	/**
	 * Get the currently active provider.
	 *
	 * Returns the provider selected in settings, or falls back to honeypot
	 * if the selected provider is not available.
	 *
	 * @since 1.2.0
	 *
	 * @return AntiSpamProviderInterface|null The active provider or null if none available.
	 */
	public function get_active_provider(): ?AntiSpamProviderInterface {
		$selected = get_option_value( AntiSpamProviderOption::class );

		// If the selected provider is available, use it.
		if ( isset( $this->providers[ $selected ] ) && $this->providers[ $selected ]->is_available() ) {
			return $this->providers[ $selected ];
		}

		// Fall back to honeypot if available.
		if ( isset( $this->providers['honeypot'] ) && $this->providers['honeypot']->is_available() ) {
			return $this->providers['honeypot'];
		}

		return null;
	}

	/**
	 * Check if anti-spam protection is enabled.
	 *
	 * @since 1.2.0
	 *
	 * @return bool True if an active provider is available.
	 */
	public function is_enabled(): bool {
		return null !== $this->get_active_provider();
	}

	/**
	 * Render the anti-spam field(s).
	 *
	 * Outputs the HTML for the active anti-spam provider's field.
	 *
	 * @since 1.2.0
	 *
	 * @return void
	 */
	public function render_field(): void {
		$provider = $this->get_active_provider();

		if ( null === $provider ) {
			return;
		}

		$provider->render_field();
	}

	/**
	 * Get the field HTML as a string.
	 *
	 * @since 1.2.0
	 *
	 * @return string The field HTML.
	 */
	public function get_field_html(): string {
		ob_start();
		$this->render_field();
		return ob_get_clean();
	}

	/**
	 * Validate the anti-spam submission.
	 *
	 * @since 1.2.0
	 *
	 * @param array $request_data The request data (typically $_POST).
	 *
	 * @return bool True if validation passed, false if spam detected.
	 */
	public function validate( array $request_data ): bool {
		$provider = $this->get_active_provider();

		// If no provider is active, allow the request.
		if ( null === $provider ) {
			return true;
		}

		$is_valid = $provider->validate( $request_data );

		if ( ! $is_valid ) {
			$this->last_error = $provider->get_error_message();
		}

		return $is_valid;
	}

	/**
	 * Get the last error message from validation.
	 *
	 * @since 1.2.0
	 *
	 * @return string The error message.
	 */
	public function get_last_error(): string {
		if ( empty( $this->last_error ) ) {
			return __( 'Something went wrong. Please try again.', 'rewardswp' );
		}

		return $this->last_error;
	}

	/**
	 * Get the field name for the active provider.
	 *
	 * @since 1.2.0
	 *
	 * @return string The field name or empty string if no provider.
	 */
	public function get_field_name(): string {
		$provider = $this->get_active_provider();

		if ( null === $provider ) {
			return '';
		}

		return $provider->get_field_name();
	}
}

