<?php
namespace ReyCore\Modules\OffcanvasPanels;

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

class Base extends \ReyCore\Modules\ModuleBase {

	private $settings = [];

	public $added = [];

	private $offcanvas_panels;

	private static $prevent_cached_ids = [];

	const GSTYPE = 'offcanvas';

	const ASSET_HANDLE = 'reycore-offcanvas-panels';

	const AJAX_LAZY_ACTION = 'get_offcanvas_panel';

	public function __construct()
	{
		add_action( 'init', [$this, 'init'] );
		add_filter( 'reycore/global_sections/types', [$this, 'add_gs_support']);
		add_filter( 'reycore/acf/global_section_icons', [$this, 'add_icon'], 20);
		add_filter( 'reycore/acf/global_section_descriptions', [$this, 'add_description'], 20);
		add_action( 'reycore/elementor/document_settings/gs', [$this, 'gs_settings'], 10, 3);
		add_action( 'reycore/ajax/register_actions', [ $this, 'register_actions' ] );
		add_action( 'save_post', [$this, 'flush_offcanvas_transient_ids'], 20, 2 );
		add_action( 'delete_post', [$this, 'flush_offcanvas_transient_ids'], 20, 2 );
	}

	public function init()
	{
		if( ! $this->is_enabled() ){
			return;
		}

		add_action( 'reycore/assets/register_scripts', [$this, 'register_assets']);
		add_action( 'reycore/elementor/btn_trigger', [ $this, 'init_content'] );
		add_action( 'reycore/elementor/header_nav/offcanvas', [ $this, 'init_content'] );
		add_action( 'wp_enqueue_scripts', [ $this, 'force_init_content'] );
		add_action(	'wp_footer', [$this, 'prevent_panel_caching'], 20);
		add_filter( 'reycore/global_section_template/attributes', [$this, 'editor_gs_attribute'], 10, 2 );

	}

	public function add_gs_support( $gs ){
		$gs[self::GSTYPE]  = __( 'Off-Canvas Panel', 'rey-core' );
		return $gs;
	}

	public function add_description( $gs ){
		$gs[self::GSTYPE]  = sprintf( _x('Create and display any type of content into animated side panels. <a href="%s" target="_blank">Learn More</a>.', 'Global section description', 'rey-core'), reycore__support_url('/kb/off-canvas-global-sections/') );
		return $gs;
	}

	public function add_icon( $gs ){
		$gs[self::GSTYPE]  = 'woo-pdp-components-in-summary';
		return $gs;
	}

	public function force_init_content(){

		if( ! get_theme_mod('perf__offcanvas_load_always', false) ){
			return;
		}

		$this->init_content();
	}

	public function register_assets($assets){

		$assets->register_asset('styles', [
			self::ASSET_HANDLE => [
				'src'      => self::get_path( basename( __DIR__ ) ) . '/style.css',
				'deps'     => [],
				'version'  => REY_CORE_VERSION,
				'priority' => 'low',
				'lazy_assets' => "a[href^='#offcanvas-']",
			]
		]);

		$assets->register_asset('scripts', [
			self::ASSET_HANDLE => [
				'src'     => self::get_path( basename( __DIR__ ) ) . '/script.js',
				'deps'    => ['animejs', 'rey-simple-scrollbar', 'reycore-elementor-frontend'],
				'version'   => REY_CORE_VERSION,
				'lazy_assets' => "a[href^='#offcanvas-']",
			]
		]);
	}

	public function init_content(){

		reycore_assets()->add_styles(['rey-overlay', self::ASSET_HANDLE, 'rey-simple-scrollbar']);
		reycore_assets()->add_scripts(self::ASSET_HANDLE);

		// run only if triggers are inside the page, or set to force
		add_action(	'wp_footer', [$this, 'add_panels']);

	}

	public function editor_gs_attribute($attributes, $type){

		if( $type === self::GSTYPE ){

			$page_id = get_the_ID();

			if( get_post_type() === 'revision' && ($rev_id = wp_get_post_parent_id($page_id)) && $rev_id !== 0 ){
				$page_id = $rev_id;
			}

			$attributes['data-position'] = ($pos = \ReyCore\Elementor\Helper::get_elementor_option( $page_id, 'offcanvas_position' )) ? $pos : 'left';
			$attributes['data-disable-padding'] = '';
		}

		return $attributes;
	}

