<?php
namespace SabaiApps\Directories\Component\Captcha\Api;

use SabaiApps\Directories\Component\Form\Form;
use SabaiApps\Directories\Exception;

abstract class AbstractReCaptchaApi extends AbstractApi {

	protected static $_jsLoaded, $_preRenderAdded = array();

	public function _validateCaptcha( Form $form, $secret, $trigger, $id, $element = null, $action = null, $minScore = null ) {
		if ( isset( $trigger ) && ! $form->getValue( $trigger ) ) {
			return;
		}

		if ( ! isset( $_POST[ $id ] )
			|| ! strlen( $_POST[ $id ] )
		) {
			if ( isset( $element ) ) {
				$form->setError( __( 'Please fill out this field.', 'directories-pro' ), $element );
			} else {
				$form->setError( __( 'Failed validating captcha value.', 'directories-pro' ) );
			}
		} elseif ( true !== $result = $this->_verify( $secret, $_POST[ $id ], $action, $minScore ) ) {
				$error = $result['error'];
			if ( ! empty( $result['error_codes'] ) ) {
				$error .= ' (' . implode( ',', $result['error_codes'] ) . ')';
			}
				$form->setError( $error, isset( $element ) ? $element : '' );
		}
		if ( empty( self::$_preRenderAdded[ $form->settings['#id'] ] ) ) {
			$form->settings['#pre_render'][]                 = array( $this, '_preRenderCallback' );
			self::$_preRenderAdded[ $form->settings['#id'] ] = true;
		}
	}

	public function _preRenderCallback( $form ) {
		if ( $form->hasError() ) {
			$form->settings['#js_ready'][] = 'sabaiReCaptchaCallback();';
		}
	}

	protected function _verify( $secret, $value, $action = null, $minScore = null ) {
		if ( empty( $secret ) ) {
			throw new Exception\InvalidArgumentException( __( 'Invalid captcha secret key.', 'directories-pro' ) );
		}

		if ( empty( $value ) ) {
			throw new Exception\InvalidArgumentException( __( 'Invalid captcha value.', 'directories-pro' ) );
		}

		$url = 'https://www.google.com/recaptcha/api/siteverify?' . http_build_query(
			array(
				'secret'   => $secret,
				'response' => $value,
				'remoteip' => $this->_getIp(),
			)
		);
		if ( ( ! $json = $this->_application->getPlatform()->remoteGet( $url ) )
			|| ( ! $response = json_decode( $json, true ) )
		) {
			$this->_application->logError( 'Failed obtaining valid reCAPTCHA verify response from ' . $url );
			throw new Exception\RuntimeException( __( 'Failed obtaining valid reCAPTCHA verify response.', 'directories-pro' ) );
		}

		// Check response
		if ( empty( $response['success'] ) ) {
			$error = __( 'Unknown error.', 'directories-pro' );
			if ( ! empty( $response['error-codes'] ) ) {
				switch ( $response['error-codes'][0] ) {
					case 'missing-input-secret':
					case 'invalid-input-secret':
						$error = __( 'Invalid or missing secret parameter.', 'directories-pro' );
						break;
					case 'missing-input-response':
					case 'invalid-input-response':
						$error = __( 'Invalid or missing response parameter', 'directories-pro' );
						break;
					case 'bad-request':
						$error = __( 'Invalid or malformed request.', 'directories-pro' );
						break;
				}
			}
			return array(
				'error'       => $error,
				'error_codes' => empty( $response['error-codes'] ) ? array() : $response['error-codes'],
			);
		}

		// Check action?
		if ( isset( $action )
			&& $action !== $response['action']
		) {
			return array( 'error' => __( 'Invalid action.', 'directories-pro' ) );
		}

		// Check score?
		if ( ! empty( $minScore )
			&& isset( $response['score'] )
			&& $response['score'] < $minScore
		) {
			return array( 'error' => __( 'Request denied.', 'directories-pro' ) );
		}

		return true;
	}
}
