<?php
/**
 * Google reCAPTCHA support
 *
 * Verifies a reCAPTCHA token against Google's siteverify endpoint using the
 * keys configured in the Kirki admin common data option.
 *
 * @package kirki
 */

namespace Kirki\App\Supports;

use Kirki\Framework\Http\Response;
use Kirki\Framework\Supports\Facades\Http;
use Kirki\App\Supports\Session;
use RuntimeException;

if (!defined('ABSPATH')) {
	exit; // Exit if accessed directly.
}

class Recaptcha
{
	/**
	 * Google reCAPTCHA verification endpoint.
	 *
	 * @var string
	 */
	public const VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';

	/**
	 * Verify a reCAPTCHA token.
	 *
	 * No-op when no token is supplied (matches the legacy behaviour where the
	 * check only runs if the front-end sent a token). Throws on misconfiguration
	 * or a failed verification so the caller can abort the request.
	 *
	 * @param array|null $params Get the reCAPTCHA token from the submission params.
	 * @param string|null $form_id The form ID.
	 * @return void
	 *
	 * @throws RuntimeException When configuration is missing or verification fails.
	 */
	public static function verify(?array $params = [], ?string $form_id = null)
	{
		$session_data = Session::get($form_id);
		$recaptcha = $session_data['recaptcha'] ?? [];

		if (empty($recaptcha)) {
			return;
		}

		if (!isset($recaptcha['GRC_version'])) {
			throw new RuntimeException(
				esc_html__('reCAPTCHA configuration not found', 'kirki'),
				(int) Response::BAD_REQUEST
			);
		}

		$token = $recaptcha['GRC_version'] === '2.0' ? ($params['g-recaptcha-response'] ?? '') : ($params['g-recaptcha-token'] ?? '');

		if (empty($token)) {
			throw new RuntimeException(
				esc_html__('Recaptcha is required.', 'kirki'),
				(int) Response::BAD_REQUEST
			);
		}

		$secret_key = $recaptcha['GRC_secret_key'] ?? '';

		if (empty($secret_key)) {
			throw new RuntimeException(
				esc_html__('reCAPTCHA secret key not configured', 'kirki'),
				(int) Response::BAD_REQUEST
			);
		}

		if (!static::is_token_valid($secret_key, $token)) {
			throw new RuntimeException(
				esc_html__('Google reCAPTCHA verification failed', 'kirki'),
				(int) Response::BAD_REQUEST
			);
		}
	}

	/**
	 * Call Google's siteverify endpoint for the given token.
	 *
	 * @param string $secret_key The reCAPTCHA secret key.
	 * @param string $token      The reCAPTCHA token.
	 * @return bool
	 */
	protected static function is_token_valid(string $secret_key, string $token)
	{
		$response = Http::as_form()->post(
			static::VERIFY_URL,
			[
				'secret' => $secret_key,
				'response' => $token,
			]
		);

		if ($response->failed()) {
			return false;
		}

		return (bool) $response->json('success');
	}
}
