<?php

use GP_Entry_Blocks\Blocks;
use GP_Entry_Blocks\Entry_Filters;
use GP_Entry_Blocks\Permissions;
use GP_Entry_Blocks\Compatibility;

if ( ! class_exists( 'GP_Plugin' ) ) {
	return;
}

/**
 * @todo Before 1.0 Beta: Prevent authors without gravityforms_edit_entries from manipulating the block attributes of any Entries Blocks.
 * @todo Before 1.0: does everything have a decent DocBlock?
 * @todo Add dashicons as the delete button is missing from multi file upload fields.
 */

class GP_Entry_Blocks extends \GP_Plugin {

	/* @var Blocks\Entries */
	public $block_entries;

	/* @var Blocks\Entries_Table */
	public $block_entries_table;

	/* @var Blocks\Entries_Loop */
	public $block_entries_loop;

	/* @var Blocks\Pagination */
	public $block_pagination;

	/* @var Blocks\View_Entry */
	public $block_view_entry;

	/* @var Blocks\Edit_Entry */
	public $block_edit_entry;

	/* @var Blocks\Edit_Form */
	public $block_edit_form;

	/* @var Blocks\Filters */
	public $block_filters;

	/* @var Entry_Filters */
	public $entry_filters;

	/* @var Permissions */
	public $permissions;

	/* @var GP_Entry_Blocks\Compatibility\GP_Populate_Anything */
	public $compatibility_gppa;

	/* @var GP_Entry_Blocks\Compatibility\GP_Nested_Forms */
	public $compatibility_gpnf;

	/* @var GP_Entry_Blocks | null */
	private static $instance = null;

