<?php
/**
 * Page settings metabox.
 *
 * @package Neve
 */

namespace Neve\Admin\Metabox;

use Neve\Core\Settings\Config;
use Neve\Core\Settings\Mods;
use Neve\Customizer\Defaults\Layout;
use Neve\Customizer\Defaults\Single_Post;
use Neve\Customizer\Options\Layout_Single_Post;
use Neve\Views\Post_Layout;
use Neve\Core\Supported_Post_Types;

/**
 * Class Manager
 *
 * @package Neve\Admin\Metabox
 */
final class Manager {
	use Single_Post;
	use Layout;

	/**
	 * Control instances.
	 *
	 * @var array
	 */
	private $controls = array();

	/**
	 * Control classes to get controls from.
	 *
	 * @var array
	 */
	private $control_classes;

	/**
	 * Init function
	 */
	public function init() {
		add_action( 'add_meta_boxes', array( $this, 'add' ) );
		add_action( 'admin_init', array( $this, 'define_controls' ) );
		add_action( 'admin_init', array( $this, 'load_controls' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) );
		add_action( 'save_post', array( $this, 'save' ) );

		/**
		 * Gtb meta
		 */
		add_action( 'init', array( $this, 'neve_register_meta' ) );
		add_action( 'enqueue_block_editor_assets', array( $this, 'meta_sidebar_script_enqueue' ) );
	}

	/**
	 * Define the controls.
	 */
	public function define_controls() {
		$this->control_classes = array(
			'Neve\\Admin\\Metabox\\Main',
		);

		$this->control_classes = apply_filters( 'neve_filter_metabox_controls', $this->control_classes );
	}

	/**
	 * Instantiate the controls and actually load them into the control manager.
	 */
	public function load_controls() {
		if ( empty( $this->control_classes ) ) {
			return;
		}
		foreach ( $this->control_classes as $control_manager ) {
			$control_instance = new $control_manager();
			if ( ! $control_instance instanceof Controls_Base ) {
				continue;
			}

			$control_instance->init();

			$this->controls = array_merge( $this->controls, $control_instance->get_controls() );
		}
		$this->order_by_priority();
	}

	/**
	 * The metabox content.
	 */
	public function render_controls() {
		global $post;

		foreach ( $this->controls as $control ) {
			if ( method_exists( $control, 'render' ) ) {
				$control->render( $post->ID );
			}
		}
	}

	/**
	 * Save metabox content.
	 *
	 * @param int $post_id the post id.
	 */
	public function save( $post_id ) {
		foreach ( $this->controls as $control ) {
			if ( method_exists( $control, 'save' ) ) {
				$control->save( $post_id );
			}
		}
	}

	/**
	 * Register meta box to control layout on pages and posts.
	 */
	public function add() {
		$post_type_label   = 'Neve';
		$post_type_from_db = get_post_type();
		$post_type_object  = get_post_type_object( $post_type_from_db );
		
		if ( $post_type_object && isset( $post_type_object->labels->name ) ) {
			$post_type_label = $post_type_object->labels->name;
		}

		add_meta_box(
			'neve-page-settings',
			sprintf(
			/* translators: %s - post type */
				__( '%s Settings', 'neve' ),
				$post_type_label
			),
			array( $this, 'render_metabox' ),
			array( 'post', 'page', 'product' ),
			'side',
			'default',
			array(
				'__back_compat_meta_box' => true,
			)
		);

		if ( $this->is_gutenberg_active() ) {
			add_meta_box(
				'neve-page-settings-notice',
				sprintf(
				/* translators: %s - post type */
					__( '%s Settings', 'neve' ),
					$post_type_label
				),
				array( $this, 'render_metabox_notice' ),
				Supported_Post_Types::get( 'block_editor' ),
				'side',
				'default',
				array(
					'__back_compat_meta_box' => false,
				)
			);
		}
	}

	/**
	 * Detect if is gutenberg editor.
	 *
	 * @return bool
	 */
	private function is_gutenberg_active() {
		global $current_screen;
		if ( method_exists( $current_screen, 'is_block_editor' ) ) {
			return $current_screen->is_block_editor();
		}
		return false;
	}

	/**
	 * The metabox content.
	 */
	public function render_metabox() {
		$this->render_controls();
	}