	public function panel_settings_defaults( $setting = '' ){

		$settings = [
			'offcanvas_position'             => 'left',
			'offcanvas_close_position'       => 'inside',
			'offcanvas_close_text'           => '',
			'offcanvas_close_outside_rotate' => '',
			'offcanvas_transition'           => '',
			'offcanvas_transition_duration'  => 700,
			'offcanvas_animate_cols'         => 'yes',
			'offcanvas_shift_site'           => 'yes',
			'offcanvas_lazyload'             => '',
			'offcanvas_lazyload_cache'       => 'yes',
		];

		if( isset($settings[$setting]) ){
			return $settings[$setting];
		}

		return $settings;
	}

	/**
	 * Publish all available and non-lazy loaded panels
	 *
	 * @return void
	 */
	public function add_panels(){

		foreach ($this->get_offcanvas_panels() as $id => $gs):

			if( reycore__is_multilanguage() ){
				$id = apply_filters('reycore/translate_ids', $id, \ReyCore\Elementor\GlobalSections::POST_TYPE);
			}

			if( in_array($id, $this->added, true) ){
				continue;
			}

			if( ! apply_filters("reycore/module/offcanvas_panels/load_panel={$id}", false) ){
				continue;
			}

			if( ! ( $settings = $this->get_settings($id) ) ){
				continue;
			}

			$this->added[] = $id;

			// markup will be loaded through Ajax
			if( isset($settings['offcanvas_lazyload']) && $settings['offcanvas_lazyload'] !== '' ){
				if( isset($settings['offcanvas_lazyload_cache']) && $settings['offcanvas_lazyload_cache'] === '' ){
					self::$prevent_cached_ids[] = $id;
				}
				continue;
			}

			$this->make_markup( $id, $settings );

		endforeach;
	}

	/**
	 * Create offcanvas panel's markup and print the Global section
	 *
	 * @param int $id
	 * @param array $settings
	 * @return void
	 */
	public function make_markup($id, $settings){

		if( get_post_type() === \ReyCore\Elementor\GlobalSections::POST_TYPE ){
			return;
		}

		$attributes = [
			'data-gs-id'               => $id,
			'data-transition'          => $settings['offcanvas_transition'],
			'data-transition-duration' => $settings['offcanvas_transition_duration'],
			'data-position'            => $settings['offcanvas_position'],
			'data-close-position'      => $settings['offcanvas_close_position'],
			'data-close-rotate'        => $settings['offcanvas_close_outside_rotate'],
			'data-animate-cols'        => $settings['offcanvas_animate_cols'],
			'data-shift'               => $settings['offcanvas_shift_site'],
		]; ?>

		<div class="rey-offcanvas-wrapper --hidden" <?php echo reycore__implode_html_attributes($attributes) ?> >
			<div class="rey-offcanvas-contentWrapper">
				<button class="rey-offcanvas-close" aria-label="<?php esc_html_e('Close', 'rey-core') ?>" >
					<span class="rey-offcanvas-closeText"><?php echo $settings['offcanvas_close_text'] ?></span>
					<?php echo reycore__get_svg_icon(['id' => 'close', 'class' => 'icon-close']) ?>
				</button>
				<div class="rey-offcanvas-content">
					<?php
						reycore_assets()->defer_page_styles('elementor-post-' . $id, true);
						echo \ReyCore\Elementor\GlobalSections::do_section( $id, false, true );
					?>
				</div>
			</div>
			<div class="rey-lineLoader"></div>
		</div>
		<?php
	}

	public function register_actions( $ajax_manager ){
		$ajax_manager->register_ajax_action( self::AJAX_LAZY_ACTION, [$this, 'ajax__get_offcanvas_panel_content'], [
			'auth'      => 3,
			'nonce'     => false,
			'assets'    => true, // in case cache is disabled
			'transient' => [
				'expiration'         => 2 * WEEK_IN_SECONDS,
				'unique_id'          => 'gs',
				'unique_id_sanitize' => 'absint',
			],
		] );
	}

