<?php

if ( ! class_exists( 'Presscore_Modules_Posts_Defaults', false ) ) {

	class Presscore_Modules_Posts_Defaults {

		public static function execute() {
			// Bail for not admin screens.
			if ( ! is_admin() ) {
				return;
			}

			include_once dirname( __FILE__ ) . '/class-the7-post-meta-preset.php';
			include_once dirname( __FILE__ ) . '/interface-the7-post-meta-data-provider.php';
			include_once dirname( __FILE__ ) . '/class-the7-post-meta-wp-provider.php';
			include_once dirname( __FILE__ ) . '/class-the7-post-meta-wp-sanitizer.php';
			include_once dirname( __FILE__ ) . '/class-the7-post-meta-defaults.php';

			// Add meta boxes.
			add_action( 'load-post.php', array( __CLASS__, 'add_meta_box_actions' ) );

			// Handle ajax.
			add_action( 'wp_ajax_the7_meta_preset', array( __CLASS__, 'handle_meta_presets_ajax_action' ) );

			// Handle bulk actions.
			add_action( 'bulk_edit_custom_box', array( __CLASS__, 'bulk_actions' ), 10, 2 );
			add_action( 'quick_edit_custom_box', array( __CLASS__, 'bulk_actions' ), 10, 2 );
			add_action( 'save_post', array( __CLASS__, 'handle_bulk_action' ), 10, 2 );

			// Replace box defaults.
			add_action( 'the7_before_meta_box_registration', array( __CLASS__, 'replace_box_defaults' ) );

			add_action( 'admin_print_styles-post.php', array( __CLASS__, 'localize_js_data' ), 5 );
		}

		public static function localize_js_data() {
			$strings = array(
				'enterName'      => __( 'Enter preset name', 'the7mk2' ),
				'presetSaved'    => __( 'Preset saved', 'the7mk2' ),
				'defaultsSaved'  => __( 'Defaults saved', 'the7mk2' ),
				'applyingPreset' => __( 'Applying preset ...', 'the7mk2' ),
			);
			wp_localize_script( 'the7-meta-box-magic', 'the7MetaPresetsStrings', $strings );

			$post_id = self::get_current_admin_post_id();
			$nonces = array();
			if ( self::current_user_can_use_meta_presets() ) {
				foreach ( self::get_meta_preset_actions() as $preset_action ) {
					$nonces[ $preset_action ] = wp_create_nonce( self::get_meta_preset_nonce_action( $preset_action, $post_id ) );
				}
			}

			wp_localize_script( 'the7-meta-box-magic', 'the7MetaPresetsNonces', $nonces );
		}

		public static function handle_meta_presets_ajax_action() {
			$request = self::prepare_meta_preset_ajax_request( $_POST );
			if ( is_wp_error( $request ) ) {
				self::send_meta_preset_ajax_error( $request );
			}

			$action = $request['action'];
			$post_id = $request['post_id'];
			if ( ! check_ajax_referer( self::get_meta_preset_nonce_action( $action, $post_id ), false, false ) ) {
				wp_send_json_error( array( 'msg' => __( 'Seems that you use expired or incorrect nonce. Please reload the page and try again.', 'the7mk2' ) ) );
			}

			if ( ! self::current_user_can_handle_meta_preset_action( $action, $post_id ) ) {
				wp_send_json_error( array( 'msg' => __( 'Insufficient permissions.', 'the7mk2' ) ) );
			}

			$id = $request['id'];
			$title = $request['title'];
			$meta = $request['meta'];
			$response = array();

			try {
				switch ( $action ) {
					case 'add_preset':
						$new_presets_names = self::add_preset( $post_id, $title, $meta );
						$response = array( 'presetsNames' => $new_presets_names );
						break;
					case 'save_preset':
						self::save_preset( $post_id, $id, $meta );
						break;
					case 'apply_preset':
						self::apply_preset( $post_id, $id );
						break;
					case 'delete_preset':
						$new_presets_names = self::delete_preset( $post_id, $id );
						$response = array( 'presetsNames' => $new_presets_names );
						break;
					case 'save_defaults':
						self::save_defaults( $post_id, $meta );
						break;
					default:
						wp_send_json_error( array( 'msg' => __( 'Invalid action:', 'the7mk2' ) . ' ' . $action ) );
				}
			} catch ( Exception $e ) {
				wp_send_json_error( array( 'msg' => $e->getMessage() ) );
			}

			wp_send_json_success( $response );
		}

		public static function get_meta_preset_actions() {
			return array(
				'add_preset',
				'save_preset',
				'apply_preset',
				'delete_preset',
				'save_defaults',
			);
		}

		public static function get_meta_preset_nonce_action( $action, $post_id ) {
			return 'the7-meta-preset-' . sanitize_key( $action ) . '-' . absint( $post_id );
		}

		public static function verify_meta_preset_nonce( $action, $post_id, $nonce ) {
			return (bool) wp_verify_nonce( $nonce, self::get_meta_preset_nonce_action( $action, $post_id ) );
		}

		public static function prepare_meta_preset_ajax_request( $data ) {
			$action = isset( $data['preset_action'] ) ? sanitize_key( wp_unslash( $data['preset_action'] ) ) : '';
			if ( ! in_array( $action, self::get_meta_preset_actions(), true ) ) {
				return new WP_Error( 'invalid_action', __( 'Invalid action.', 'the7mk2' ) );
			}

			$post_id = isset( $data['postID'] ) ? absint( wp_unslash( $data['postID'] ) ) : 0;
			if ( ! self::is_supported_post_for_meta_presets( $post_id ) ) {
				return new WP_Error( 'invalid_post', __( 'Invalid post.', 'the7mk2' ) );
			}

			$id = null;
			if ( isset( $data['id'] ) ) {
				$id_raw = (string) wp_unslash( $data['id'] );
				if ( ctype_digit( $id_raw ) ) {
					$id = (int) $id_raw;
				}
			}

			if ( in_array( $action, array( 'save_preset', 'apply_preset', 'delete_preset' ), true ) && null === $id ) {
				return new WP_Error( 'invalid_preset', __( 'Invalid preset.', 'the7mk2' ) );
			}

			return array(
				'action'  => $action,
				'post_id' => $post_id,
				'id'      => $id,
				'title'   => isset( $data['title'] ) ? wp_unslash( $data['title'] ) : '',
				'meta'    => ( isset( $data['meta'] ) && is_array( $data['meta'] ) ) ? wp_unslash( $data['meta'] ) : array(),
			);
		}

		public static function current_user_can_handle_meta_preset_action( $action, $post_id ) {
			if ( ! in_array( $action, self::get_meta_preset_actions(), true ) ) {
				return false;
			}

			return self::current_user_can_use_meta_presets( $post_id );
		}

		public static function current_user_can_use_meta_presets( $post_id = 0 ) {
			return current_user_can( 'edit_theme_options' ) && ( ! $post_id || current_user_can( 'edit_post', $post_id ) );
		}

		public static function is_supported_post_for_meta_presets( $post_id ) {
			$post = get_post( $post_id );
			if ( ! $post ) {
				return false;
			}

			return post_type_exists( $post->post_type ) && in_array( $post->post_type, presscore_get_pages_with_basic_meta_boxes(), true );
		}

		public static function meta_preset_exists( $post_type, $id ) {
			if ( null === $id ) {
				return false;
			}

			$wp_provider = self::new_post_meta_wp_provider( $post_type );
			$presets_names = $wp_provider->get_presets_names();

			return is_array( $presets_names ) && array_key_exists( $id, $presets_names );
		}

		protected static function get_current_admin_post_id() {
			if ( isset( $_GET['post'] ) ) {
				return absint( wp_unslash( $_GET['post'] ) );
			}

			if ( isset( $_POST['post_ID'] ) ) {
				return absint( wp_unslash( $_POST['post_ID'] ) );
			}

			global $post;
			if ( $post instanceof WP_Post ) {
				return absint( $post->ID );
			}

			return 0;
		}

		protected static function send_meta_preset_ajax_error( WP_Error $error ) {
			wp_send_json_error( array( 'msg' => $error->get_error_message() ) );
		}

		public static function add_preset( $post_id, $title, $meta ) {
			$meta = wp_list_pluck( $meta, 'value', 'name' );
			$post_type = get_post_type( $post_id );
			$wp_provider = self::new_post_meta_wp_provider( $post_type );
			$preset = new The7_Post_Meta_Preset( $wp_provider );
			$preset->set_meta( The7_Post_Meta_WP_Sanitizer::sanitize_meta( $meta, $post_id ) );
			$preset->set_title( The7_Post_Meta_WP_Sanitizer::sanitize_title( $title ) );
			$preset->save();

			return self::prepare_presets_names_for_output( $wp_provider->get_presets_names() );
		}

		public static function save_preset( $post_id, $id, $meta ) {
			$meta = wp_list_pluck( $meta, 'value', 'name' );
			$post_type = get_post_type( $post_id );
			if ( ! self::meta_preset_exists( $post_type, $id ) ) {
				throw new Exception( __( 'Invalid preset.', 'the7mk2' ) );
			}

			$wp_provider = self::new_post_meta_wp_provider( $post_type );
			$preset = new The7_Post_Meta_Preset( $wp_provider, $id );
			$preset->set_meta( The7_Post_Meta_WP_Sanitizer::sanitize_meta( $meta, $post_id ) );
			$preset->delete();
			$preset->save();
		}

		public static function apply_preset( $post_id, $id ) {
			$post_type = get_post_type( $post_id );
			if ( ! self::meta_preset_exists( $post_type, $id ) ) {
				throw new Exception( __( 'Invalid preset.', 'the7mk2' ) );
			}

			$wp_provider = self::new_post_meta_wp_provider( $post_type );
			$preset = new The7_Post_Meta_Preset( $wp_provider, $id );
			$preset->set_meta( The7_Post_Meta_WP_Sanitizer::sanitize_meta( $preset->get_meta(), $post_id ) );
			$preset->apply_to_post( $post_id );
		}

		public static function delete_preset( $post_id, $id ) {
			$post_type = get_post_type( $post_id );
			if ( ! self::meta_preset_exists( $post_type, $id ) ) {
				throw new Exception( __( 'Invalid preset.', 'the7mk2' ) );
			}

			$wp_provider = self::new_post_meta_wp_provider( $post_type );
			$preset = new The7_Post_Meta_Preset( $wp_provider, $id );
			$preset->delete();

			return self::prepare_presets_names_for_output( $wp_provider->get_presets_names() );
		}

		public static function save_defaults( $post_id, $meta ) {
			$meta = wp_list_pluck( $meta, 'value', 'name' );
			$post_type = get_post_type( $post_id );
			$defaults = new The7_Post_Meta_Defaults( $post_type );
			$defaults->set( The7_Post_Meta_WP_Sanitizer::sanitize_meta( $meta, $post_id ) );
        }

		public static function new_post_meta_wp_provider( $post_type ) {
			$post_type = sanitize_key( $post_type );

			return new The7_Post_Meta_WP_Provider(
				"the7_{$post_type}_presets",
				"the7_{$post_type}_presets_names"
			);
		}

		public static function prepare_presets_names_for_output( $names ) {
			$escaped_names = array();
			foreach ( $names as $id => $name ) {
				$escaped_names[] = array( 'id' => $id, 'name' => $name );
			}

			if ( empty( $escaped_names ) ) {
				$escaped_names[] = array( 'id' => '', 'name' => _x( '-- No presets --', 'admin', 'the7mk2' ) );
			}

			return array_reverse( $escaped_names );
		}

		/**
		 * Add meta box actions.
		 */
		public static function add_meta_box_actions() {
			add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_box' ) );
        }

		/**
		 * Add the meta box.
		 */
		public static function add_meta_box() {
			if ( ! self::current_user_can_use_meta_presets() ) {
				return;
			}

			add_meta_box( 'the7-post-meta-presets-box', __( 'Settings Presets', 'the7mk2' ), array(
				__CLASS__,
				'render_meta_box',
			), presscore_get_pages_with_basic_meta_boxes(), 'side', 'default' );
		}

		/**
		 * Render the meta box.
		 */
		public static function render_meta_box( $post ) {
			if ( ! self::current_user_can_use_meta_presets( $post->ID ) ) {
				return;
			}

			?>

            <p>
                <select id="the7-post-meta-presets" name="_the7_post_meta_presets">
					<?php
					$presets_provider = self::new_post_meta_wp_provider( $post->post_type );
					$presets_names = self::prepare_presets_names_for_output( $presets_provider->get_presets_names() );

					foreach ( $presets_names as $preset_name ) {
						printf( '<option value="%1$s">%2$s</option>', esc_attr( $preset_name['id'] ), esc_html( $preset_name['name'] ) );
					}
					?>
	                </select>
            </p>
			<?php
			$preset_action_status = '';
			if ( $presets_names[0]['id'] === '' ) {
				$preset_action_status = 'disabled="disabled"';
			}
			?>
            <p id="the7-post-meta-presets-actions">
                <button type="button" id="the7-post-meta-add-preset" class="button button-secondary"><?php esc_html_e( 'Create new', 'the7mk2' ) ?></button>
                <button type="button" id="the7-post-meta-save-preset" class="button button-primary" <?php echo $preset_action_status ?>><?php esc_html_e( 'Save', 'the7mk2' ) ?></button>
                <button type="button" id="the7-post-meta-delete-preset" class="button button-secondary" <?php echo $preset_action_status ?>><?php esc_html_e( 'Delete', 'the7mk2' ) ?></button>
            </p>
            <div class="the7-mb-field the7-mb-heading-wrapper"><div class="dt_hr dt_hr-top"></div><h4><?php esc_html_e( 'Preset Actions', 'the7mk2' ) ?></h4></div>
            <p>
                <button type="button" id="the7-post-meta-save-defaults" class="button button-secondary"><?php esc_html_e( 'Save as default', 'the7mk2' ) ?></button>
                <button type="button" id="the7-post-meta-apply-preset" class="button button-primary" <?php echo $preset_action_status ?>><?php esc_html_e( 'Apply to page', 'the7mk2' ) ?></button>
            </p>

			<?php
		}

		public static function bulk_actions( $column, $type ) {
			if ( ! self::current_user_can_use_meta_presets() ) {
				return;
			}

			$post_types = presscore_get_pages_with_basic_meta_boxes();

			// Display for one custom column.
			if ( 'presscore-sidebar' !== $column || ! in_array( $type, $post_types ) ) {
				return;
			}
			?>
			<div class="presscore-bulk-actions">
				<fieldset class="inline-edit-col-left dt-inline-edit-sidebars">
					<legend class="inline-edit-legend"><?php _ex( 'Apply setting preset', 'backend bulk edit', 'the7mk2' ) ?></legend>
                    <p><small><?php echo esc_html_x( 'To apply setting preset just select one from the list below and press Update button.', 'backend bulk edit', 'the7mk2' ) ?></small></p>
					<div class="inline-edit-col">
						<div class="inline-edit-group">
							<label class="alignleft">
								<span class="title"><?php _ex( 'Setting preset', 'backend bulk edit', 'the7mk2' ) ?></span>
								<select name="_dt_bulk_apply_post_meta_preset">
                                    <option value="-1"><?php _ex( '&mdash; No Change &mdash;', 'backend bulk edit', 'the7mk2' ) ?></option>
									<?php
									$presets_provider = self::new_post_meta_wp_provider( $type );
									$presets_names = self::prepare_presets_names_for_output( $presets_provider->get_presets_names() );

									foreach ( $presets_names as $preset_name ) {
										// Exclude empty array filler. We have a default value above.
										if ( '' === $preset_name['id'] ) {
											continue;
										}

										printf( '<option value="%1$s">%2$s</option>', esc_attr( $preset_name['id'] ), esc_html( $preset_name['name'] ) );
									}
									?>
									</select>
							</label>
						</div>
					</div>
				</fieldset>
			</div>
			<?php
		}

		public static function handle_bulk_action( $post_id, $post ) {
			if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
				return;
			}

			if ( ! self::check_bulk_action() && ! self::check_quick_editor_action() ) {
			    return;
            }

			// Check permissions.
			if ( ! self::current_user_can_use_meta_presets( $post_id ) ) {
				return;
			}

			// update sidebar
			if ( isset( $_REQUEST['_dt_bulk_apply_post_meta_preset'] ) ) {
				$preset_id = wp_unslash( $_REQUEST['_dt_bulk_apply_post_meta_preset'] );
				if ( '-1' === (string) $preset_id || ! ctype_digit( (string) $preset_id ) ) {
					return;
				}

				try {
					self::apply_preset( $post_id, absint( $preset_id ) );
				} catch ( Exception $e ) {
					return;
				}
			}
		}

		protected static function check_quick_editor_action() {
			// Verify this came from the our screen and with proper authorization,
			// because save_post can be triggered at other times.
			if ( ! check_ajax_referer( 'inlineeditnonce', '_inline_edit', false ) ) {
				return false;
			}

			return true;
        }

		protected static function check_bulk_action() {
			// Verify this came from the our screen and with proper authorization,
			// because save_post can be triggered at other times.
			if ( ! check_ajax_referer( 'bulk-posts', false, false ) ) {
				return false;
			}

			if ( ! isset( $_REQUEST['bulk_edit'] ) ) {
				return false;
			}

			return true;
        }

		public static function replace_box_defaults() {
			if ( defined( 'DOING_AJAX' ) ) {
				return;
			}

			global $DT_META_BOXES;

			if ( isset( $_GET['post'] ) ) {
				$post_id = (int) $_GET['post'];
			} elseif ( isset( $_POST['post_ID'] ) ) {
				$post_id = (int) $_POST['post_ID'];
			} else {
				$post_id = 0;
			}

			if ( $post_id ) {
				$post_type = get_post_type( $post_id );
			} elseif ( isset( $_GET['post_type'] ) ) {
				$post_type = $_GET['post_type'];
			} else {
				$post_type = 'post';
			}

			if ( ! post_type_exists( $post_type ) ) {
				return;
			}

			$defaults = new The7_Post_Meta_Defaults( $post_type );
			$post_meta_defaults = $defaults->get();
			if ( empty( $post_meta_defaults ) ) {
				return;
			}

			foreach ( $DT_META_BOXES as $meta_id => $meta_box ) {
				foreach ( $DT_META_BOXES[ $meta_id ]['fields'] as $key => &$field ) {
					$field_id = $field['id'];

					if ( array_key_exists( $field_id, $post_meta_defaults ) ) {
						$field['std'] = $post_meta_defaults[ $field_id ];
					}
				}
			}
        }
	}

	Presscore_Modules_Posts_Defaults::execute();
}
