<?php
/**
 * CaptchaEngine — provider-agnostic CAPTCHA support for Login Limiter.
 *
 * Supports Cloudflare Turnstile and Google reCAPTCHA v2/v3 on the WordPress
 * login page. Rendering and verification are fully handled server-side using
 * WordPress APIs and stored module settings.
 *
 * @package UltraguardPro\modules\loginlimiter
 */

namespace UltraguardPro\modules\loginlimiter;

use UltraguardPro\Plugin;
use UltraguardPro\core\Logger;
use UltraguardPro\core\Utils;

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

class CaptchaEngine {

    public const PROVIDER_TURNSTILE    = 'turnstile';
    public const PROVIDER_RECAPTCHA_V2 = 'recaptcha_v2';
    public const PROVIDER_RECAPTCHA_V3 = 'recaptcha_v3';

    private const TURNSTILE_VERIFY_URL = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
    private const RECAPTCHA_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';

    private Plugin $plugin;

    public function __construct( Plugin $plugin ) {
        $this->plugin = $plugin;
    }

    /**
     * Inject the configured CAPTCHA widget into the login form.
     */
    public function inject_login_form_widget(): void {
        $provider = $this->get_provider();
        $site_key = $this->get_site_key();

        if ( '' === $site_key ) {
            return;
        }

        echo '<div class="ultraguard-login-captcha" style="margin:16px 0;">';

        if ( self::PROVIDER_TURNSTILE === $provider ) {
            echo '<div class="cf-turnstile" data-sitekey="' . esc_attr( $site_key ) . '"></div>';
        } elseif ( self::PROVIDER_RECAPTCHA_V2 === $provider ) {
            echo '<div class="g-recaptcha" data-sitekey="' . esc_attr( $site_key ) . '"></div>';
        } elseif ( self::PROVIDER_RECAPTCHA_V3 === $provider ) {
            echo '<input type="hidden" name="g-recaptcha-response" id="ultraguard-recaptcha-v3-response" value="">';
        }

        echo '</div>';
    }

    /**
     * Enqueue the CAPTCHA provider script on the login page.
     */
    public function enqueue_scripts(): void {
        $provider = $this->get_provider();
        $site_key = $this->get_site_key();

        if ( '' === $site_key ) {
            return;
        }

        wp_enqueue_script(
            'ultraguard-captcha-loader',
            ULTRAGUARD_PRO_URL . 'assets/js/ultraguard-captcha-loader.js',
            [],
            ULTRAGUARD_PRO_VERSION,
            true
        );

        wp_add_inline_script(
            'ultraguard-captcha-loader',
            'window.ultraguardCaptchaConfigs = window.ultraguardCaptchaConfigs || []; window.ultraguardCaptchaConfigs.push(' . wp_json_encode(
                [
                    'provider' => $provider,
                    'siteKey'  => $site_key,
                    'context'  => 'login',
                ]
            ) . ');',
            'before'
        );
    }

    /**
     * Verify a submitted CAPTCHA token with the configured provider.
     */
    public function verify( string $token ): bool {
        $provider   = $this->get_provider();
        $secret_key = $this->get_secret_key();
        $token      = sanitize_text_field( $token );

        if ( '' === $provider || '' === $secret_key || '' === $token ) {
            return false;
        }

        $response = wp_remote_post(
            self::PROVIDER_TURNSTILE === $provider ? self::TURNSTILE_VERIFY_URL : self::RECAPTCHA_VERIFY_URL,
            [
                'timeout' => 15,
                'body'    => [
                    'secret'   => $secret_key,
                    'response' => $token,
                    'remoteip' => Utils::get_client_ip(),
                ],
            ]
        );

        if ( is_wp_error( $response ) ) {
            Logger::warning( '[CaptchaEngine] CAPTCHA verification request failed.', [
                'provider' => $provider,
                'message'  => $response->get_error_message(),
            ] );
            return false;
        }

        $body = json_decode( (string) wp_remote_retrieve_body( $response ), true );
        if ( ! is_array( $body ) || empty( $body['success'] ) ) {
            return false;
        }

        if ( self::PROVIDER_RECAPTCHA_V3 === $provider ) {
            $score     = (float) ( $body['score'] ?? 0 );
            $threshold = (float) $this->plugin->settings->get_option( 'loginlimiter_recaptcha_v3_min_score', 0.5 );

            return $score >= max( 0.1, min( $threshold, 1.0 ) );
        }

        return true;
    }

    /**
     * Determine whether CAPTCHA should be shown for the current IP address.
     */
    public function should_show( string $ip ): bool {
        if ( ! $this->plugin->settings->get_option( 'loginlimiter_captcha_enabled', false ) ) {
            return false;
        }

        if ( '' === $this->get_site_key() || '' === $this->get_secret_key() ) {
            return false;
        }

        $after = (int) $this->plugin->settings->get_option( 'loginlimiter_captcha_after', 3 );
        if ( $after <= 0 ) {
            return true;
        }

        $table = $this->plugin->modules->get_db_tables()->get_table( 'login_attempts' );
        if ( ! $table || ! method_exists( $table, 'count_failures' ) ) {
            return false;
        }

        $window_minutes = (int) $this->plugin->settings->get_option( 'loginlimiter_attempt_window', 10 );
        return (int) $table->count_failures( $ip, $window_minutes ) >= $after;
    }

    /**
     * Return the configured CAPTCHA provider.
     */
    public function get_provider(): string {
        $provider = (string) $this->plugin->settings->get_option( 'loginlimiter_captcha_provider', self::PROVIDER_TURNSTILE );

        return in_array( $provider, [ self::PROVIDER_TURNSTILE, self::PROVIDER_RECAPTCHA_V2, self::PROVIDER_RECAPTCHA_V3 ], true )
            ? $provider
            : self::PROVIDER_TURNSTILE;
    }

    /**
     * Return the current provider's public site key.
     */
    public function get_site_key(): string {
        $provider = $this->get_provider();

        if ( self::PROVIDER_TURNSTILE === $provider ) {
            return (string) $this->plugin->settings->get_option( 'loginlimiter_turnstile_site_key', '' );
        }

        if ( in_array( $provider, [ self::PROVIDER_RECAPTCHA_V2, self::PROVIDER_RECAPTCHA_V3 ], true ) ) {
            return (string) $this->plugin->settings->get_option( 'loginlimiter_recaptcha_site_key', '' );
        }

        return '';
    }

    /**
     * Return the current provider's secret key.
     */
    private function get_secret_key(): string {
        $provider = $this->get_provider();

        if ( self::PROVIDER_TURNSTILE === $provider ) {
            return (string) $this->plugin->settings->get_option( 'loginlimiter_turnstile_secret_key', '' );
        }

        if ( in_array( $provider, [ self::PROVIDER_RECAPTCHA_V2, self::PROVIDER_RECAPTCHA_V3 ], true ) ) {
            return (string) $this->plugin->settings->get_option( 'loginlimiter_recaptcha_secret_key', '' );
        }

        return '';
    }
}
