<?php
/**
 * Setup Wizard
 *
 * Orchestrates the first-run setup wizard: registering the hidden admin page,
 * redirecting on first activation, rendering the modal, and routing form
 * submissions through the correct wizard step.
 *
 * Flow:
 *   1. On activation, WizardState::schedule_redirect() sets a short transient.
 *   2. On the next admin_init, maybe_redirect() consumes the transient and
 *      redirects to the wizard page (ambassadorhub-setup).
 *   3. The wizard page renders the modal overlay housing the current step.
 *   4. Each step's form POSTs to admin-post.php with action=ambh_wizard_step.
 *   5. handle_step() calls the step's handle(), then advances (or completes)
 *      the wizard and redirects back.
 *
 * @package AmbassadorHub\Admin\Wizard
 */

namespace AmbassadorHub\Admin\Wizard;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use AmbassadorHub\Admin\AdminPage;
use AmbassadorHub\Admin\Wizard\Steps\WelcomeStep;
use AmbassadorHub\Admin\Wizard\Steps\CreatePagesStep;
use AmbassadorHub\Admin\Wizard\Steps\TestEmailStep;
use AmbassadorHub\Admin\Wizard\Steps\PspStep;
use AmbassadorHub\Admin\Wizard\Steps\CampaignStep;

/**
 * Registers and drives the setup wizard.
 */
final class SetupWizard {

	/** Admin page / menu slug for the wizard. */
	public const PAGE_SLUG = 'ambassadorhub-setup';

	/**
	 * Register all hooks.
	 *
	 * @return void
	 */
	public static function init(): void {
		add_action( 'admin_init', array( self::class, 'maybe_redirect' ) );
		add_action( 'admin_menu', array( self::class, 'register_page' ), 20 );
		add_action( 'admin_head', array( self::class, 'hide_menu_item' ) );
		add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_assets' ) );
		add_action( 'admin_notices', array( self::class, 'maybe_show_plugins_page_nudge' ) );
		add_action( 'admin_notices', array( self::class, 'maybe_show_setup_incomplete_notice' ) );
		add_action( 'admin_post_ambh_wizard_step', array( self::class, 'handle_step' ) );
		add_action( 'admin_post_ambh_wizard_skip_all', array( self::class, 'handle_skip_all' ) );
		add_action( 'admin_post_ambh_wizard_restart', array( self::class, 'handle_restart' ) );
	}

	// -------------------------------------------------------------------------
	// Step registry
	// -------------------------------------------------------------------------

	/**
	 * Return the ordered list of wizard steps.
	 *
	 * @return AbstractWizardStep[]
	 */
	private static function get_steps(): array {
		return array(
			new WelcomeStep(),
			new CreatePagesStep(),
			new TestEmailStep(),
			new PspStep(),
			new CampaignStep(),
		);
	}

	// -------------------------------------------------------------------------
	// Activation redirect
	// -------------------------------------------------------------------------

