<?php
/**
 * First-time configuration wizard (Yoast-style stepper)
 *
 * A guided path over the existing settings — every step writes the SAME
 * options as the settings pages (no parallel wizard state). Skippable at
 * every step; finishing sets bw_schema_setup_complete, which flips the
 * dashboard's "Complete the first-time configuration" check to passing.
 *
 * Reached from the dashboard task, the Tools page, and the post-activation
 * redirect. Hidden from the admin menu (BW_Schema_Admin removes the entry).
 *
 * POST handling runs on admin_init (before headers) so each save can
 * redirect to the next step (POST → redirect → GET).
 *
 * @package BW_Schema
 * @since 3.3.0
 */

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

class BW_Schema_Page_Setup extends BW_Schema_Page {

	/**
	 * Option flag set when the wizard is finished
	 *
	 * @var string
	 */
	const COMPLETE_OPTION = 'bw_schema_setup_complete';

	/**
	 * Number of steps
	 *
	 * @var int
	 */
	const STEPS = 4;

	/**
	 * Initialize page properties
	 *
	 * @return void
	 */
	protected function init() {
		$this->slug        = 'bw-schema-setup';
		$this->title       = __( 'Solomon Schema Setup', 'bw-schema' );
		$this->parent_slug = 'bw-schema';

		// Handle step submissions before headers are sent, so we can redirect
		add_action( 'admin_init', array( $this, 'handle_step_post' ) );
	}

	/**
	 * Step titles, in order
	 *
	 * @return string[] Step number (1-based) => title
	 */
	private function get_steps() {
		return array(
			1 => __( 'Organization', 'bw-schema' ),
			2 => __( 'Contact', 'bw-schema' ),
			3 => __( 'People', 'bw-schema' ),
			4 => __( 'Content', 'bw-schema' ),
		);
	}

	/**
	 * Current step from the URL (clamped to valid range)
	 *
	 * @return int
	 */
	private function get_current_step() {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only navigation
		$step = isset( $_GET['step'] ) ? (int) $_GET['step'] : 1;
		return max( 1, min( self::STEPS, $step ) );
	}

	/**
	 * URL for a given step
	 *
	 * @param int $step Step number
	 * @return string
	 */
	private function get_step_url( $step ) {
		return add_query_arg(
			array( 'page' => $this->slug, 'step' => (int) $step ),
			admin_url( 'admin.php' )
		);
	}

	/**
	 * Whether the wizard has been finished
	 *
	 * @return bool
	 */
	public static function is_complete() {
		return (bool) get_option( self::COMPLETE_OPTION, false );
	}

	/**
	 * Base-class save hook — unused; steps are handled on admin_init
	 *
	 * @return void
	 */
	protected function handle_save() {}

