<?php

namespace WPForms\Admin;

use WPForms\Admin\Builder\PreviewDropdownEducationItems;
use WPForms_Builder;
use WP_Post;

/**
 * Embed Form in a Page wizard.
 *
 * @since 1.6.2
 */
class FormEmbedWizard {

	/**
	 * Max search results count of 'Select Page' dropdown.
	 *
	 * @since 1.7.9
	 *
	 * @var int
	 */
	const MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT = 20;

	/**
	 * Post statuses of pages in 'Select Page' dropdown.
	 *
	 * @since 1.7.9
	 *
	 * @var string[]
	 */
	const POST_STATUSES_OF_DROPDOWN_PAGES = [ 'publish', 'pending' ];

	/**
	 * Initialize class.
	 *
	 * @since 1.6.2
	 */
	public function init() {

		// Form Embed Wizard should load only in the Form Builder and on the Edit/Add Page screen.
		if (
			! wpforms_is_admin_page( 'builder' ) &&
			! wpforms_is_admin_ajax() &&
			! $this->is_form_embed_page()
		) {
			return;
		}

		$this->hooks();
	}

	/**
	 * Register hooks.
	 *
	 * @since 1.6.2
	 * @since 1.7.9 Add hook for searching pages in embed wizard via AJAX.
	 */
	public function hooks() {

		add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
		add_action( 'admin_footer', [ $this, 'output' ] );
		add_filter( 'default_title', [ $this, 'embed_page_title' ], 10, 2 );
		add_filter( 'default_content', [ $this, 'embed_page_content' ], 10, 2 );
		add_action( 'wp_ajax_wpforms_admin_form_embed_wizard_embed_page_url', [ $this, 'get_embed_page_url_ajax' ] );
		add_action( 'wp_ajax_wpforms_admin_form_embed_wizard_search_pages_choicesjs', [ $this, 'get_search_result_pages_ajax' ] );
	}

	/**
	 * Enqueue assets.
	 *
	 * @since 1.6.2
	 * @since 1.7.9 Add 'underscore' as dependency.
	 */
	public function enqueues() {

		$min = wpforms_get_min_suffix();

		if ( $this->is_form_embed_page() && $this->get_meta() && ! $this->is_challenge_active() ) {

			wp_enqueue_style(
				'wpforms-admin-form-embed-wizard',
				WPFORMS_PLUGIN_URL . "assets/css/form-embed-wizard{$min}.css",
				[],
				WPFORMS_VERSION
			);

			wp_enqueue_style(
				'tooltipster',
				WPFORMS_PLUGIN_URL . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.css',
				null,
				'4.2.6'
			);

			wp_enqueue_script(
				'tooltipster',
				WPFORMS_PLUGIN_URL . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.js',
				[ 'jquery' ],
				'4.2.6',
				true
			);
		}

		// In the Form Builder the education cards delegate their "open preview"
		// and "jump to settings section" actions to the Preview dropdown module,
		// so we declare it as an explicit dependency there.
		$deps = [ 'jquery', 'underscore' ];

		if ( wpforms_is_admin_page( 'builder' ) ) {
			$deps[] = 'wpforms-builder-preview-dropdown';
		}

		wp_enqueue_script(
			'wpforms-admin-form-embed-wizard',
			WPFORMS_PLUGIN_URL . "assets/js/admin/form-embed-wizard{$min}.js",
			$deps,
			WPFORMS_VERSION,
			false
		);

		wp_localize_script(
			'wpforms-admin-form-embed-wizard',
			'wpforms_admin_form_embed_wizard',
			[
				'nonce'        => wp_create_nonce( 'wpforms_admin_form_embed_wizard_nonce' ),
				'is_edit_page' => (int) $this->is_form_embed_page( 'edit' ),
				'i18n'         => [
					'add_to_page' => __( 'Add to Page', 'wpforms-lite' ),
					'create_page' => __( 'Create Page', 'wpforms-lite' ),
				],
			]
		);
	}

	/**
	 * Output HTML.
	 *
	 * @since 1.6.2
	 */
	public function output() {

		// We don't need to output tooltip if Challenge is active.
		if ( $this->is_form_embed_page() && $this->is_challenge_active() ) {
			$this->delete_meta();

			return;
		}

		// We don't need to output tooltip if it's not an embed flow.
		if ( $this->is_form_embed_page() && ! $this->get_meta() ) {
			return;
		}

		$template = $this->is_form_embed_page() ? 'admin/form-embed-wizard/tooltip' : 'admin/form-embed-wizard/popup';
		$args     = [];

		if ( ! $this->is_form_embed_page() ) {
			$args['user_can_edit_pages'] = current_user_can( 'edit_pages' );
			$args['dropdown_pages']      = $this->get_select_dropdown_pages_html();
			$args['education_items']     = $this->get_education_items();
			$args['is_lite']             = ! wpforms()->is_pro();
		}

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo wpforms_render( $template, $args );

		$this->delete_meta();
	}