	protected $_version     = GPEB_VERSION;
	protected $_path        = 'gp-entry-blocks/gp-entry-blocks.php';
	protected $_full_path   = __FILE__;
	protected $_slug        = 'gp-entry-blocks';
	protected $_title       = 'Gravity Forms Entry Blocks';
	protected $_short_title = 'Entry Blocks';

	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self;
		}

		return self::$instance;
	}

	public function minimum_requirements() {
		return array(
			'gravityforms' => array(
				'version' => '2.3-rc-1',
			),
			'wordpress'    => array(
				'version' => '4.8',
			),
			'plugins'      => array(
				'gravityperks/gravityperks.php' => array(
					'name'    => 'Gravity Perks',
					'version' => '2.0',
				),
			),
		);
	}

	public function init() {
		parent::init();

		require plugin_dir_path( __FILE__ ) . 'includes/functions.php';

		load_plugin_textdomain( 'gp-entry-blocks', false, basename( dirname( __file__ ) ) . '/languages/' );

		$this->block_entries       = new Blocks\Entries( __DIR__ . '/js/src/blocks/entries' );
		$this->block_entries_table = new Blocks\Entries_Table( __DIR__ . '/js/src/blocks/entries-table' );
		$this->block_entries_loop  = new Blocks\Entries_Loop( __DIR__ . '/js/src/blocks/entries-loop' );
		$this->block_pagination    = new Blocks\Pagination( __DIR__ . '/js/src/blocks/pagination' );
		$this->block_view_entry    = new Blocks\View_Entry( __DIR__ . '/js/src/blocks/view-entry' );
		$this->block_edit_entry    = new Blocks\Edit_Entry( __DIR__ . '/js/src/blocks/edit-entry' );
		$this->block_edit_form     = new Blocks\Edit_Form( __DIR__ . '/js/src/blocks/edit-form' );
		$this->block_filters       = new Blocks\Filters( __DIR__ . '/js/src/blocks/filters' );

		$this->entry_filters = new Entry_Filters();
		$this->permissions   = new Permissions();

		$this->compatibility_gppa = new Compatibility\GP_Populate_Anything();
		$this->compatibility_gpnf = new Compatibility\GP_Nested_Forms();

		$this->register_deps();
	}

	public function init_ajax() {
		parent::init_ajax();

		add_action( 'wp_ajax_gpeb_block_preview', array( $this, 'ajax_block_preview' ) );
		add_action( 'wp_ajax_gpeb_get_forms', array( $this, 'ajax_get_forms' ) );
		add_action( 'wp_ajax_gpeb_get_form', array( $this, 'ajax_get_form' ) );
		add_action( 'wp_ajax_gpeb_get_form_merge_tags', array( $this, 'ajax_get_form_merge_tags' ) );
		add_action( 'wp_ajax_gpeb_get_form_meta', array( $this, 'ajax_get_form_meta' ) );
		add_action( 'wp_ajax_gpeb_get_entry_properties', array( $this, 'ajax_get_entry_properties' ) );
		add_action( 'wp_ajax_gpeb_get_entry_property_values', array( $this, 'ajax_get_entry_property_values' ) );
	}

	public function register_deps() {
		$block_editor_asset_file           = include( plugin_dir_path( __FILE__ ) . 'js/built/block-editor.asset.php' );
		$frontend_block_entries_asset_file = include( plugin_dir_path( __FILE__ ) . 'js/built/frontend-block-entries.asset.php' );

		wp_register_script(
			'gp-entry-blocks-block-editor',
			plugins_url( 'js/built/block-editor.js', __FILE__ ),
			$block_editor_asset_file['dependencies'],
			$block_editor_asset_file['version']
		);

		wp_register_script(
			'gp-entry-blocks-frontend-block-entries',
			plugins_url( 'js/built/frontend-block-entries.js', __FILE__ ),
			$frontend_block_entries_asset_file['dependencies'],
			$frontend_block_entries_asset_file['version']
		);

		wp_set_script_translations( 'gp-entry-blocks-block-editor', 'gp-entry-blocks', plugin_dir_path( __FILE__ ) . 'languages/' );

		$block_filters = $this->block_filters;

		wp_localize_script( 'gp-entry-blocks-block-editor', 'GPEB', array(
			'blockEditorXHRNonce'              => wp_create_nonce( 'gpeb_block_editor_xhr' ),
			// Pass our own ajaxUrl in as the default window.ajaxurl may not always contain the entire URL.
			'ajaxUrl'                          => admin_url( 'admin-ajax.php' ),
			'canEditEntriesBlocks'             => GFAPI::current_user_can_any( 'gravityforms_edit_forms' ),
			'entryFilterPropertyGroups'        => $this->entry_filters->get_entry_property_groups(),
			'filterBlockUnsupportedInputTypes' => $block_filters::$unsupported_input_types,
		) );

		wp_register_style(
			'gp-entry-blocks-block-editor',
			plugins_url( 'styles/block-editor.css', __FILE__ ),
			array( 'wp-edit-blocks' )
		);

		wp_register_style(
			'gp-entry-blocks-styles',
			plugins_url( 'styles/block-styles.css', __FILE__ )
		);
	}

	public function ajax_get_form_merge_tags() {
		if ( ! check_ajax_referer( 'gpeb_block_editor_xhr', 'blockEditorXHRNonce' ) ) {
			return;
		}

		if ( ! GFAPI::current_user_can_any( 'gravityforms_edit_forms' ) ) {
			wp_send_json_error( __( 'Insufficient permissions.', 'gp-entry-blocks' ) );
			return;
		}

		$form_id = intval( rgpost( 'formId' ) );
		$form    = GFAPI::get_form( $form_id );
		$return  = array();

		if ( ! is_wp_error( $form ) ) {
			$return = GFCommon::get_merge_tags( $form['fields'], '#content' );
		}

		// Links
		$return['custom']['tags'][] = array(
			'tag'   => '{go_back_link}',
			'label' => __( 'Go Back Link', 'gp-entry-blocks' ),
		);

		$return['custom']['tags'][] = array(
			'tag'   => '{edit_link}',
			'label' => __( 'Edit Entry Link', 'gp-entry-blocks' ),
		);

		$return['custom']['tags'][] = array(
			'tag'   => '{view_link}',
			'label' => __( 'View Entry Link', 'gp-entry-blocks' ),
		);

		$return['custom']['tags'][] = array(
			'tag'   => '{delete_link}',
			'label' => __( 'Delete Entry Link', 'gp-entry-blocks' ),
		);

		$return['custom']['tags'][] = array(
			'tag'   => '{duplicate_link}',
			'label' => __( 'Duplicate Entry Link', 'gp-entry-blocks' ),
		);

		// URLs
		$return['custom']['tags'][] = array(
			'tag'   => '{go_back_url}',
			'label' => __( 'Go Back URL', 'gp-entry-blocks' ),
		);

		$return['custom']['tags'][] = array(
			'tag'   => '{edit_url}',
			'label' => __( 'Edit Entry URL', 'gp-entry-blocks' ),
		);

		$return['custom']['tags'][] = array(
			'tag'   => '{view_url}',
			'label' => __( 'View Entry URL', 'gp-entry-blocks' ),
		);

		$return['custom']['tags'][] = array(
			'tag'   => '{delete_url}',
			'label' => __( 'Delete Entry URL', 'gp-entry-blocks' ),
		);

		$return['custom']['tags'][] = array(
			'tag'   => '{duplicate_url}',
			'label' => __( 'Duplicate Entry URL', 'gp-entry-blocks' ),
		);

		wp_send_json( $return );
	}

	public function ajax_get_form_meta() {
		if ( ! check_ajax_referer( 'gpeb_block_editor_xhr', 'blockEditorXHRNonce' ) ) {
			return;
		}

		if ( ! GFAPI::current_user_can_any( 'gravityforms_edit_forms' ) ) {
			wp_send_json_error( __( 'Insufficient permissions.', 'gp-entry-blocks' ) );
			return;
		}

		$form_id = intval( rgpost( 'formId' ) );
		$return  = array();

		foreach ( GFFormsModel::get_entry_meta( $form_id ) as $meta_key => $meta ) {
			$return[] = array(
				'key'   => $meta_key,
				'label' => $meta['label'],
			);
		}

		wp_send_json( $return );
	}

	public function ajax_get_entry_properties() {
		if ( ! check_ajax_referer( 'gpeb_block_editor_xhr', 'blockEditorXHRNonce' ) ) {
			return;
		}

		if ( ! GFAPI::current_user_can_any( 'gravityforms_edit_forms' ) ) {
			wp_send_json_error( __( 'Insufficient permissions.', 'gp-entry-blocks' ) );
			return;
		}

		$form_id = intval( rgpost( 'formId' ) );

		wp_send_json( $this->entry_filters->get_entry_properties( $form_id ) );
	}

	public function ajax_get_entry_property_values() {
		if ( ! check_ajax_referer( 'gpeb_block_editor_xhr', 'blockEditorXHRNonce' ) ) {
			return;
		}

		if ( ! GFAPI::current_user_can_any( 'gravityforms_edit_forms' ) ) {
			wp_send_json_error( __( 'Insufficient permissions.', 'gp-entry-blocks' ) );
			return;
		}

		$form_id     = intval( rgpost( 'formId' ) );
		$property_id = rgpost( 'propertyId' );

		wp_send_json( $this->entry_filters->get_entry_property_values( $form_id, $property_id ) );
	}


	/**
	 * Fetches the contents as HTML of the provided block.
	 *
	 * This is used in the Block Editor. It is used in lieu of <ServerSideRender /> and its accompanying REST endpoint
	 * as it does not support block context which we heavily use for specifying the form ID, any filters, and more.
	 *
	 * @return void
	 */
	public function ajax_block_preview() {
		check_ajax_referer( 'gpeb_block_editor_xhr', 'blockEditorXHRNonce' );

		if ( ! GFAPI::current_user_can_any( 'gravityforms_edit_forms' ) ) {
			wp_send_json_error( __( 'Insufficient permissions.', 'gp-entry-blocks' ) );
			return;
		}

		$block = $this->json_block_to_wp_block( rgpost( 'block' ) );

		switch ( $block->name ) {
			case 'gp-entry-blocks/entries-table':
				wp_send_json( array(
					'html' => $this->block_entries_table->render( $block->attributes, null, $block ),
				) );
				break;

			case 'gp-entry-blocks/filters':
				wp_send_json( array(
					'html' => $this->block_filters->render( $block->attributes, null, $block ),
				) );
				break;

			default:
				wp_send_json_error( __( 'Block type does not support AJAX previews.', 'gp-entry-blocks' ) );
				break;
		}
	}

	/**
	 * Convert JSON representation of block to WP_Block.
	 *
	 * @param string Block JSON
	 *
	 * @return WP_Block
	 */
	public function json_block_to_wp_block( $json_block ) {
		$json_block_parsed = self::maybe_decode_json( $json_block );

		/* Bypass __construct() for WP_Block since we don't have the available arguments. */
		$rc = new ReflectionClass( 'WP_Block' );

		/** @var WP_Block $block */
		$block = $rc->newInstanceWithoutConstructor();

		foreach ( $json_block_parsed as $property => $property_value ) {
			$block->{$property} = $property_value;
		}

		return $block;
	}

	public function ajax_get_forms() {
		check_ajax_referer( 'gpeb_block_editor_xhr', 'blockEditorXHRNonce' );

		if ( ! GFAPI::current_user_can_any( 'gravityforms_edit_forms' ) ) {
			wp_send_json_error( __( 'Insufficient permissions.', 'gp-entry-blocks' ) );
			return;
		}

		$data = array();

		$forms = GFAPI::get_forms( true, false, 'title', 'ASC' );
		foreach ( $forms as $form ) {
			$data[] = array(
				'id'    => $form['id'],
				'title' => $form['title'],
			);
		}

		wp_send_json( $data );
	}

	public function ajax_get_form() {
		check_ajax_referer( 'gpeb_block_editor_xhr', 'blockEditorXHRNonce' );

		if ( ! GFAPI::current_user_can_any( 'gravityforms_edit_forms' ) ) {
			wp_send_json_error( __( 'Insufficient permissions.', 'gp-entry-blocks' ) );
			return;
		}

		$data = null;
		$form = GFAPI::get_form( $_REQUEST['formId'] );

		if ( $form ) {
			$data = $form;
		}

		wp_send_json( $data );
	}

}

GFAddOn::register( 'GP_Entry_Blocks' );