	/**
	 * On the first admin request after activation, redirect to the wizard.
	 *
	 * Consumes the transient so it fires exactly once.
	 *
	 * @return void
	 */
	public static function maybe_redirect(): void {
		if ( ! get_transient( WizardState::TRANSIENT_REDIRECT ) ) {
			return;
		}

		// Never consume the transient in environments where a redirect is unsafe.
		// The transient stays alive (60 s) so the next normal page load picks it up.
		if ( wp_doing_ajax() || wp_doing_cron() || is_network_admin() ) {
			return;
		}

		// Bulk plugin activation: WordPress sets activate-multi in the request.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['activate-multi'] ) ) {
			return;
		}

		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			return;
		}

		// Avoid redirect loops.
		if ( self::is_wizard_page() ) {
			return;
		}

		// All clear: consume the transient and redirect.
		delete_transient( WizardState::TRANSIENT_REDIRECT );
		wp_safe_redirect( admin_url( 'admin.php?page=' . self::PAGE_SLUG ) );
		exit;
	}

	// -------------------------------------------------------------------------
	// Page registration + assets
	// -------------------------------------------------------------------------

	/**
	 * Register the wizard under the plugin menu so WordPress can resolve its page title.
	 *
	 * @return void
	 */
	public static function register_page(): void {
		add_submenu_page(
			'ambassadorhub',
			__( 'AmbassadorHub Setup', 'ambassadorhub' ),
			__( 'Setup', 'ambassadorhub' ),
			'ambh_manage_hub',
			self::PAGE_SLUG,
			array( self::class, 'render' )
		);
	}

	/**
	 * Hide the wizard submenu item while keeping the page registered.
	 *
	 * WordPress needs the submenu to exist when it calculates the admin title,
	 * so we remove it later during admin_head instead of registering it without
	 * a parent.
	 *
	 * @return void
	 */
	public static function hide_menu_item(): void {
		remove_submenu_page( 'ambassadorhub', self::PAGE_SLUG );
	}

	/**
	 * Enqueue wizard styles on the wizard page only.
	 *
	 * @param string $hook Current admin page hook suffix.
	 * @return void
	 */
	public static function enqueue_assets( string $hook ): void {
		if ( false === strpos( $hook, self::PAGE_SLUG ) ) {
			return;
		}

		wp_enqueue_style( 'ambh-admin' );
		wp_enqueue_style(
			'ambh-wizard',
			trailingslashit( plugin_dir_url( __FILE__ ) ) . 'assets/wizard.css',
			array( 'ambh-admin' ),
			'1.0.0'
		);
	}

	/**
	 * Show a single dismissible nudge on the Plugins page when the wizard
	 * has not been completed yet.
	 *
	 * Per WooCommerce / WordPress UX guidelines: the activation nudge belongs
	 * on the Plugins page in context, not on the plugin's own screens or globally.
	 *
	 * @return void
	 */
	public static function maybe_show_plugins_page_nudge(): void {
		global $pagenow;

		if ( 'plugins.php' !== $pagenow ) {
			return;
		}
		if ( WizardState::is_completed() ) {
			return;
		}
		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			return;
		}

		$wizard_url = admin_url( 'admin.php?page=' . self::PAGE_SLUG );
		?>
		<div class="notice notice-info is-dismissible">
			<p>
				<?php esc_html_e( 'AmbassadorHub is installed — run the quick setup wizard to finish configuring it.', 'ambassadorhub' ); ?>
				&nbsp;<a href="<?php echo esc_url( $wizard_url ); ?>" class="button button-primary button-small">
					<?php esc_html_e( 'Start setup', 'ambassadorhub' ); ?>
				</a>
			</p>
		</div>
		<?php
	}

	/**
	 * Show a persistent warning on all ambassadorhub admin pages when one or
	 * more alertable setup steps are not yet complete.
	 *
	 * @return void
	 */
	public static function maybe_show_setup_incomplete_notice(): void {
		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			return;
		}

		// Scope to ambassadorhub pages only, but not the wizard page itself.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$page = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : '';
		if ( ! str_starts_with( $page, 'ambassadorhub' ) || self::PAGE_SLUG === $page ) {
			return;
		}

		$incomplete = array_filter(
			self::get_steps(),
			static fn( AbstractWizardStep $step ) => $step->is_alertable() && ! $step->is_done()
		);

		if ( empty( $incomplete ) ) {
			return;
		}

		$restart_url = admin_url( 'admin-post.php' );
		?>
		<div class="notice notice-warning">
			<p>
				<strong><?php esc_html_e( 'AmbassadorHub setup is incomplete.', 'ambassadorhub' ); ?></strong>
				<?php esc_html_e( 'The following steps still need to be configured:', 'ambassadorhub' ); ?>
			</p>
			<ul style="margin:.4em 0 .8em 1.5em;list-style:disc;">
				<?php foreach ( $incomplete as $step ) : ?>
					<li><?php echo esc_html( $step->get_title() ); ?></li>
				<?php endforeach; ?>
			</ul>
			<form method="post" action="<?php echo esc_url( $restart_url ); ?>" style="margin-bottom:.5em;">
				<input type="hidden" name="action" value="ambh_wizard_restart">
				<?php wp_nonce_field( 'ambh_wizard_restart' ); ?>
				<button type="submit" class="button button-primary button-small">
					<?php esc_html_e( 'Restart setup wizard', 'ambassadorhub' ); ?>
				</button>
			</form>
		</div>
		<?php
	}

	/**
	 * Whether the current admin request is for the wizard setup page.
	 *
	 * @return bool
	 */
	private static function is_wizard_page(): bool {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return isset( $_GET['page'] ) && self::PAGE_SLUG === sanitize_key( $_GET['page'] );
	}

	// -------------------------------------------------------------------------
	// Rendering
	// -------------------------------------------------------------------------

	/**
	 * Render the wizard page.
	 *
	 * @return void
	 */
	public static function render(): void {
		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			wp_die( esc_html__( 'You do not have permission to access this page.', 'ambassadorhub' ) );
		}

		$steps         = self::get_steps();
		$total         = count( $steps );
		$current_index = WizardState::get_step();

		// Wizard already done — redirect to dashboard.
		if ( $current_index >= $total ) {
			WizardState::mark_completed();
			wp_safe_redirect( admin_url( 'admin.php?page=ambassadorhub' ) );
			exit;
		}

		$current_step = $steps[ $current_index ];
		$is_last      = ( $current_index + 1 ) === $total;

		// Build the "Skip setup" button for the header action slot.
		$skip_all_html =
			'<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" style="display:inline;">'
			. '<input type="hidden" name="action" value="ambh_wizard_skip_all">'
			. wp_nonce_field( 'ambh_wizard_skip_all', '_wpnonce', true, false )
			. '<button type="submit" class="ambh-header__add-new">'
			. esc_html__( 'Skip setup', 'ambassadorhub' )
			. '</button></form>';

		AdminPage::header(
			esc_html__( 'AmbassadorHub', 'ambassadorhub' ),
			esc_html__( 'Quick setup', 'ambassadorhub' ),
			$skip_all_html
		);
		?>
		<div class="wrap">
			<h1 class="hidden"></h1>
			<div class="ambh-wizard-container">
				<div class="ambh-wizard-card">

					<!-- Progress dots -->
					<div class="ambh-wizard-dots" role="list"
						aria-label="<?php esc_attr_e( 'Setup steps', 'ambassadorhub' ); ?>">
						<?php for ( $i = 0; $i < $total; $i++ ) : ?>
							<?php
							$dot_class = 'ambh-wizard-dot';
							if ( $i < $current_index ) {
								$dot_class .= ' is-done';
							} elseif ( $i === $current_index ) {
								$dot_class .= ' is-active';
							}
							?>
							<div class="<?php echo esc_attr( $dot_class ); ?>"
								title="<?php echo esc_attr( $steps[ $i ]->get_title() ); ?>"
								role="listitem">
								<?php if ( $i < $current_index ) : ?>
									<span class="dashicons dashicons-yes" aria-hidden="true"></span>
								<?php else : ?>
									<?php echo absint( $i + 1 ); ?>
								<?php endif; ?>
							</div>
						<?php endfor; ?>
					</div>

					<!-- Step body -->
					<div class="ambh-wizard-card__body">
					<h2 class="ambh-wizard-step__title">
						<?php echo esc_html( $current_step->get_title() ); ?>
					</h2>

					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"
						class="ambh-wizard-step-form">
						<input type="hidden" name="action" value="ambh_wizard_step">
						<input type="hidden" name="ambh_wizard_step_index" value="<?php echo (int) $current_index; ?>">
						<?php wp_nonce_field( 'ambh_wizard_step' ); ?>

						<div class="ambh-wizard-step__content">
							<?php $current_step->render(); ?>
						</div>

						<!-- Footer nav -->
						<div class="ambh-wizard-card__footer">
							<div class="ambh-wizard-nav">
								<?php if ( $current_step->is_skippable() ) : ?>
									<button type="submit" name="ambh_wizard_action" value="skip"
										class="button ambh-wizard-skip-btn">
										<?php esc_html_e( 'Skip', 'ambassadorhub' ); ?>
									</button>
								<?php endif; ?>

								<button type="submit" name="ambh_wizard_action" value="next"
									class="button button-primary">
									<?php
									if ( $is_last ) {
										esc_html_e( 'Finish setup', 'ambassadorhub' );
									} else {
										esc_html_e( 'Next →', 'ambassadorhub' );
									}
									?>
								</button>
							</div>

							<p class="ambh-wizard-step-count">
								<?php
								echo esc_html(
									sprintf(
										/* translators: 1: current step number, 2: total steps */
										__( 'Step %1$d of %2$d', 'ambassadorhub' ),
										$current_index + 1,
										$total
									)
								);
								?>
							</p>
						</div>
					</form>
				</div>

				</div><!-- /.ambh-wizard-card -->
			</div><!-- /.ambh-wizard-container -->
		</div><!-- /.wrap -->
		<?php
	}

	// -------------------------------------------------------------------------
	// Form handlers
	// -------------------------------------------------------------------------

	/**
	 * Handle a step form submission (Next or Skip).
	 *
	 * @return void
	 */
	public static function handle_step(): void {
		check_admin_referer( 'ambh_wizard_step' );

		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'ambassadorhub' ) );
		}

		$steps         = self::get_steps();
		$total         = count( $steps );
		$step_index    = isset( $_POST['ambh_wizard_step_index'] ) ? (int) $_POST['ambh_wizard_step_index'] : 0;
		$wizard_action = isset( $_POST['ambh_wizard_action'] ) ? sanitize_key( $_POST['ambh_wizard_action'] ) : 'next';

		if ( ! isset( $steps[ $step_index ] ) ) {
			wp_safe_redirect( admin_url( 'admin.php?page=' . self::PAGE_SLUG ) );
			exit;
		}

		$step       = $steps[ $step_index ];
		$next_index = $step_index + 1;

		if ( 'skip' === $wizard_action ) {
			// Skip this individual step.
			self::advance_or_complete( $next_index, $total );
		}

		// 'next': let the step process its data.
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- steps sanitize their own fields within handle().
		$redirect_override = $step->handle( $_POST );

		if ( null !== $redirect_override && '' !== $redirect_override ) {
			// Step wants to redirect somewhere specific (e.g. stay on same step with a message).
			wp_safe_redirect( $redirect_override );
			exit;
		}

		self::advance_or_complete( $next_index, $total );
	}

	/**
	 * Handle the "Re-run wizard" request: reset state and redirect to step 1.
	 *
	 * @return void
	 */
	public static function handle_restart(): void {
		check_admin_referer( 'ambh_wizard_restart' );

		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'ambassadorhub' ) );
		}

		delete_option( WizardState::OPTION_COMPLETED );
		WizardState::set_step( 0 );

		wp_safe_redirect( admin_url( 'admin.php?page=' . self::PAGE_SLUG ) );
		exit;
	}

	/**
	 * Handle the "Skip setup" (skip entire wizard) form submission.
	 *
	 * @return void
	 */
	public static function handle_skip_all(): void {
		check_admin_referer( 'ambh_wizard_skip_all' );

		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'ambassadorhub' ) );
		}

		WizardState::mark_completed();
		wp_safe_redirect( admin_url( 'admin.php?page=ambassadorhub' ) );
		exit;
	}

	// -------------------------------------------------------------------------
	// Internal helpers
	// -------------------------------------------------------------------------

	/**
	 * Either advance to the next step or complete the wizard.
	 *
	 * @param int $next_index Index of the step to move to.
	 * @param int $total      Total number of steps.
	 * @return void
	 */
	private static function advance_or_complete( int $next_index, int $total ): void {
		if ( $next_index >= $total ) {
			WizardState::mark_completed();
			wp_safe_redirect( admin_url( 'admin.php?page=ambassadorhub&ambh_wizard_done=1' ) );
			exit;
		}

		WizardState::set_step( $next_index );
		wp_safe_redirect( admin_url( 'admin.php?page=' . self::PAGE_SLUG ) );
		exit;
	}
}