	/**
	 * Check if Challenge is active.
	 *
	 * @since 1.6.4
	 *
	 * @return boolean
	 */
	public function is_challenge_active() {

		static $challenge_active = null;

		if ( $challenge_active === null ) {
			$challenge        = wpforms()->obj( 'challenge' );
			$challenge_active = method_exists( $challenge, 'challenge_active' ) ? $challenge->challenge_active() : false;
		}

		return $challenge_active;
	}

	/**
	 * Check if the current page is a form embed page.
	 *
	 * @since 1.6.2
	 *
	 * @param string $type Type of the embed page to check. Can be '', 'add' or 'edit'. By default is empty string.
	 *
	 * @return boolean
	 */
	public function is_form_embed_page( $type = '' ) {

		global $pagenow;

		$type = $type === 'add' || $type === 'edit' ? $type : '';

		if (
			$pagenow !== 'post.php' &&
			$pagenow !== 'post-new.php'
		) {
			return false;
		}

		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$post_id   = empty( $_GET['post'] ) ? 0 : (int) $_GET['post'];
		$post_type = empty( $_GET['post_type'] ) ? '' : sanitize_key( $_GET['post_type'] );
		$action    = empty( $_GET['action'] ) ? 'add' : sanitize_key( $_GET['action'] );
		// phpcs:enable

		if ( $pagenow === 'post-new.php' &&
			( empty( $post_type ) || $post_type !== 'page' )
		) {
			return false;
		}

		if (
			$pagenow === 'post.php' &&
			( empty( $post_id ) || get_post_type( $post_id ) !== 'page' )
		) {
			return false;
		}

		$meta       = $this->get_meta();
		$embed_page = ! empty( $meta['embed_page'] ) ? (int) $meta['embed_page'] : 0;

		if ( 'add' === $action && 0 === $embed_page && $type !== 'edit' ) {
			return true;
		}

		if ( ! empty( $post_id ) && $embed_page === $post_id && $type !== 'add' ) {
			return true;
		}

		return false;
	}

	/**
	 * Set user's embed meta data.
	 *
	 * @since 1.6.2
	 *
	 * @param array $data Data array to set.
	 */
	public function set_meta( $data ) {

		update_user_meta( get_current_user_id(), 'wpforms_admin_form_embed_wizard', $data );
	}

	/**
	 * Get user's embed meta data.
	 *
	 * @since 1.6.2
	 *
	 * @return array User's embed meta data.
	 */
	public function get_meta() {

		return get_user_meta( get_current_user_id(), 'wpforms_admin_form_embed_wizard', true );
	}

	/**
	 * Delete user's embed meta data.
	 *
	 * @since 1.6.2
	 */
	public function delete_meta() {

		delete_user_meta( get_current_user_id(), 'wpforms_admin_form_embed_wizard' );
	}

	/**
	 * Get embed page URL via AJAX.
	 *
	 * @since 1.6.2
	 */
	public function get_embed_page_url_ajax() {

		// Run a security check.
		check_admin_referer( 'wpforms_admin_form_embed_wizard_nonce' );

		// Check for permissions.
		if ( ! wpforms_current_user_can( 'edit_forms' ) ) {
			wp_send_json_error( esc_html__( 'You are not allowed to perform this action.', 'wpforms-lite' ) );
		}

		$page_id = ! empty( $_POST['pageId'] ) ? absint( $_POST['pageId'] ) : 0;
		$meta    = $this->prepare_meta_data( $page_id );

		$this->set_meta( $meta );

		// Update challenge option to properly continue challenge on the embed page.
		$this->update_challenge_option( $meta );

		wp_send_json_success( $meta['url'] );
	}