	/**
	 * Handle a step submission (admin_init, before output)
	 *
	 * Saves the posted step's data via the same services the settings pages
	 * use, then redirects to the next step (or the dashboard after step 4).
	 *
	 * @return void
	 */
	public function handle_step_post() {
		if ( ! isset( $_POST['bw_schema_setup_step'], $_POST['bw_schema_setup_nonce'] ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- verified below
		if ( ! isset( $_GET['page'] ) || $this->slug !== $_GET['page'] ) {
			return;
		}

		if ( ! current_user_can( $this->capability ) ) {
			return;
		}

		if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['bw_schema_setup_nonce'] ) ), 'bw_schema_setup' ) ) {
			wp_die( esc_html__( 'Security check failed. Please go back and try again.', 'bw-schema' ) );
		}

		$step  = max( 1, min( self::STEPS, (int) $_POST['bw_schema_setup_step'] ) );
		$issue = '';

		switch ( $step ) {
			case 1:
				$issue = $this->save_step_organization();
				break;
			case 2:
				$this->save_step_contact();
				break;
			case 3:
				$this->save_step_people();
				break;
			case 4:
				$this->save_step_content();
				break;
		}

		// Invalidate schema caches so changes reach the frontend immediately
		if ( class_exists( 'BW_Schema_Cache' ) ) {
			BW_Schema_Cache::invalidate();
			BW_Schema_Cache::invalidate_org_data();
		}

		// Guidance guard: an unfinished choice (category without type, or a
		// logo URL that doesn't resolve) sends the user back to fix it —
		// everything else they entered is already saved.
		if ( '' !== $issue ) {
			wp_safe_redirect( add_query_arg( 'bws-notice', $issue, $this->get_step_url( $step ) ) );
			exit;
		}

		if ( self::STEPS === $step ) {
			update_option( self::COMPLETE_OPTION, time() );
			wp_safe_redirect( admin_url( 'admin.php?page=bw-schema&bws-setup=done' ) );
		} else {
			wp_safe_redirect( $this->get_step_url( $step + 1 ) );
		}
		exit;
	}

	/**
	 * Step 1 save: organization name, business type, logo
	 *
	 * @return string Issue slug for the guidance guard ('' when all good)
	 */
	private function save_step_organization() {
		$issue = '';
		$org   = BW_Schema_Service_Organization::get();

		if ( isset( $_POST['org_name'] ) && '' !== trim( (string) $_POST['org_name'] ) ) {
			$org['name'] = sanitize_text_field( wp_unslash( $_POST['org_name'] ) );
		}

		// Logo: only save a URL that actually resolves to an image.
		// A rejected URL is kept in a short-lived transient so the form can
		// show it back for correction (the previously saved logo is untouched).
		if ( isset( $_POST['org_logo'] ) ) {
			$logo   = esc_url_raw( wp_unslash( $_POST['org_logo'] ) );
			$result = BW_Schema_Service_Organization::verify_remote_image( $logo );

			if ( true === $result ) {
				$org['logo'] = $logo;
				delete_transient( 'bw_schema_logo_rejected_' . get_current_user_id() );
			} else {
				$issue = 'logo-invalid';
				set_transient(
					'bw_schema_logo_rejected_' . get_current_user_id(),
					array( 'url' => $logo, 'reason' => $result->get_error_message() ),
					5 * MINUTE_IN_SECONDS
				);
			}
		}

		BW_Schema_Service_Organization::save( $org );

		// Business classification — same options the Organization page writes
		$category = isset( $_POST['bw_schema_business_category'] )
			? sanitize_key( $_POST['bw_schema_business_category'] ) : '';
		$type     = isset( $_POST['bw_schema_business_type'] )
			? sanitize_key( $_POST['bw_schema_business_type'] ) : '';

		if ( '' !== $category ) {
			update_option( 'bw_schema_business_category', $category );

			// Only accept a type that belongs to the chosen category; anything
			// else (empty, or a leftover from a previous category) clears the
			// type so the state never holds a mismatched category/type pair.
			$valid_types = BW_Schema_Service_Organization::get_types_for_category( $category );
			if ( '' !== $type && isset( $valid_types[ $type ] ) ) {
				update_option( 'bw_schema_business_type', $type );
			} else {
				update_option( 'bw_schema_business_type', '' );
			}
		}

		// A category without a type is the more fundamental gap — it wins
		// over a logo problem when both need attention
		if ( '' !== get_option( 'bw_schema_business_category', '' )
			&& '' === get_option( 'bw_schema_business_type', '' ) ) {
			$issue = 'select-type';
		}

		return $issue;
	}

	/**
	 * Step 2 save: contact details
	 *
	 * @return void
	 */
	private function save_step_contact() {
		$org = BW_Schema_Service_Organization::get();

		if ( isset( $_POST['org_email'] ) ) {
			$org['email'] = sanitize_email( wp_unslash( $_POST['org_email'] ) );
		}
		if ( isset( $_POST['org_telephone'] ) ) {
			$org['telephone'] = sanitize_text_field( wp_unslash( $_POST['org_telephone'] ) );
		}
		if ( isset( $_POST['org_url'] ) && '' !== trim( (string) $_POST['org_url'] ) ) {
			$org['url'] = esc_url_raw( wp_unslash( $_POST['org_url'] ) );
		}

		BW_Schema_Service_Organization::save( $org );

		// "Not used" field opt-outs — absent checkboxes clear the opt-out
		$optouts = isset( $_POST['bw_schema_field_optout'] ) && is_array( $_POST['bw_schema_field_optout'] )
			? array_map( 'sanitize_key', wp_unslash( $_POST['bw_schema_field_optout'] ) )
			: array();
		BW_Schema_Service_Organization::set_field_optouts( $optouts );
	}

	/**
	 * Step 3 save: team post type
	 *
	 * @return void
	 */
	private function save_step_people() {
		$post_type = isset( $_POST['bw_schema_team_post_type'] )
			? sanitize_key( $_POST['bw_schema_team_post_type'] ) : '';

		// '' is a valid choice — "no team section on this site"
		if ( '' === $post_type || post_type_exists( $post_type ) ) {
			BW_Schema_Service_People::set_team_post_type( $post_type );
		}
	}

	/**
	 * Step 4 save: content schema defaults
	 *
	 * @return void
	 */
	private function save_step_content() {
		$eligible = BW_Schema_Service_Content::get_eligible_post_types();

		$selected = isset( $_POST['bw_schema_article_post_types'] ) && is_array( $_POST['bw_schema_article_post_types'] )
			? array_map( 'sanitize_key', wp_unslash( $_POST['bw_schema_article_post_types'] ) )
			: array();

		// Keep only genuinely eligible post types
		$selected = array_values( array_intersect( $selected, array_keys( $eligible ) ) );

		BW_Schema_Service_Content::set_article_post_types( $selected );
		BW_Schema_Service_Content::set_breadcrumbs_enabled( ! empty( $_POST['bw_schema_enable_breadcrumbs'] ) );
	}

	/**
	 * Render page content
	 *
	 * @return void
	 */
	protected function render() {
		$step = $this->get_current_step();

		echo '<div class="bws-setup">';

		$this->render_stepper_nav( $step );

		echo '<div class="bws-card bws-setup-card">';
		echo '<form method="post">';
		wp_nonce_field( 'bw_schema_setup', 'bw_schema_setup_nonce' );
		echo '<input type="hidden" name="bw_schema_setup_step" value="' . esc_attr( $step ) . '">';

		switch ( $step ) {
			case 1:
				$this->render_step_organization();
				break;
			case 2:
				$this->render_step_contact();
				break;
			case 3:
				$this->render_step_people();
				break;
			case 4:
				$this->render_step_content();
				break;
		}

		$this->render_step_footer( $step );

		echo '</form>';
		echo '</div>';
		echo '</div>';
	}

	/**
	 * Render the numbered step navigation
	 *
	 * @param int $current Current step
	 * @return void
	 */
	private function render_stepper_nav( $current ) {
		echo '<ol class="bws-setup-steps">';
		foreach ( $this->get_steps() as $number => $label ) {
			$state = 'upcoming';
			if ( $number < $current ) {
				$state = 'done';
			} elseif ( $number === $current ) {
				$state = 'current';
			}

			echo '<li class="is-' . esc_attr( $state ) . '">';
			if ( 'done' === $state ) {
				echo '<a href="' . esc_url( $this->get_step_url( $number ) ) . '">';
				echo '<span class="bws-setup-step-num" aria-hidden="true">✓</span> ' . esc_html( $label );
				echo '</a>';
			} else {
				echo '<span class="bws-setup-step-num" aria-hidden="true">' . esc_html( $number ) . '</span> ' . esc_html( $label );
			}
			echo '</li>';
		}
		echo '</ol>';
	}

	/**
	 * Step 1: organization identity + business type
	 *
	 * @return void
	 */
	private function render_step_organization() {
		$org      = BW_Schema_Service_Organization::get();
		$category = get_option( 'bw_schema_business_category', '' );
		$type     = get_option( 'bw_schema_business_type', '' );

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display-only flags from the step-1 guard redirect
		$notice     = isset( $_GET['bws-notice'] ) ? sanitize_key( $_GET['bws-notice'] ) : '';
		$needs_type = ( 'select-type' === $notice );

		// Rejected logo (kept briefly so the user can correct it in place)
		$logo_rejected = array();
		if ( 'logo-invalid' === $notice ) {
			$stashed = get_transient( 'bw_schema_logo_rejected_' . get_current_user_id() );
			if ( is_array( $stashed ) && ! empty( $stashed['url'] ) ) {
				$logo_rejected = $stashed;
			}
		}

		$this->render_step_intro(
			__( 'Who is this site about?', 'bw-schema' ),
			__( 'These basics power the Organization schema on every page of the site.', 'bw-schema' )
		);

		if ( $needs_type ) {
			echo '<div class="notice notice-warning inline"><p>';
			echo '<strong>' . esc_html__( 'One more choice needed:', 'bw-schema' ) . '</strong> ';
			echo esc_html__( 'your category is saved, but you haven\'t picked a business type yet. The type is what upgrades your schema from generic Organization to the specific kind search engines prefer.', 'bw-schema' );
			echo '</p></div>';
		}

		if ( ! empty( $logo_rejected ) ) {
			echo '<div class="notice notice-warning inline"><p>';
			echo '<strong>' . esc_html__( 'Logo URL check failed:', 'bw-schema' ) . '</strong> ';
			echo esc_html( $logo_rejected['reason'] );
			echo ' ' . esc_html__( 'Your other details are saved — fix or clear the logo URL to continue.', 'bw-schema' );
			echo '</p></div>';
		}

		echo '<table class="form-table" role="presentation">';

		echo '<tr><th scope="row"><label for="org_name">' . esc_html__( 'Organization name', 'bw-schema' ) . '</label></th><td>';
		echo '<input type="text" class="regular-text" id="org_name" name="org_name" value="' . esc_attr( $org['name'] ) . '" required>';
		echo '<p class="description">' . esc_html__( 'The official name, exactly as it should appear in search results.', 'bw-schema' ) . '</p>';
		echo '</td></tr>';

		echo '<tr><th scope="row"><label for="bw_schema_business_category">' . esc_html__( 'Business category', 'bw-schema' ) . '</label></th><td>';
		echo '<select id="bw_schema_business_category" name="bw_schema_business_category">';
		echo '<option value="">' . esc_html__( '— Select a category —', 'bw-schema' ) . '</option>';
		foreach ( BW_Schema_Service_Organization::get_business_categories() as $key => $label ) {
			echo '<option value="' . esc_attr( $key ) . '" ' . selected( $category, $key, false ) . '>' . esc_html( $label ) . '</option>';
		}
		echo '</select>';
		echo '</td></tr>';

		echo '<tr><th scope="row"><label for="bw_schema_business_type">' . esc_html__( 'Business type', 'bw-schema' ) . '</label></th><td>';
		echo '<select id="bw_schema_business_type" name="bw_schema_business_type">';
		echo '<option value="">' . esc_html__( '— Select a type —', 'bw-schema' ) . '</option>';
		if ( $category ) {
			foreach ( BW_Schema_Service_Organization::get_types_for_category( $category ) as $key => $def ) {
				echo '<option value="' . esc_attr( $key ) . '" ' . selected( $type, $key, false ) . '>' . esc_html( is_array( $def ) ? $def[0] : $def ) . '</option>';
			}
		}
		echo '</select>';
		echo '<p class="description">' . esc_html__( 'Upgrades your markup from generic Organization to the specific schema.org type search engines prefer.', 'bw-schema' ) . '</p>';
		echo '<p class="bws-field-warning" id="bw_schema_type_warning" ' . ( $needs_type ? '' : 'hidden' ) . '>';
		echo esc_html__( 'Please select a business type to go with your category.', 'bw-schema' );
		echo '</p>';
		echo '</td></tr>';

		$logo_value = ! empty( $logo_rejected ) ? $logo_rejected['url'] : $org['logo'];

		echo '<tr><th scope="row"><label for="org_logo">' . esc_html__( 'Logo URL', 'bw-schema' ) . '</label></th><td>';
		echo '<input type="url" class="regular-text" id="org_logo" name="org_logo" value="' . esc_attr( $logo_value ) . '" placeholder="https://…">';
		echo '<p class="description">' . esc_html__( 'Shown next to your organization in search results. Paste a media library URL — it is checked on save.', 'bw-schema' ) . '</p>';
		if ( ! empty( $logo_rejected ) ) {
			echo '<p class="bws-field-warning">' . esc_html( $logo_rejected['reason'] ) . '</p>';
		}
		echo '</td></tr>';

		echo '</table>';

		$this->render_business_type_js();
	}

	/**
	 * Inline JS: repopulate the type select when the category changes
	 *
	 * Same behavior as the Organization settings page, self-contained.
	 *
	 * @return void
	 */
	private function render_business_type_js() {
		$types_by_category = array();
		foreach ( BW_Schema_Service_Organization::get_business_types() as $cat => $types ) {
			foreach ( $types as $key => $def ) {
				$types_by_category[ $cat ][ $key ] = is_array( $def ) ? $def[0] : $def;
			}
		}
		?>
		<script>
		(function () {
			var types = <?php echo wp_json_encode( $types_by_category ); ?>;
			var categorySelect = document.getElementById('bw_schema_business_category');
			var typeSelect = document.getElementById('bw_schema_business_type');
			if (!categorySelect || !typeSelect) { return; }

			var warning = document.getElementById('bw_schema_type_warning');

			categorySelect.addEventListener('change', function () {
				var options = types[this.value] || {};
				typeSelect.innerHTML = '';
				var placeholder = document.createElement('option');
				placeholder.value = '';
				placeholder.textContent = '<?php echo esc_js( __( '— Select a type —', 'bw-schema' ) ); ?>';
				typeSelect.appendChild(placeholder);
				Object.keys(options).forEach(function (key) {
					var option = document.createElement('option');
					option.value = key;
					option.textContent = options[key];
					typeSelect.appendChild(option);
				});
			});

			typeSelect.addEventListener('change', function () {
				if (warning && this.value) { warning.hidden = true; }
			});

			// Block Save & Continue when a category is chosen but no type —
			// the server guard catches this too; this just saves a round-trip.
			typeSelect.form.addEventListener('submit', function (e) {
				if (categorySelect.value && !typeSelect.value) {
					e.preventDefault();
					if (warning) { warning.hidden = false; }
					typeSelect.focus();
				}
			});
		})();
		</script>
		<?php
	}

	/**
	 * Step 2: contact details
	 *
	 * @return void
	 */
	private function render_step_contact() {
		$org = BW_Schema_Service_Organization::get();

		$this->render_step_intro(
			__( 'How can people reach you?', 'bw-schema' ),
			__( 'Contact details appear in your Organization schema and help search engines connect your site to your business listings.', 'bw-schema' )
		);

		echo '<table class="form-table" role="presentation">';

		echo '<tr><th scope="row"><label for="org_url">' . esc_html__( 'Website URL', 'bw-schema' ) . '</label></th><td>';
		echo '<input type="url" class="regular-text" id="org_url" name="org_url" value="' . esc_attr( $org['url'] ) . '">';
		echo '</td></tr>';

		echo '<tr><th scope="row"><label for="org_email">' . esc_html__( 'Email address', 'bw-schema' ) . '</label></th><td>';
		echo '<input type="email" class="regular-text" id="org_email" name="org_email" value="' . esc_attr( $org['email'] ) . '">';
		$this->render_optout_checkbox( 'email' );
		echo '</td></tr>';

		echo '<tr><th scope="row"><label for="org_telephone">' . esc_html__( 'Phone number', 'bw-schema' ) . '</label></th><td>';
		echo '<input type="tel" class="regular-text" id="org_telephone" name="org_telephone" value="' . esc_attr( $org['telephone'] ) . '" placeholder="+1-201-555-0123">';
		echo '<p class="description">' . esc_html__( 'International format works best (e.g. +62-361-555-0123).', 'bw-schema' ) . '</p>';
		$this->render_optout_checkbox( 'telephone' );
		echo '</td></tr>';

		echo '</table>';

		echo '<p class="description">';
		printf(
			/* translators: %s: link to the Locations tab */
			esc_html__( 'Physical addresses are managed per-location — you can add them later under %s.', 'bw-schema' ),
			'<a href="' . esc_url( admin_url( 'admin.php?page=bw-schema-organization&tab=locations' ) ) . '">' . esc_html__( 'Organization → Locations', 'bw-schema' ) . '</a>'
		);
		echo '</p>';
	}

	/**
	 * Render a "not used" opt-out checkbox for a contact field
	 *
	 * @param string $field Opt-outable field key ('telephone'|'email')
	 * @return void
	 */
	private function render_optout_checkbox( $field ) {
		echo '<label class="bw-schema-optout">';
		echo '<input type="checkbox" name="bw_schema_field_optout[]" value="' . esc_attr( $field ) . '" '
			. checked( BW_Schema_Service_Organization::is_field_opted_out( $field ), true, false ) . '> ';
		echo esc_html__( 'Not used — this organization doesn\'t have this, don\'t count it as missing', 'bw-schema' );
		echo '</label>';
	}

	/**
	 * Step 3: team post type
	 *
	 * @return void
	 */
	private function render_step_people() {
		$current = BW_Schema_Service_People::get_team_post_type();

		$this->render_step_intro(
			__( 'Does this site have a team section?', 'bw-schema' ),
			__( 'Pick the post type that holds your team members. Each member page then emits Person schema linked to your organization.', 'bw-schema' )
		);

		echo '<table class="form-table" role="presentation">';
		echo '<tr><th scope="row"><label for="bw_schema_team_post_type">' . esc_html__( 'Team post type', 'bw-schema' ) . '</label></th><td>';
		echo '<select id="bw_schema_team_post_type" name="bw_schema_team_post_type">';
		echo '<option value="">' . esc_html__( 'No team section on this site', 'bw-schema' ) . '</option>';

		foreach ( get_post_types( array( 'public' => true ), 'objects' ) as $post_type ) {
			if ( in_array( $post_type->name, array( 'attachment', 'post', 'page' ), true ) ) {
				continue;
			}
			$count     = wp_count_posts( $post_type->name );
			$published = isset( $count->publish ) ? (int) $count->publish : 0;

			echo '<option value="' . esc_attr( $post_type->name ) . '" ' . selected( $current, $post_type->name, false ) . '>';
			printf(
				/* translators: 1: post type label, 2: post type slug, 3: published count */
				esc_html__( '%1$s (%2$s) — %3$d published', 'bw-schema' ),
				esc_html( $post_type->labels->name ),
				esc_html( $post_type->name ),
				(int) $published
			);
			echo '</option>';
		}

		echo '</select>';
		echo '<p class="description">' . esc_html__( 'Members detected in the chosen post type appear on the dashboard health checks (photos, job titles).', 'bw-schema' ) . '</p>';
		echo '</td></tr>';
		echo '</table>';
	}

	/**
	 * Step 4: content schema defaults
	 *
	 * @return void
	 */
	private function render_step_content() {
		$eligible = BW_Schema_Service_Content::get_eligible_post_types();
		$selected = BW_Schema_Service_Content::get_article_post_types();

		$this->render_step_intro(
			__( 'What content gets schema markup?', 'bw-schema' ),
			__( 'Selected post types emit Article schema on their pages. Team pages always emit Person schema regardless.', 'bw-schema' )
		);

		echo '<table class="form-table" role="presentation">';

		echo '<tr><th scope="row">' . esc_html__( 'Article schema', 'bw-schema' ) . '</th><td>';
		echo '<fieldset>';
		foreach ( $eligible as $slug => $label ) {
			echo '<label style="display:block; margin-bottom:4px;">';
			echo '<input type="checkbox" name="bw_schema_article_post_types[]" value="' . esc_attr( $slug ) . '" ' . checked( in_array( $slug, $selected, true ), true, false ) . '> ';
			echo esc_html( $label ) . ' <code>' . esc_html( $slug ) . '</code>';
			echo '</label>';
		}
		echo '</fieldset>';
		echo '</td></tr>';

		echo '<tr><th scope="row">' . esc_html__( 'Breadcrumbs', 'bw-schema' ) . '</th><td>';
		echo '<label>';
		echo '<input type="checkbox" name="bw_schema_enable_breadcrumbs" value="1" ' . checked( BW_Schema_Service_Content::is_breadcrumbs_enabled(), true, false ) . '> ';
		echo esc_html__( 'Help search engines show a page trail (Home › About › Team) under your search results (recommended)', 'bw-schema' );
		echo '</label>';
		echo '</td></tr>';

		echo '</table>';
	}

	/**
	 * Render a step's heading + description
	 *
	 * @param string $heading Step heading
	 * @param string $description Step description
	 * @return void
	 */
	private function render_step_intro( $heading, $description ) {
		echo '<h2 class="bws-setup-heading">' . esc_html( $heading ) . '</h2>';
		echo '<p class="bws-setup-description">' . esc_html( $description ) . '</p>';
	}

	/**
	 * Render the step footer: back / skip / continue
	 *
	 * @param int $step Current step
	 * @return void
	 */
	private function render_step_footer( $step ) {
		$is_last = ( self::STEPS === $step );

		echo '<div class="bws-setup-footer">';

		echo '<div class="bws-setup-footer-left">';
		if ( $step > 1 ) {
			echo '<a class="button" href="' . esc_url( $this->get_step_url( $step - 1 ) ) . '">← ' . esc_html__( 'Back', 'bw-schema' ) . '</a>';
		}
		echo '</div>';

		echo '<div class="bws-setup-footer-right">';
		if ( $is_last ) {
			echo '<a class="bws-setup-skip" href="' . esc_url( admin_url( 'admin.php?page=bw-schema' ) ) . '">' . esc_html__( 'Skip for now — the dashboard will remind you', 'bw-schema' ) . '</a> ';
			submit_button( __( 'Finish setup', 'bw-schema' ), 'primary', 'submit', false );
		} else {
			echo '<a class="bws-setup-skip" href="' . esc_url( $this->get_step_url( $step + 1 ) ) . '">' . esc_html__( 'Skip for now — the dashboard will remind you', 'bw-schema' ) . '</a> ';
			submit_button( __( 'Save & Continue', 'bw-schema' ), 'primary', 'submit', false );
		}
		echo '</div>';

		echo '</div>';
	}
}
