<?php

namespace SugarCalendarBookings\Antispam;

use SugarCalendarBookings\Antispam\Captcha\AbstractCaptchaVerifier;
use SugarCalendarBookings\Antispam\Captcha\CaptchaVerifierRegistry;
use SugarCalendarBookings\Options;
use SugarCalendarBookings\Plugin;

/**
 * Anti-spam facade.
 *
 * Thin entry point — delegates provider knowledge to CaptchaVerifierRegistry
 * and the concrete provider classes. Owns only cross-provider concerns:
 * policy (`should_check`), dispatch (`verify`), no-conflict toggle.
 *
 * @since 1.5.0
 */
class AntispamService {

	/**
	 * Resolved active provider (lazy, one-instance).
	 *
	 * Sentinel `false` distinguishes "not yet resolved" from "resolved as null".
	 *
	 * @since 1.5.0
	 *
	 * @var AbstractCaptchaVerifier|null|false
	 */
	private $active_provider = false;

	/**
	 * The currently-active captcha provider, or null when antispam is disabled.
	 *
	 * @since 1.5.0
	 *
	 * @return AbstractCaptchaVerifier|null
	 */
	public function get_active_provider(): ?AbstractCaptchaVerifier {

		if ( $this->active_provider === false ) {
			$class                 = CaptchaVerifierRegistry::resolve_active_class();
			$this->active_provider = $class === null ? null : new $class();
		}

		return $this->active_provider;
	}

	/**
	 * Decide whether to verify the captcha for the chosen payment method.
	 *
	 * Rules:
	 *   - no active provider → false
	 *   - payment_method === 'onsite' → true
	 *   - payment_method === 'stripe' → filter result (default false)
	 *   - any other gateway → filter result (default true; fail-closed)
	 *
	 * @since 1.5.0
	 *
	 * @param string $payment_method Selected payment method literal.
	 *
	 * @return bool
	 */
	public function should_check( string $payment_method ): bool {

		if ( $this->get_active_provider() === null ) {
			return false;
		}

		if ( $payment_method === 'onsite' ) {
			return true;
		}

		$default = $payment_method !== 'stripe';

		/**
		 * Filter whether captcha verification runs for a given payment method.
		 *
		 * Default for Stripe is false — Stripe's CC step is itself a strong
		 * anti-spam barrier; site owners under CC-testing bot attack can opt
		 * back in. Future gateways default to true (fail-closed).
		 *
		 * @since 1.5.0
		 *
		 * @param bool   $check          Whether to verify on this payment path.
		 * @param string $payment_method Payment method literal (e.g. 'stripe').
		 */
		return (bool) apply_filters(
			'sugar_calendar_bookings_antispam_should_verify_payment',
			$default,
			$payment_method
		);
	}

	/**
	 * Verify a token using the active provider.
	 *
	 * @since 1.5.0
	 *
	 * @param string $token   Token captured from the client.
	 * @param string $context Verification context (e.g. 'booking_form_create').
	 *
	 * @return bool
	 */
	public function verify( string $token, string $context = '' ): bool {

		$active = $this->get_active_provider();

		if ( $active === null ) {
			return true;
		}

		return $active->verify( $token, $context );
	}

	/**
	 * Script handle for the active captcha provider.
	 *
	 * Returns null when no provider is active, so callers can short-circuit
	 * registration/enqueue without reaching into provider class constants.
	 *
	 * @since 1.5.0
	 *
	 * @return string|null
	 */
	public function get_active_script_handle(): ?string {

		$active = $this->get_active_provider();

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

		$class = get_class( $active );

		return $class::SCRIPT_HANDLE;
	}

	/**
	 * User-facing fail message from the active provider.
	 *
	 * Returns an empty string when no provider is active.
	 *
	 * @since 1.5.0
	 *
	 * @return string
	 */
	public function get_fail_message(): string {

		$active = $this->get_active_provider();

		return $active === null ? '' : $active->get_fail_message();
	}

	/**
	 * Whether no-conflict mode is enabled.
	 *
	 * @since 1.5.0
	 *
	 * @return bool
	 */
	public function is_no_conflict_enabled(): bool {

		return (bool) Plugin::get( Options::class )->get( 'antispam.no_conflict' );
	}
}
