<?php
/**
 * Astra Site Builder
 *
 * @package Astra Addon
 */

// Return if WP_REST_Controller class does not exist.
if ( ! class_exists( 'WP_REST_Controller' ) ) {
	return;
}

if ( ! class_exists( 'Astra_Addon_Theme_Builder' ) ) {

	/**
	 * Site Builder Pro.
	 *
	 * @since 4.5.0
	 */
	class Astra_Addon_Theme_Builder extends WP_REST_Controller {
		/**
		 * Member Variable
		 *
		 * @var object instance
		 */
		private static $instance;

		/**
		 * Plugin slug
		 *
		 * @since 4.5.0
		 * @var string $plugin_slug
		 */
		public static $plugin_slug = 'astra';

		/**
		 *  Initiator
		 *
		 * @since 4.5.0
		 */
		public static function get_instance() {
			if ( ! isset( self::$instance ) ) {
				self::$instance = new self();
			}
			return self::$instance;
		}

		/**
		 *  Constructor
		 *
		 * @since 4.5.0
		 * @return void
		 */
		public function __construct() {
			if ( method_exists( 'Astra_Menu', 'get_theme_page_slug' ) ) {
				self::$plugin_slug = Astra_Menu::get_theme_page_slug();
			}
			add_action( 'admin_enqueue_scripts', array( $this, 'theme_builder_admin_enqueue_scripts' ) );
			add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
			add_action( 'admin_menu', array( $this, 'setup_menu' ) );
			add_action( 'rest_api_init', array( $this, 'register_routes' ) );
			add_action( 'admin_init', array( $this, 'astra_theme_builder_redirect' ) );
			add_action( 'admin_init', array( $this, 'astra_theme_builder_disable_notices' ) );
		}

		/**
		 *  Enqueue scripts and styles.
		 *
		 * @since 4.5.0
		 * @return void
		 */
		public function theme_builder_admin_enqueue_scripts() {
			$file_prefix = '';
			if ( is_rtl() ) {
				$file_prefix .= '.rtl';
			}

			wp_enqueue_style( 'wp-components' );

			if ( isset( $_GET['page'] ) && $_GET['page'] === 'theme-builder' ) {
				/**
				 * Enqueue advanced-hook-admin-edit styles for the design consistency for Display Condition Modal.
				 */
				if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
					wp_enqueue_style( 'advanced-hook-admin-edit', ASTRA_ADDON_EXT_ADVANCED_HOOKS_URL . 'assets/css/unminified/astra-advanced-hooks-admin-edit.css', null, ASTRA_EXT_VER );
				} else {
					wp_enqueue_style( 'advanced-hook-admin-edit', ASTRA_ADDON_EXT_ADVANCED_HOOKS_URL . 'assets/css/minified/astra-advanced-hooks-admin-edit.min.css', null, ASTRA_EXT_VER );
				}
			}

			wp_enqueue_style( 'astra-theme-builder-style', ASTRA_ADDON_EXT_ADVANCED_HOOKS_URL . 'theme-builder/build/index' . $file_prefix . '.css', array(), ASTRA_EXT_VER );
			wp_enqueue_script( 'astra-theme-builder-script', ASTRA_ADDON_EXT_ADVANCED_HOOKS_URL . 'theme-builder/build/index.js', array( 'react', 'react-dom', 'wp-api-fetch', 'wp-components', 'wp-element', 'wp-i18n' ), ASTRA_EXT_VER, true );
			wp_enqueue_style( 'dashicons' );

			if ( function_exists( 'astra_is_white_labelled' ) ) {
				$white_labelled = astra_is_white_labelled();
			}

			$localized_data = array(
				'title'                      => __( 'Site Builder', 'astra-addon' ),
				'rest_url'                   => get_rest_url( '', '/astra-addon/v1/custom-layouts/' ),
				'new_custom_layout_base_url' => admin_url( 'post-new.php?post_type=astra-advanced-hook' ),
				'astra_pricing_page_url'     => 'https://wpastra.com/pricing/',
				'astra_docs_page_url'        => 'https://wpastra.com/docs/site-builder/',
				'admin_url'                  => admin_url(),
				'spectra_pro_url'            => 'https://wpspectra.com/pricing/',
				'uae_pro_url'                => 'https://ultimateelementor.com/pricing/',
				'show_notice_for'            => $this->show_theme_builder_notice(),
				'table_view_url'             => admin_url( 'edit.php?post_type=astra-advanced-hook&view=table-view' ),
				'nonce'                      => wp_create_nonce( 'wp_rest' ),
				'logo_url'                   => apply_filters( 'astra_admin_menu_icon', '' ),
				'white_labelled'             => isset( $white_labelled ) ? $white_labelled : false,
				'quick_view'                 => array(
					'url'              => admin_url( 'admin-ajax.php' ),
					'quick_view_nonce' => wp_create_nonce( 'astra-addon-quick-layout-view-nonce' ),
					'nonce'            => wp_create_nonce( 'astra-addon-enable-tgl-nonce' ),
				),
			);

			wp_localize_script( 'astra-theme-builder-script', 'astra_theme_builder', $localized_data );
			wp_set_script_translations( 'astra-theme-builder-script', 'astra-addon' );

			if ( ! get_post_type() ) {
				/**
				 * Here, only localize needed "astCustomLayout" compatible values when on Layout List page.
				 */
				wp_localize_script(
					'astra-theme-builder-script',
					'astCustomLayout',
					array(
						'userRoles'           => Astra_Target_Rules_Fields::get_user_selections(),
						'displayRules'        => Astra_Target_Rules_Fields::get_location_selections(),
						'singleDisplayRules'  => Astra_Target_Rules_Fields::get_location_selections( 'single' ),
						'archiveDisplayRules' => Astra_Target_Rules_Fields::get_location_selections( 'archive' ),
						'ajax_nonce'          => wp_create_nonce( 'astra-addon-get-posts-by-query' ),
					)
				);
			}
		}

		/**
		 * Admin Body Classes
		 *
		 * @since 4.5.0
		 * @param string $classes Space separated class string.
		 * @return void
		 */
		public function admin_body_class( $classes = '' ) {
			$theme_builder_class = isset( $_GET['page'] ) && 'theme-builder' === $_GET['page'] ? 'ast-theme-builder' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Fetching a $_GET value, no nonce available to validate.
			$classes            .= ' ' . $theme_builder_class . ' ';

			return $classes;
		}

		/**
		 * Renders the admin settings.
		 *
		 * @since 4.5.0
		 * @return void
		 */
		public function render_theme_builder() {
			?>
				<div class="ast-tb-menu-page-wrapper">
					<div id="ast-tb-menu-page">
						<div class="ast-tb-menu-page-content">
							<div id="ast-tb-app-root" class="ast-tb-app-root"></div>
						</div>
					</div>
				</div>
			<?php
		}

		/**
		 * Setup menu.
		 *
		 * @since 4.5.0
		 * @return void
		 */
		public function setup_menu() {

			$is_astra_addon_active = Astra_Ext_Extension::is_active( 'advanced-hooks' );

			if ( $is_astra_addon_active ) {
				add_submenu_page(
					self::$plugin_slug,
					__( 'Site Builder', 'astra-addon' ),
					__( 'Site Builder', 'astra-addon' ),
					'manage_options',
					'theme-builder',
					array( $this, 'render_theme_builder' ),
					2
				);
			}
		}

		/**
		 * Register API routes.
		 *
		 * @since 4.5.0
		 * @return void
		 */
		public function register_routes() {
			register_rest_route(
				'astra-addon/v1',
				'custom-layouts',
				array(
					array(
						'methods'             => WP_REST_Server::READABLE,
						'callback'            => array( $this, 'get_custom_layouts' ),
						'permission_callback' => array( $this, 'get_permissions_check' ),
						'args'                => array(),
					),
					'schema' => array( $this, 'get_public_item_schema' ),
				)
			);

			register_rest_route(
				'astra-addon/v1',
				'custom-layouts/(?P<id>\d+)',
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_custom_layout' ),
					'permission_callback' => array( $this, 'delete_permissions_check' ),
					'args'                => array(
						'id' => array(
							'validate_callback' => 'rest_validate_request_arg',
							'required'          => true,
							'type'              => 'integer',
						),
					),
				)
			);

			register_rest_route(
				'astra-addon/v1',
				'custom-layouts/(?P<id>\d+)/duplicate',
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'duplicate_custom_layout' ),
					'permission_callback' => array( $this, 'get_permissions_check' ),
					'args'                => array(
						'id' => array(
							'validate_callback' => 'rest_validate_request_arg',
							'required'          => true,
							'type'              => 'integer',
						),
					),
				)
			);
		}

		/**
		 * Get Custom Layouts.
		 *
		 * @since 4.5.0
		 * @param WP_REST_Request $request Full details about the request.
		 * @return array $updated_option defaults + set DB option data.
		 */
		public function get_custom_layouts( $request ) {
			$custom_layouts = new WP_Query(
				array(
					'post_type'      => 'astra-advanced-hook',
					'orderby'        => 'ID',
					'post_status'    => array( 'publish', 'draft', 'private', 'pending', 'future' ),
					'posts_per_page' => -1,
				)
			);

			$results = array();

			foreach ( $custom_layouts->posts as $post ) {

				// Get the author information for each post. get_userdata() returns false for a deleted author.
				$author_id   = $post->post_author;
				$author      = get_userdata( $author_id );
				$author_name = $author instanceof WP_User ? $author->display_name : '';

				// Get the author's avatar URL
				$author_avatar_url = get_avatar_url( $author_id );

				// Generate the edit link manually
				$edit_post_link = admin_url( 'post.php?post=' . $post->ID . '&action=edit' );

				// Get the post preview link
				$post_preview_link = get_preview_post_link( $post );

				// Get the custom field values
				$layout_value  = get_post_meta( $post->ID, 'ast-advanced-hook-layout', true );
				$template_type = get_post_meta( $post->ID, 'ast-advanced-hook-template-type', true );
				$is_enabled    = get_post_meta( $post->ID, 'ast-advanced-hook-enabled', 'yes' );

				// Get the post preview link if type is template.
				$post_preview_link = $this->get_template_preview_link( $post, $post_preview_link, $layout_value, $template_type );

				$layout_data = array(
					'ID'             => $post->ID,
					'post_author'    => $post->post_author,
					'post_title'     => $post->post_title,
					'author_name'    => $author_name,
					'author_image'   => $author_avatar_url,
					'post_modified'  => date( 'Y-m-d', strtotime( $post->post_modified ) ),
					'post_name'      => $post->post_name,
					'post_status'    => $post->post_status,
					'post_link'      => $post_preview_link,
					'edit_post_link' => $edit_post_link,
					'layout_value'   => $layout_value,
					'template_type'  => $template_type,
					'enabled'        => $is_enabled,
				);

				$results[] = $layout_data;
			}

			return $results;
		}

		/**
		 * Check whether a given request has permission access route.
		 *
		 * @since 4.5.0
		 * @param  WP_REST_Request $request Full details about the request.
		 * @return WP_Error|bool
		 */
		public function get_permissions_check( $request ) {
			if ( ! current_user_can( 'edit_theme_options' ) ) {
				return new WP_Error( 'astra_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'astra-addon' ), array( 'status' => rest_authorization_required_code() ) );
			}
			return true;
		}

		/**
		 * Delete custom layout
		 *
		 * @since 4.5.0
		 * @param  WP_REST_Request $request Full details about the request.
		 * @return WP_Error|bool
		 */
		public function delete_custom_layout( $request ) {
			$post_id = $request['id'];
			if ( get_post_status( $post_id ) ) {
				if ( ! current_user_can( 'delete_post', $post_id ) ) {
					wp_die( esc_html__( 'Sorry, you are not allowed to move this item to the Trash.', 'astra-addon' ) );
				}
				wp_trash_post( $post_id );
				return new WP_REST_Response( array( 'message' => 'Post deleted successfully' ), 200 );
			}

			return new WP_Error( 'post_not_found', 'Post not found', array( 'status' => 404 ) );
		}

		/**
		 * Create a duplicate of a layout post with all its metadata
		 *
		 * @since 4.11.13
		 * @param int $post_id The original post ID to duplicate.
		 * @return int|WP_Error The new post ID on success, WP_Error on failure.
		 */
		public function create_layout_duplicate( $post_id ) {
			$original_post = get_post( $post_id );

			if ( ! $original_post ) {
				return new WP_Error( 'post_not_found', 'Post not found' );
			}

			$new_post = array(
				'post_type'    => $original_post->post_type,
				'post_title'   => $original_post->post_title . ' - ' . __( 'Copy', 'astra-addon' ),
				'post_content' => $original_post->post_content,
				'post_status'  => 'draft',
				'post_author'  => get_current_user_id(),
			);

			$new_post_id = wp_insert_post( $new_post );

			if ( is_wp_error( $new_post_id ) ) {
				return new WP_Error( 'post_creation_failed', 'Failed to create duplicate post' );
			}

			$post_meta    = get_post_meta( $post_id );
			$exclude_keys = array(
				'_wp_old_slug',
				'_elementor_css', // Compiled CSS — must be regenerated, not copied.
				'_edit_lock',
				'_edit_last',
			);

			if ( ! empty( $post_meta ) && is_array( $post_meta ) ) {
				foreach ( $post_meta as $key => $values ) {
					if ( in_array( $key, $exclude_keys, true ) ) {
						continue;
					}
					foreach ( $values as $value ) {
						$value = maybe_unserialize( $value );
						add_post_meta( $new_post_id, $key, wp_slash( $value ) );
					}
				}
			}

			return $new_post_id;
		}

		/**
		 * Duplicate custom layout
		 *
		 * @since 4.11.13
		 * @param  WP_REST_Request $request Full details about the request.
		 * @return WP_Error|WP_REST_Response
		 */
		public function duplicate_custom_layout( $request ) {
			$post_id = $request['id'];

			if ( ! get_post_status( $post_id ) ) {
				return new WP_Error( 'post_not_found', 'Post not found', array( 'status' => 404 ) );
			}

			if ( ! current_user_can( 'edit_post', $post_id ) ) {
				return new WP_Error( 'rest_forbidden', __( 'You do not have permission to duplicate this item.', 'astra-addon' ), array( 'status' => 403 ) );
			}

			$new_post_id = $this->create_layout_duplicate( $post_id );

			if ( is_wp_error( $new_post_id ) ) {
				return new WP_Error( 'post_creation_failed', 'Failed to create duplicate post', array( 'status' => 500 ) );
			}

			$layout_data = array(
				'ID'             => $new_post_id,
				'post_author'    => get_current_user_id(),
				'post_title'     => get_post_field( 'post_title', $new_post_id ),
				'author_name'    => wp_get_current_user()->display_name,
				'author_image'   => get_avatar_url( get_current_user_id() ),
				'post_modified'  => date( 'Y-m-d' ),
				'post_name'      => get_post_field( 'post_name', $new_post_id ),
				'post_status'    => 'draft',
				'post_link'      => get_preview_post_link( $new_post_id ),
				'edit_post_link' => admin_url( 'post.php?post=' . $new_post_id . '&action=edit' ),
				'layout_value'   => get_post_meta( $new_post_id, 'ast-advanced-hook-layout', true ),
				'template_type'  => get_post_meta( $new_post_id, 'ast-advanced-hook-template-type', true ),
				'enabled'        => get_post_meta( $new_post_id, 'ast-advanced-hook-enabled', true ),
			);

			return new WP_REST_Response( $layout_data, 201 );
		}

		/**
		 * Check whether a given request has permission to delete route.
		 *
		 * @since 4.5.0
		 * @param  WP_REST_Request $request Full details about the request.
		 * @return WP_Error|bool
		 */
		public function delete_permissions_check( $request ) {
			$post_id = $request['id'];
			if ( current_user_can( 'delete_post', $post_id ) ) {
				return true;
			}

			return new WP_Error(
				'rest_forbidden',
				__( 'You do not have permission to delete this item.', 'astra-addon' ),
				array( 'status' => 403 )
			);
		}

		/**
		 * Determines which notice to show for Site Builder.
		 *
		 * @since 4.5.0
		 * @return string The required plugin name to show install notice for.
		 */
		public function show_theme_builder_notice() {
			$is_uagb_installed      = defined( 'UAGB_VER' );
			$is_spectra_pro         = defined( 'SPECTRA_PRO_VER' );
			$is_elementor_installed = defined( 'ELEMENTOR_VERSION' );
			$is_uael_installed      = defined( 'UAEL_VER' );

			if ( $is_uagb_installed && ! $is_spectra_pro ) {
				return 'spectra';
			}

			if ( $is_elementor_installed && ! $is_uael_installed ) {
				return 'uae_pro';
			}

			return '';
		}

		/**
		 * Redirect conditionally as per current page.
		 * Redirect to Site Builder create new page if user accessing create new custom layout page.
		 *
		 * @since 4.5.0
		 * @return void
		 */
		public function astra_theme_builder_redirect() {
			global $pagenow;
			$custom_layout_page = isset( $_GET['post_type'] ) && $_GET['post_type'] === 'astra-advanced-hook';
			if ( isset( $pagenow ) && 'post-new.php' === $pagenow && $custom_layout_page ) {
				if ( isset( $_GET['type'] ) ) {
					return;
				}
				wp_safe_redirect( admin_url( 'admin.php?page=theme-builder&path=create-new' ) );
				exit;
			}
		}

		/**
		 * Disable notices for Site Builder page.
		 *
		 * @since 4.5.0
		 * @return void
		 */
		public function astra_theme_builder_disable_notices() {

			if ( isset( $_GET['page'] ) && 'theme-builder' === $_GET['page'] ) {
				remove_all_actions( 'admin_notices' );
				remove_all_actions( 'all_admin_notices' );
			}
		}

		/**
		 * Gets the specific preview link for the template.
		 *
		 * @since 4.5.0
		 * @return string Preview link.
		 */
		public function get_template_preview_link( $post, $post_preview_link, $layout_value, $template_type ) {

			if ( 'template' === $layout_value ) {

				/**
				 * Get the display conditions.
				 * Based on the display conditions get the appropriate preview link.
				 * Return the preview link.
				 */

				$display_conditions = get_post_meta( $post->ID, 'ast-advanced-hook-location', true );

				if ( 'single' === $template_type ) {
					if ( isset( $display_conditions['rule'] ) ) {
						$display_rule = $display_conditions['rule'];
						if ( isset( $display_rule ) && isset( $display_rule[0] ) ) {
							$ruleParts = explode( '|', $display_rule[0] );
							if ( isset( $ruleParts ) && $ruleParts[0] ) {
								$pageValue = $ruleParts[0];
								if ( isset( $pageValue ) ) {
									if ( 'basic-global' === $pageValue || 'basic-singulars' === $pageValue ) {
										$pageValue = 'post';
									} elseif ( 'specifics' === $pageValue ) {
										// The 'specific' key is absent when the rule was saved without a target, so it cannot be read unguarded.
										$specific_post = isset( $display_conditions['specific'] ) ? $display_conditions['specific'] : array();
										if ( is_array( $specific_post ) && isset( $specific_post[0] ) ) {
											$specific_post = explode( '-', $specific_post[0] );
											if ( isset( $specific_post[1] ) ) {
												$specific_post_id = (int) $specific_post[1];
												$args             = array(
													'p' => $specific_post_id,
												);
												$specific_post    = get_posts( $args );
												if ( isset( $specific_post ) && isset( $specific_post[0] ) ) {
													$post_preview_link = get_preview_post_link( $specific_post[0]->ID );
												}
											}
										}
									} else {
										$args        = array(
											'posts_per_page' => 1,
											'orderby'   => 'rand',
											'post_type' => $pageValue,
										);
										$random_post = get_posts( $args );
										if ( isset( $random_post ) && isset( $random_post[0] ) ) {
											$post_preview_link = get_preview_post_link( $random_post[0]->ID );
										}
									}
								}
							}
						}
					}
				} elseif ( 'archive' === $template_type ) {
					$display_rule = isset( $display_conditions['rule'] ) ? $display_conditions['rule'] : array();
					if ( isset( $display_rule ) && isset( $display_rule[0] ) ) {
						$display_rule = $display_rule[0];

						if ( 'basic-global' === $display_rule || 'basic-archives' === $display_rule || 'special-blog' === $display_rule ) {

							// URL for the entire site
							$post_preview_link = home_url();
						} elseif ( 'special-404' === $display_rule ) {

							// URL for the 404 Page
							$post_preview_link = home_url( '/hshsh' );
						} elseif ( 'special-search' === $display_rule ) {

							// URL for the Search Page
							$post_preview_link = home_url( '/?s=' );
						} elseif ( 'special-front' === $display_rule ) {

							// URL for the Front Page
							$post_preview_link = home_url();
						} elseif ( 'special-date' === $display_rule ) {

							// URL for the Date Archive
							$year  = date( 'Y' );
							$month = date( 'm' );
							if ( isset( $year ) && isset( $month ) ) {
								$post_preview_link = get_month_link( $year, $month );
							} else {
								$post_preview_link = get_preview_post_link( $post );
							}
						} elseif ( 'special-author' === $display_rule ) {

							// URL for the Author Archive
							$author_id = 1;
							$author    = get_userdata( $author_id );
							if ( $author instanceof WP_User ) {
								$author_slug       = $author->user_nicename;
								$post_preview_link = home_url( '/author/' . $author_slug );
							} else {
								$post_preview_link = get_preview_post_link( $post );
							}
						} elseif ( 'post|all|archive' === $display_rule ) {

							// URL for All Posts Archive
							$post_preview_link = get_post_type_archive_link( 'post' );
						} elseif ( 'post|all|taxarchive|category' === $display_rule ) {

							// URL for All Categories Archive. The array is not guaranteed to be zero-indexed, so read the first term with reset() instead of assuming a [0] key.
							$categories    = get_categories( array( 'number' => 1 ) );
							$category_term = is_array( $categories ) ? reset( $categories ) : false;
							if ( $category_term instanceof WP_Term ) {
								$category_link = get_term_link( $category_term, 'category' );
								if ( ! is_wp_error( $category_link ) ) {
									$post_preview_link = $category_link;
								}
							}
						} elseif ( 'post|all|taxarchive|post_tag' === $display_rule ) {

							// URL for All Tags Archive. Same non-sequential key caveat as categories above.
							$tags     = get_tags( array( 'number' => 1 ) );
							$tag_term = is_array( $tags ) ? reset( $tags ) : false;
							if ( $tag_term instanceof WP_Term ) {
								$tag_link = get_term_link( $tag_term, 'post_tag' );
								if ( ! is_wp_error( $tag_link ) ) {
									$post_preview_link = $tag_link;
								}
							}
						}
					}
				}
			}

			return $post_preview_link;
		}
	}
}

/**
 *  Kicking this off by calling 'get_instance()' method
 */
Astra_Addon_Theme_Builder::get_instance();