	/**
	 * Retrieve the panel's content via Ajax
	 *
	 * @param array $data
	 * @return void
	 */
	public function ajax__get_offcanvas_panel_content( $data ){

		if( ! (isset($data['panel_id']) && ($id = absint($data['panel_id']))) ){
			return ['errors'=> esc_html__('Missing Global Section.', 'rey-core')];
		}

		if( ! class_exists('\ReyCore\Elementor\GlobalSections') ){
			return ['errors'=> esc_html__('Elementor is disabled?', 'rey-core')];
		}

		if( reycore__is_multilanguage() ){
			$id = apply_filters('reycore/translate_ids', $id, \ReyCore\Elementor\GlobalSections::POST_TYPE);
		}

		if( ! ( $settings = $this->get_settings($id) ) ){
			return ['errors'=> esc_html__('Cannot retrieve settings!', 'rey-core')];
		}

		ob_start();
		$this->make_markup($id, $settings);
		return ob_get_clean();

	}

	public function get_settings($id){

		if( ($settings = get_post_meta( $id, \Elementor\Core\Settings\Page\Manager::META_KEY, true )) === false ){
			return;
		}

		return wp_parse_args($settings, $this->panel_settings_defaults());
	}

	public function prevent_panel_caching(){

		if( empty(self::$prevent_cached_ids) ){
			return;
		}
		printf('<script type="text/javascript">var offcanvasUncached = [%s];</script>', implode(',', self::$prevent_cached_ids));
	}

