<?php
/**
 * Please see weepie-framework.php for more details.
 */

namespace WpieFw\Hooks;

use WpieFw\Exceptions\WpieExceptionInterface;
use WpieFw\Exceptions\WpieExceptionLogger;
use WpieFw\Exceptions\WpieUnexpectedValueException;
use WpieFw\Helpers\WpieAjaxHelper;
use WpieFw\Helpers\WpieMiscHelper;
use WpieFw\Wpie\WpieGlobals;

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

/**
 * WpieHooks Class
 *
 * @author $Author: Vincent Weber <weepie-plugins@outlook.com> $
 * @since 1.4.0
 */
abstract class WpieHooks implements WpieHooksInterface
{
	/**
	 * Flag if frontend hooks should be added
	 *
	 * @since 1.4.0
	 *
	 * @var boolean
	 */
	public $doFrontend = true;

	/**
	 * WpieGlobals instance
	 *
	 * @since 1.4.0
	 * @since 2.0 WpieGlobals instead of WpiePluginGlobals
	 *
	 * @var WpieGlobals
	 */
	protected $globals;

	/**
	 * Constructor
	 *
	 * @access public
	 *
	 * @param WpieGlobals $globals
	 *
	 * @since 1.4.0
	 */
	public function __construct( WpieGlobals $globals )
	{
		$this->globals = $globals;
	}

	/**
	 * Callback for (WordPress) AJAX hook system
	 *
	 * This callback is also hooked to the 'wp_footer' action for AJAX requests made in the WordPress footer.
	 *
	 * WeePie Framework Plugins should always provide the following REQUEST parameters in their JavaScript AJAX CALL:
	 *
	 * 	- action: wpie-action
	 * 	- YOUR_PLUGIN_NAMESPACE_action: [UNIQUE_ACTION] to add an unique action for the AJAX CALL
	 * 	- nonce: [YOUR_PLUGIN_NAMESPACE]Data.nonce (WeePie Framework automaticly adds in some JavaScript parameters inlcuded a nonce
	 * 	- data  (optional): extra data to pass from client-side to here
	 *
	 * Example for jQuery with Plugin namespace "myplugin" : $.post(mypluginData.ajaxurl, {action:'wpie-action', myplugin_action:'do-some-logic', nonce: mypluginData.nonce, data:{'foo':bar, 'food':bars}}, function(r) { ... });
	 *
	 * @since 1.0
	 *
	 * @returns void on missing YOUR_PLUGIN_NAMESPACE_action, a raw output or an json encoded array
	 */
	public function processAjaxRequest()
	{
		$state = 1;
		$r = [
			'state' => (string)$state,
			'out' => '',
			'errors' => []
		];

		try {
			if( !isset( $_REQUEST[$this->globals->nameSpace . '_action'] ) ) {
				return;
			}

			//@TODO test additional if condition with WPIE_DOING_AJAX (set in WeePieFramework::start())
			//@TODO if has group meta, data is inside data[post_meta]

			$action = $_REQUEST[$this->globals->nameSpace . '_action'];
			$data = ( isset($_REQUEST['data']) ) ? $_REQUEST['data'] : null;
			$context = ( isset( $data['context'] ) ) ? $data['context'] : null;

			if( false === check_ajax_referer( $this->globals->nameSpace . '-action', 'nonce', false ) ) {
				throw new WpieUnexpectedValueException( 'failed verifying nonce' );
			}

			/**
			 * @todo description for hook activate_{$nameSpace}_before_process_ajax_request
			 * @todo place this filter after {nameSpace}_validate_ajax_data ?
			 */
			do_action( $this->globals->nameSpace . '_before_process_ajax_request', $action, $data );

			$validateReturn = [
				'is_valid' => true,
				'fields' => [],
				'msg' => null
			];

			/**
			 * Let modules validate the ajax data for specific context
			 *
			 * @param	array $validateReturn
			 * @param	string the current AJAX action
			 * @param	array	the AJAX data
			 *
			 * @since	1.4.6
			 *
			 * @return	array
			 */
			$validateReturn = apply_filters( $this->globals->nameSpace . '_validate_ajax_data_' . $context, $validateReturn, $action, $data );

			/**
			 * Let modules validate the ajax data before processing it
			 *
			 * @param	array	$validateReturn
			 * @param	string	the current AJAX action
			 * @param	array	the AJAX data
			 * @param	string	the context	- optional
			 *
			 * @since	1.2.1
			 *
			 * @return	array
			 */
			$validateReturn = apply_filters( $this->globals->nameSpace . '_validate_ajax_data', $validateReturn, $action, $data, $context );

			if( isset( $validateReturn['is_valid'] ) && true == $validateReturn['is_valid'] ) {
				/**
				 * @todo description for hook activate_{$nameSpace}_ajax_json_return
				 */
				$return = apply_filters( $this->globals->nameSpace . '_ajax_json_return', null, $action, $data );

				if( null === $return ) {
					echo json_encode( $return );
					exit;
				}

				/**
				 * @todo description for hook activate_{$nameSpace}_after_process_ajax_request
				 * @todo: add $data param
				 */
				do_action( $this->globals->nameSpace . '_after_process_ajax_request', $action, $return );

				if( is_array( $return ) && isset( $return['content'] ) ) {
					echo $return['content'];
					exit;
				}

				// allow data to be validated with bool false values
				// @since 1.1.8
				$allowFalse = ( is_array( $return ) && isset( $return['allow_false'] ) );

				$state = WpieAjaxHelper::isValidData( $return, $allowFalse ); // 1 or 0

				if(  0 === $state && isset( $return['errors'] ) ) {
					$r['errors'] = array_merge( $r['errors'],  [ $return['errors'] ] );
				} elseif(  0 === $state && isset( $return['msg'] ) ) {
					$r['errors'] = array_merge( $r['errors'],  [ $return['msg'] ] );
				} elseif( 1 === $state ) {
					$r['out'] = $return;
				}

				if( WpieAjaxHelper::hasWpError( $return ) ) {
					$r['errors'] = array_merge( $r['errors'],  WpieAjaxHelper::getWpErrors( $return ) );
				}
			} else {
				// if not valid, see if the implemented hook has send:
				// an error msg (may be msg or error)

				if( isset( $validateReturn['msg'] ) ) {
					$r['errors'][] = $validateReturn['msg'];
				}
				if( isset( $validateReturn['error'] ) ) {
					$r['errors'][] = $validateReturn['error'];
				}
			}
		} catch( WpieExceptionInterface $e ) {
			// log the Exceptions
			WpieExceptionLogger::log( $e );

			if( WpieMiscHelper::isDebugModeLoggedIn() ) {
				$r['errors'][] = $e->getMessage();
			}
		}

		$r['state'] = (string)$state;
		echo json_encode( $r );
		exit;
	}
}