	/**
	 * Render the metabox notice.
	 */
	public function render_metabox_notice() {
		echo '<div class="nv-meta-notice-wrapper">';
		echo '<h4>' . esc_html__( 'Page Settings are now accessible from the top bar', 'neve' ) . '</h4>';

		printf(
		/* translators: %1$s - Keyboard shortcut.   %2&s - svg icon */
			esc_html__( 'Click the %1$s icon in the top bar or use the keyboard shortcut ( %2$s ) to customise the layout settings for this page', 'neve' ),
			apply_filters( 'ti_wl_theme_is_localized', false ) ?
				neve_kses_svg( $this->get_metabox_icon() ) : //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				'<svg class="neve-logo" width="17" height="24" viewBox="0 0 17 24" fill="none" xmlns="http://www.w3.org/2000/svg">
				<path d="M4.77822 10.2133V19.3287H0.118347V0.802224C0.118347 0.712594 0.145598 0.649854 0.200099 0.614002C0.254601 0.578149 0.354519 0.622964 0.499857 0.748446L12.1359 10.2133V1.04422H16.7958V19.5976C16.7958 19.7051 16.7685 19.7724 16.714 19.7992C16.6595 19.8261 16.5596 19.7768 16.4143 19.6514L4.77822 10.2133Z"/>
				<rect x="0.118347" y="22.3334" width="16.6774" height="1.51613"/>
				</svg>',
			'<strong>SHIFT + ALT + S</strong> ' . esc_html__( 'or', 'neve' ) . ' <strong>control + option + S</strong>'
		);
		echo '</div>';
	}

	/**
	 * Get the metabox layout.
	 * 
	 * @return string
	 */
	private function get_metabox_icon() {
		return apply_filters( 'neve_metabox_wl_icon_markup', '<span class="dashicons dashicons-hammer"></span>' );
	}

	/**
	 * Enqueue scripts and styles.
	 */
	public function enqueue() {

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

		$screen = get_current_screen();

		if ( ! is_object( $screen ) ) {
			return;
		}

		if ( $screen->base !== 'post' ) {
			return;
		}

		wp_register_script( 'neve-metabox', NEVE_ASSETS_URL . 'js/build/all/metabox.js', array( 'jquery' ), NEVE_VERSION, true );

		wp_localize_script( 'neve-metabox', 'neveMetabox', $this->get_localization() );

		wp_enqueue_script( 'neve-metabox' );
	}

	/**
	 * Localize the Metabox script.
	 *
	 * @return array
	 */
	private function get_localization() {
		return array();
	}

	/**
	 * Order the controls by given priority.
	 */
	private function order_by_priority() {
		$order = array();

		foreach ( $this->controls as $key => $control_object ) {
			$order[ $key ] = $control_object->priority;
		}
		array_multisort( $order, SORT_ASC, $this->controls );
	}

	/**
	 * Register meta
	 */
	public function neve_register_meta() {
		$meta_sidebar_controls = apply_filters(
			'neve_sidebar_meta_controls',
			[
				[
					'id'   => 'neve_meta_sidebar',
					'type' => 'radio',
				],
				[
					'id'   => 'neve_meta_container',
					'type' => 'button-group',
				],
				[
					'id'   => 'neve_meta_enable_content_width',
					'type' => 'checkbox',
				],
				[
					'id'   => 'neve_meta_content_width',
					'type' => 'range',
				],
				[
					'id'   => 'neve_meta_title_alignment',
					'type' => 'button-group',
				],
				[
					'id'   => 'neve_meta_author_avatar',
					'type' => 'checkbox',
				],
				[
					'id'   => 'neve_post_elements_order',
					'type' => 'sortable-list',
				],
				[
					'id'   => 'neve_meta_disable_header',
					'type' => 'checkbox',
				],
				[
					'id'   => 'neve_meta_disable_footer',
					'type' => 'checkbox',
				],
				[
					'id'   => 'neve_meta_disable_title',
					'type' => 'checkbox',
				],
			]
		);
		foreach ( $meta_sidebar_controls as $control ) {
			$type = 'string';
			if ( $control['type'] === 'range' ) {
				$type = 'integer';
			}

			$post_type = '';
			if ( array_key_exists( 'post_type', $control ) ) {
				$post_type = $control['post_type'];
			}

			$meta_settings = array(
				'show_in_rest'      => true,
				'type'              => $type,
				'single'            => true,
				'sanitize_callback' => 'sanitize_text_field',
				'auth_callback'     => function () {
					return current_user_can( 'edit_posts' );
				},
			);

			register_post_meta(
				$post_type,
				$control['id'],
				$meta_settings
			);
		}
	}