	/**
	 * Add page settings into Elementor
	 *
	 * @since 1.7.0
	 */
	function gs_settings( $page, $gs_type, $page_id )
	{

		$page->add_control(
			'offcanvas_panel_heading',
			[
				'label' => esc_html__( 'OFFCANVAS SETTINGS', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::HEADING,
				'separator' => 'before',
				'condition' => [
					'gs_type' => self::GSTYPE,
				],
			]
		);

		$panel_selector = sprintf('.rey-offcanvas-wrapper[data-gs-id="%s"]', $page_id);

		$page->add_responsive_control(
			'offcanvas_width',
			[
				'label' => esc_html__( 'Panel Size', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::SLIDER,
				'size_units' => [ 'px', 'vw', 'vh' ],
				'range' => [
					'px' => [
						'min' => 200,
						'max' => 3000,
						'step' => 1,
					],
					'vw' => [
						'min' => 10,
						'max' => 100,
					],
					'vh' => [
						'min' => 5,
						'max' => 100,
					],
				],
				'default' => [
					'size' => 400,
					'unit' => 'px',
				],
				'selectors' => [
					'(desktop)' . $panel_selector => '--panel-width: {{SIZE}}{{UNIT}};',
					'(tablet)' . $panel_selector => '--panel-width-tablet: {{SIZE}}{{UNIT}};',
					'(mobile)' . $panel_selector => '--panel-width-mobile: {{SIZE}}{{UNIT}};',
					'{{WRAPPER}}' => '--gs-preview-width: {{SIZE}}{{UNIT}};',
				],
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		$page->add_control(
			'position_notice_x',
			[
				'type' => \Elementor\Controls_Manager::RAW_HTML,
				'raw' => __( 'Set the panel <strong>WIDTH</strong>.', 'rey-core' ),
				'content_classes' => 'rey-raw-html',
				'condition' => [
					'offcanvas_position' => ['left', 'right'],
				],
			]
		);

		$page->add_control(
			'position_notice_y',
			[
				'type' => \Elementor\Controls_Manager::RAW_HTML,
				'raw' => __( 'Set the panel <strong>HEIGHT</strong>.', 'rey-core' ),
				'content_classes' => 'rey-raw-html',
				'condition' => [
					'offcanvas_position' => ['top', 'bottom'],
				],
			]
		);

		$page->add_control(
			'offcanvas_bgcolor',
			[
				'label' => esc_html__( 'Background Color', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::COLOR,
				'selectors' => [
					$panel_selector => '--panel-color:{{VALUE}}',
					'{{WRAPPER}}' => '--gs-preview-bg:{{VALUE}}',
				],
				'separator' => 'before',
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		$page->add_control(
			'offcanvas_position',
			[
				'label' => esc_html__( 'Position', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::SELECT,
				'default' => 'left',
				'options' => [
					'left'  => esc_html__( 'Left', 'rey-core' ),
					'right'  => esc_html__( 'Right', 'rey-core' ),
					'top'  => esc_html__( 'Top', 'rey-core' ),
					'bottom'  => esc_html__( 'Bottom', 'rey-core' ),
				],
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		// -----

		$page->add_control(
			'offcanvas_transition',
			[
				'label' => esc_html__( 'Transition', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::SELECT,
				'default' => '',
				'options' => [
					''  => esc_html__( 'Default (Slide)', 'rey-core' ),
					'slideskew'  => esc_html__( 'Slide Skew', 'rey-core' ),
					'curtain'  => esc_html__( 'Curtain', 'rey-core' ),
					'basic'  => esc_html__( 'Basic', 'rey-core' ),
				],
				'separator' => 'before',
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		$page->add_control(
			'offcanvas_transition_duration',
			[
				'label' => esc_html__( 'Transition Duration', 'rey-core' ) . ' (ms)',
				'type' => \Elementor\Controls_Manager::NUMBER,
				'default' => 700,
				'min' => 0,
				'max' => 2000,
				'step' => 10,
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
				'selectors' => [
					$panel_selector => '--transition-duration: {{VALUE}}ms;',
				],
			]
		);

		$page->add_control(
			'offcanvas_animate_cols',
			[
				'label' => esc_html__( 'Animate Inside', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::SWITCHER,
				'default' => 'yes',
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		$page->add_control(
			'offcanvas_shift_site',
			[
				'label' => esc_html__( 'Shift Site Content', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::SWITCHER,
				'default' => 'yes',
				'condition' => [
					'gs_type' =>self::GSTYPE,
					'offcanvas_position' => ['left', 'right'],
				],
			]
		);

		$page->add_control(
			'offcanvas_curtain__m1_color',
			[
				'type' => \Elementor\Controls_Manager::COLOR,
				'label' => esc_html__( 'Curtain - Mask #1 Color', 'rey-core' ),
				'selectors' => [
					$panel_selector . ' .rey-offcanvas-mask.--m1' => 'background-color: {{VALUE}}',
				],
				'condition' => [
					'gs_type' =>self::GSTYPE,
					'offcanvas_transition' => 'curtain',
				],
			]
		);

		$page->add_control(
			'offcanvas_curtain__m2_color',
			[
				'type' => \Elementor\Controls_Manager::COLOR,
				'label' => esc_html__( 'Curtain - Mask #2 Color', 'rey-core' ),
				'selectors' => [
					$panel_selector . ' .rey-offcanvas-mask.--m2' => 'background-color: {{VALUE}}',
				],
				'condition' => [
					'gs_type' =>self::GSTYPE,
					'offcanvas_transition' => 'curtain',
				],
			]
		);

		$page->add_control(
			'offcanvas_lazyload',
			[
				'label' => esc_html__( 'Lazy Load Content', 'rey-core' ),
				'description' => esc_html__( 'Enabling this option will force the content to load only on demand (when button is clicked), via Ajax.', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::SWITCHER,
				'default' => '',
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		$page->add_control(
			'offcanvas_lazyload_cache',
			[
				'label' => esc_html__( 'Cache Ajax Response?', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::SWITCHER,
				'default' => $this->panel_settings_defaults('offcanvas_lazyload_cache'),
				'condition' => [
					'gs_type' =>self::GSTYPE,
					'offcanvas_lazyload!' =>'',
				],
			]
		);

		// Close

		$page->add_control(
			'close_heading',
			[
			   'label' => esc_html__( 'Close Button', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::HEADING,
				'separator' => 'before',
			]
		);

		$page->add_control(
			'offcanvas_close_position',
			[
				'label' => esc_html__( 'Close Position', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::SELECT,
				'default' => 'inside',
				'options' => [
					'inside'  => esc_html__( 'Inside', 'rey-core' ),
					'outside'  => esc_html__( 'Outside', 'rey-core' ),
				],
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		$page->add_control(
			'offcanvas_close_text',
			[
				'label' => esc_html__( 'Close text', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::TEXT,
				'default' => '',
				'placeholder' => esc_html__( 'eg: Close', 'rey-core' ),
				'selectors' => [
					$panel_selector => '--close-text: "{{VALUE}}";',
				],
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		$page->add_control(
			'offcanvas_close_outside_rotate',
			[
				'label' => esc_html__( 'Rotate Button', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::SWITCHER,
				'default' => '',
				'condition' => [
					'gs_type' =>self::GSTYPE,
					'offcanvas_position' => ['left', 'right'],
					'offcanvas_close_position' => 'outside',
					'offcanvas_close_text!' => '',
				]
			]
		);

		$page->add_control(
			'offcanvas_close_size',
			[
				'label' => esc_html__( 'Close Size', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::NUMBER,
				'default' => '',
				'min' => 8,
				'max' => 1000,
				'step' => 1,
				'selectors' => [
					$panel_selector => '--close-size: {{VALUE}}px',
				],
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		$panel_selector_close = $panel_selector . ' .rey-offcanvas-close';

		$page->add_control(
			'offcanvas_close_distance',
			[
				'label' => esc_html__( 'Close Distance', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::NUMBER,
				'default' => '',
				'min' => 8,
				'max' => 1000,
				'step' => 1,
				'selectors' => [
					$panel_selector_close => '--distance: {{VALUE}}px',
				],
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		$page->add_control(
			'offcanvas_close_color',
			[
				'label' => esc_html__( 'Color', 'rey-core' ),
				'type' => \Elementor\Controls_Manager::COLOR,
				'selectors' => [
					$panel_selector_close => 'color: {{VALUE}}',
				],
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
			]
		);

		// NOTE

		$page->add_control(
			'offcanvas_custom_trigger',
			[
				'type' => \Elementor\Controls_Manager::RAW_HTML,
				'content_classes' => 'rey-raw-html',
				'raw' => sprintf( _x( 'If you want to use a custom link anywhere in the site, make use of this anchor <strong class="js-copy-content"><u>#offcanvas-%s</u></strong>.', 'Elementor control label', 'rey-core' ), get_the_ID() ),
				'condition' => [
					'gs_type' =>self::GSTYPE,
				],
				'separator' => 'before',
			]
		);
	}

	public function get_offcanvas_panels(){

		if( $this->offcanvas_panels ){
			return $this->offcanvas_panels;
		}

		if( ! class_exists('\ReyCore\Elementor\GlobalSections') ){
			return false;
		}

		return $this->offcanvas_panels = \ReyCore\Elementor\GlobalSections::get_global_sections(self::GSTYPE);
	}

	public function flush_offcanvas_transient_ids( $post_id, $post ){

		if ( ! isset($post->post_type) ) {
			return;
		}

		if( $post->post_type !== \ReyCore\Elementor\GlobalSections::POST_TYPE ){
			return;
		}

		if( self::GSTYPE !== get_field('gs_type', $post_id) ){
			return;
		}

		delete_transient( implode('_', [\ReyCore\Ajax::AJAX_TRANSIENT_NAME, self::AJAX_LAZY_ACTION, $post_id] ) );
	}

	/**
	 * Checks if there are published Off-canvas panel global sections
	 */
	public function is_enabled() {
		return true;
	}

	public static function __config(){
		return [
			'id' => basename(__DIR__),
			'title' => esc_html_x('Offcanvas Panels (Global Sections)', 'Module name', 'rey-core'),
			'description' => esc_html_x('Adds custom Elementor built side panels which can be triggered from everywhere.', 'Module description', 'rey-core'),
			'icon'        => '',
			'categories'  => ['elementor'],
			'keywords'    => [''],
			'help'        => reycore__support_url('kb/off-canvas-global-sections/'),
			'video' => true
		];
	}

	public function module_in_use(){
		return ! empty($this->get_offcanvas_panels());
	}

}