	/**
	 * Prepare meta data for the embed page.
	 *
	 * @since 1.9.4
	 *
	 * @param int $page_id Page ID.
	 *
	 * @return array
	 */
	private function prepare_meta_data( int $page_id ): array {

		if ( ! empty( $page_id ) ) {
			$url  = get_edit_post_link( $page_id, '' );
			$meta = [
				'embed_page' => $page_id,
			];
		} else {
			$url  = add_query_arg( 'post_type', 'page', admin_url( 'post-new.php' ) );
			$meta = [
				'embed_page'       => 0,
				'embed_page_title' => ! empty( $_POST['pageTitle'] ) ? sanitize_text_field( wp_unslash( $_POST['pageTitle'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing
			];
		}

		$meta['form_id'] = ! empty( $_POST['formId'] ) ? absint( $_POST['formId'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing
		$meta['url']     = $url;

		return $meta;
	}

	/**
	 * Update challenge option to properly continue challenge on the embed page.
	 *
	 * @since 1.9.4
	 *
	 * @param array $meta Meta data.
	 */
	private function update_challenge_option( array $meta ): void {

		if ( $this->is_challenge_active() ) {
			$challenge = wpforms()->obj( 'challenge' );

			if ( $challenge && method_exists( $challenge, 'set_challenge_option' ) ) {
				$challenge->set_challenge_option( [ 'embed_page' => $meta['embed_page'] ] );
			}
		}
	}

	/**
	 * Set default title for the new page.
	 *
	 * @since 1.6.2
	 *
	 * @param string   $post_title Default post title.
	 * @param \WP_Post $post       Post object.
	 *
	 * @return string New default post title.
	 */
	public function embed_page_title( $post_title, $post ) {

		$meta = $this->get_meta();

		$this->delete_meta();

		return empty( $meta['embed_page_title'] ) ? $post_title : $meta['embed_page_title'];
	}

	/**
	 * Embed the form to the new page.
	 *
	 * @since 1.6.2
	 *
	 * @param string   $post_content Default post content.
	 * @param \WP_Post $post         Post object.
	 *
	 * @return string Embedding string (shortcode or GB component code).
	 */
	public function embed_page_content( $post_content, $post ) {

		$meta = $this->get_meta();

		$form_id = ! empty( $meta['form_id'] ) ? $meta['form_id'] : 0;
		$page_id = ! empty( $meta['embed_page'] ) ? $meta['embed_page'] : 0;

		if ( ! empty( $page_id ) || empty( $form_id ) ) {
			return $post_content;
		}

		if ( wpforms_is_gutenberg_active() ) {
			$pattern = '<!-- wp:wpforms/form-selector {"formId":"%d"} /-->';
		} else {
			$pattern = '[wpforms id="%d" title="false" description="false"]';
		}

		return sprintf( $pattern, absint( $form_id ) );
	}

	/**
	 * Get product education items shown in the embed wizard card grid.
	 *
	 * Reuses the canonical item list from `PreviewDropdownEducationItems`
	 * and enriches each item with wizard-specific UTM content, demo URL,
	 * card-body attributes, and (for Lite users) the upgrade URL.
	 *
	 * @since 1.10.1
	 *
	 * @return array
	 */
	private function get_education_items(): array {

		$items = ( new PreviewDropdownEducationItems( $this->get_current_form() ) )->get_items();

		if ( empty( $items ) ) {
			return [];
		}

		// UTM content mapping keyed by item slug.
		$utm_map = [
			'conversational-forms' => [
				'upgrade' => 'Conversational Forms - Upgrade to Pro Link',
				'demo'    => 'Conversational Forms - Demo Link',
			],
			'form-pages'           => [
				'upgrade' => 'Form Pages - Upgrade to Pro Link',
				'demo'    => 'Form Pages - Demo Link',
			],
			'lead-forms'           => [
				'upgrade' => 'Lead Forms - Upgrade to Pro Link',
				'demo'    => 'Lead Forms - Demo Link',
			],
		];

		$is_lite = ! wpforms()->is_pro();

		foreach ( $items as &$item ) {
			$slug_utm = $utm_map[ $item['slug'] ] ?? [];

			// Override UTM medium and content for the embed wizard context.
			$item['utm_medium']       = 'Builder Embed Modal';
			$item['utm_content']      = $slug_utm['upgrade'] ?? $item['utm_content'];
			$item['demo_utm_content'] = $slug_utm['demo'] ?? ( $item['demo_utm_content'] ?? $item['utm_content'] );

			$item['demo_url']     = PreviewDropdownEducationItems::get_demo_url( $item );
			$item['button_attrs'] = $this->get_education_item_attrs( $item, $is_lite );

			if ( $is_lite ) {
				$item['upgrade_url'] = wpforms_admin_upgrade_link( 'Builder Embed Modal', $item['utm_content'] );
			}
		}
		unset( $item );

		return $items;
	}

	/**
	 * Build the CSS class and data attributes for an education card body.
	 *
	 * Mirrors the Preview dropdown's `print_preview_dropdown_item()` logic so
	 * clicks on the card body are handled by the same JS flows already wired
	 * to the Preview dropdown: education upgrade modal (Lite), Addons Required
	 * modal (Pro without addon), or "active addon" preview handler (Pro with
	 * addon installed and active).
	 *
	 * @since 1.10.1
	 *
	 * @param array $item    Education item.
	 * @param bool  $is_lite Whether the current user is on Lite.
	 *
	 * @return array {
	 *     Card body rendering data.
	 *
	 *     @type string $class CSS class for the card body.
	 *     @type array  $data  Associative array of `data-*` attributes (name => value).
	 * }
	 */
	private function get_education_item_attrs( array $item, bool $is_lite ): array {

		if ( $is_lite ) {
			// Lite user — card click opens the pricing page directly,
			// bypassing the standard education upgrade modal.
			return [
				'class' => 'wpforms-admin-form-embed-wizard-card-education-lite',
				'data'  => [
					'name'        => $item['label'],
					'utm-content' => $item['utm_content'],
					'upgrade-url' => wpforms_admin_upgrade_link( 'Builder Embed Modal', $item['utm_content'] ),
				],
			];
		}

		$addon_slug = $item['addon_slug'] ?? '';

		if ( PreviewDropdownEducationItems::is_addon_active( $addon_slug ) ) {
			// Addon is installed and active — open preview URL in a new tab,
			// scoped to the addon section via the `section` query param.
			$preview_url = $item['preview_url'] ?? '';

			return [
				'class' => 'wpforms-admin-form-embed-wizard-card-education-active',
				'data'  => [
					'section'     => $item['section'] ?? '',
					'toggle-id'   => $item['toggle_id'] ?? '',
					'preview-url' => $preview_url,
				],
			];
		}

		// Pro user without the addon installed or active — open the
		// Addons Required modal (same handler as the Preview dropdown).
		return [
			'class' => 'wpforms-addons-required-trigger',
			'data'  => [
				'license'     => 'pro',
				'name'        => $item['label'],
				'utm-content' => $item['utm_content'],
				'demo-url'    => $item['demo_url'],
				'addon-slug'  => $addon_slug,
			],
		];
	}

	/**
	 * Resolve the current builder form from the Builder singleton.
	 *
	 * @since 1.10.1
	 *
	 * @return WP_Post|null
	 */
	private function get_current_form(): ?WP_Post {

		if ( ! class_exists( WPForms_Builder::class ) ) {
			return null;
		}

		$form = WPForms_Builder::instance()->form ?? null;

		return $form instanceof WP_Post ? $form : null;
	}

	/**
	 * Generate select with pages which are available to edit for current user.
	 *
	 * @since 1.6.6
	 * @since 1.7.9 Refactor to use ChoicesJS instead of `wp_dropdown_pages()`.
	 *
	 * @return string
	 */
	private function get_select_dropdown_pages_html() {

		$dropdown_pages = wpforms_search_posts(
			'',
			[
				'count'       => self::MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT,
				'post_status' => self::POST_STATUSES_OF_DROPDOWN_PAGES,
			]
		);

		if ( empty( $dropdown_pages ) ) {
			return '';
		}

		$total_pages    = 0;
		$wp_count_pages = (array) wp_count_posts( 'page' );

		foreach ( $wp_count_pages as $page_status => $pages_count ) {
			if ( in_array( $page_status, self::POST_STATUSES_OF_DROPDOWN_PAGES, true ) ) {
				$total_pages += $pages_count;
			}
		}

		// Include so we can use `\wpforms_settings_select_callback()`.
		require_once WPFORMS_PLUGIN_DIR . 'includes/admin/settings-api.php';

		$options = [ '' => esc_html__( 'Search for a page', 'wpforms-lite' ) ] + wp_list_pluck( $dropdown_pages, 'post_title', 'ID' );

		return wpforms_settings_select_callback(
			[
				'id'        => 'form-embed-wizard-choicesjs-select-pages',
				'type'      => 'select',
				'choicesjs' => true,
				'options'   => $options,
				'data'      => [
					'use_ajax' => $total_pages > self::MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT,
				],
			]
		);
	}

	/**
	 * Get search result pages for ChoicesJS via AJAX.
	 *
	 * @since 1.7.9
	 */
	public function get_search_result_pages_ajax() {

		// Run a security check.
		if ( ! check_ajax_referer( 'wpforms_admin_form_embed_wizard_nonce', false, false ) ) {
			wp_send_json_error(
				[
					'msg' => esc_html__( 'Your session expired. Please reload the builder.', 'wpforms-lite' ),
				]
			);
		}

		// Check for permissions.
		if ( ! wpforms_current_user_can( 'edit_forms' ) ) {
			wp_send_json_error( esc_html__( 'You are not allowed to perform this action.', 'wpforms-lite' ) );
		}

		if ( ! array_key_exists( 'search', $_GET ) ) {
			wp_send_json_error(
				[
					'msg' => esc_html__( 'Incorrect usage of this operation.', 'wpforms-lite' ),
				]
			);
		}

		$result_pages = wpforms_search_pages_for_dropdown(
			sanitize_text_field( wp_unslash( $_GET['search'] ) ),
			[
				'count'       => self::MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT,
				'post_status' => self::POST_STATUSES_OF_DROPDOWN_PAGES,
			]
		);

		if ( empty( $result_pages ) ) {
			wp_send_json_error( [] );
		}

		wp_send_json_success( $result_pages );
	}
}