	/**
	 * Register the metabox sidebar.
	 */
	public function meta_sidebar_script_enqueue() {
		global $post_type, $pagenow;

		$do_not_load_on = [ 'widgets.php', 'customize.php' ];

		// $post_type returns "page" on widgets.php and on customize.php so we need to check this separately.
		if ( in_array( $pagenow, $do_not_load_on, true ) || ! in_array( $post_type, Supported_Post_Types::get( 'block_editor' ) ) ) {
			return false;
		}

		$dependencies = ( include get_template_directory() . '/assets/apps/metabox/build/index.asset.php' );

		wp_enqueue_script(
			'neve-meta-sidebar',
			trailingslashit( get_template_directory_uri() ) . 'assets/apps/metabox/build/index.js',
			$dependencies['dependencies'],
			$dependencies['version'],
			true
		);

		if ( function_exists( 'wp_set_script_translations' ) ) {
			wp_set_script_translations( 'neve-meta-sidebar', 'neve' );
		}

		$container    = $post_type === 'post' ? Mods::get( Config::MODS_SINGLE_POST_CONTAINER_STYLE, 'contained' ) : Mods::get( Config::MODS_DEFAULT_CONTAINER_STYLE, 'contained' );
		$editor_width = Mods::get( Config::MODS_CONTAINER_WIDTH );

		$advanced_layout = Mods::get( Config::MODS_ADVANCED_LAYOUT_OPTIONS, true );

		$single_width  = $post_type === 'post' ?
			Mods::get( Config::MODS_SINGLE_CONTENT_WIDTH, $this->sidebar_layout_width_default( Config::MODS_SINGLE_CONTENT_WIDTH ) ) :
			Mods::get( Config::MODS_OTHERS_CONTENT_WIDTH, $this->sidebar_layout_width_default( Config::MODS_OTHERS_CONTENT_WIDTH ) );
		$content_width = $advanced_layout ?
			$single_width :
			Mods::get( Config::MODS_SITEWIDE_CONTENT_WIDTH, $this->sidebar_layout_width_default( Config::MODS_SITEWIDE_CONTENT_WIDTH ) );

		$editor_width = isset( $editor_width['desktop'] ) ? (int) $editor_width['desktop'] : 1170;

		$post_elements_default_order = $this->get_post_elements_default_order();
		$show_avatar                 = $this->get_author_avatar_state();
		$reading_time                = $this->get_reading_time_state();

		$post_type_details = get_post_type_object( $post_type );
		$post_type_label   = esc_html( $post_type_details->labels->singular_name );

		$localized_data = apply_filters(
			'neve_meta_sidebar_localize_filter',
			array(
				'actions'                 => array(
					'neve_meta_content_width' => array(
						'container' => $container,
						'editor'    => $editor_width,
						'content'   => $content_width,
					),
				),
				'elementsDefaultOrder'    => $post_elements_default_order,
				'avatarDefaultState'      => $show_avatar,
				'readingTimeDefaultState' => $reading_time,
				'postTypeLabel'           => $post_type_label,
				'isCoverLayout'           => Layout_Single_Post::is_cover_layout(),
				'icon'                    => $this->get_metabox_icon(),
			)
		);
		wp_localize_script(
			'neve-meta-sidebar',
			'metaSidebar',
			$localized_data
		);

		wp_enqueue_style(
			'neve-meta-sidebar-css', // Handle.
			trailingslashit( get_template_directory_uri() ) . 'assets/apps/metabox/build/index.css',
			array( 'wp-edit-blocks' ),
			NEVE_VERSION
		);
	}

	/**
	 * Get the value of elements order from customizer.
	 *
	 * @return string
	 */
	private function get_post_elements_default_order() {
		$default_order = $this->get_v4_defaults( 'neve_layout_single_post_elements_order', $this->post_ordering() );

		$content_order = get_theme_mod( 'neve_layout_single_post_elements_order', wp_json_encode( $default_order ) );
		if ( ! is_string( $content_order ) ) {
			$content_order = wp_json_encode( $default_order );
		}
		$content_order = json_decode( $content_order, true );
		if ( empty( $content_order ) ) {
			return wp_json_encode( $content_order );
		}

		$is_cover_layout  = Layout_Single_Post::is_cover_layout();
		$title_meta_index = array_search( 'title-meta', $content_order );
		if ( $title_meta_index !== false && ! $is_cover_layout ) {
			$content_order[ $title_meta_index ] = 'title';
			$next_index                         = $title_meta_index + 1;
			$content_order                      = array_merge( array_slice( $content_order, 0, $next_index, true ), array( 'meta' ), array_slice( $content_order, $next_index, null, true ) );
		}

		return wp_json_encode( $content_order );
	}

	/**
	 * Get the value of author avatar display from customizer.
	 *
	 * @return bool
	 */
	private function get_author_avatar_state() {
		$show_avatar = get_theme_mod( 'neve_author_avatar', false );
		return get_theme_mod( 'neve_single_post_author_avatar', $show_avatar );
	}

	/**
	 * Get the value of Reading Time visibility from customizer.
	 *
	 * @return bool
	 */
	private function get_reading_time_state() {
		$meta_fields = get_theme_mod( 'neve_single_post_meta_fields', self::get_default_single_post_meta_fields() );

		if ( is_string( $meta_fields ) ) {
			$meta_fields = json_decode( $meta_fields, true );
		}

		if ( ! is_array( $meta_fields ) ) {
			return false;
		}

		foreach ( $meta_fields as $args ) {
			if ( ! array_key_exists( 'slug', $args ) || ! array_key_exists( 'visibility', $args ) || $args['slug'] !== 'reading' ) {
				continue;
			}

			return $args['visibility'] === 'yes';
		}

		return false;
	}
}
