<?php
/**
 * Onboarding wizard for Mail Doctor.
 *
 * @package MailDoctor
 */

namespace MailDoctor;

use MailDoctor\Mail\Config\Providers\Presets as Provider_Presets;

use MailDoctor\Helpers\Settings;
use MailDoctor\Helpers\Migrations;
use MailDoctor\Checks;

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

/**
 * Handles the initial onboarding flow.
 */
class Onboarding {


	/**
	 * Option key for wizard state.
	 */
	const OPTION_KEY = 'mail_doctor_onboarding';

	/**
	 * Slug for the onboarding page.
	 */
	const PAGE_SLUG = 'mail-doctor-onboarding';

	/**
	 * Initialize hooks.
	 *
	 * @return void
	 */
	public static function init(): void {
		add_action( 'admin_init', array( __CLASS__, 'handle_post' ) );
		add_action( 'admin_menu', array( __CLASS__, 'register_page' ), 11 );
		add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
		add_action( 'admin_notices', array( __CLASS__, 'maybe_prompt_notice' ) );
	}

	/**
	 * Determine if onboarding is required.
	 *
	 * @return bool
	 */
	public static function needs_onboarding(): bool {
		$status = self::get_status();

		if ( ! empty( $status['completed'] ) || ! empty( $status['dismissed'] ) ) {
			return false;
		}

		$settings = Settings::all();

		return empty( $settings['smtp_host'] ) || empty( $settings['smtp_username'] ) || empty( $settings['smtp_password'] );
	}

	/**
	 * Retrieve current wizard state.
	 *
	 * @return array<string, mixed>
	 */
	public static function get_status(): array {
		$defaults = array(
			'completed'    => false,
			'dismissed'    => false,
			'current_step' => 1,
			'provider'     => '',
		);

		$stored = get_option( self::OPTION_KEY, array() );

		if ( ! is_array( $stored ) ) {
			$stored = array();
		}

		return wp_parse_args( $stored, $defaults );
	}

	/**
	 * Update wizard state.
	 *
	 * @param array<string, mixed> $data Data to merge into stored option.
	 * @return void
	 */
	protected static function update_status( array $data ): void {
		$status = self::get_status();
		update_option( self::OPTION_KEY, array_merge( $status, $data ) );
	}

	/**
	 * Register onboarding admin page.
	 *
	 * @return void
	 */
	public static function register_page(): void {
		if ( self::needs_onboarding() || self::is_onboarding_request() ) {
			add_submenu_page(
				'maildoctor',
				__( 'Mail Doctor Setup', 'mail-doctor' ),
				__( 'Mail Doctor Setup', 'mail-doctor' ),
				Admin::required_capability(),
				self::PAGE_SLUG,
				array( __CLASS__, 'render_page' )
			);
		}
	}

	/**
	 * Determine if current request is for onboarding page.
	 *
	 * @return bool
	 */
	protected static function is_onboarding_request(): bool {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Page routing, no data processing.
		return isset( $_GET['page'] ) && self::PAGE_SLUG === sanitize_key( wp_unslash( $_GET['page'] ) );
	}

	/**
	 * Enqueue onboarding assets.
	 *
	 * @param string $hook Current admin hook.
	 * @return void
	 */
	public static function enqueue_assets( string $hook ): void {
		if ( ! self::is_onboarding_request() ) {
			return;
		}

		wp_enqueue_style(
			'mail-doctor-onboarding',
			MAIL_DOCTOR_URL . 'assets/css/onboarding/main.css',
			array(),
			MAIL_DOCTOR_VERSION
		);

		wp_enqueue_script(
			'mail-doctor-onboarding',
			MAIL_DOCTOR_URL . 'assets/js/onboarding.js',
			array( 'jquery' ),
			MAIL_DOCTOR_VERSION,
			true
		);

		wp_localize_script(
			'mail-doctor-onboarding',
			'MailDoctorOnboarding',
			array(
				'ajaxUrl'         => admin_url( 'admin-ajax.php' ),
				'connectionNonce' => wp_create_nonce( 'mail_doctor_connection_nonce' ),
			)
		);
	}

	/**
	 * Handle onboarding form submissions.
	 *
	 * @return void
	 */
	public static function handle_post(): void {
		// Handle Restart/Reset Action (GET)
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Existence check; nonce verified on next line.
		if ( self::is_onboarding_request() && isset( $_GET['mail_doctor_onboarding_restart'] ) ) {
			if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'mail_doctor_onboarding_restart' ) ) {
				wp_die( esc_html__( 'Security check failed.', 'mail-doctor' ) );
			}

			if ( current_user_can( Admin::required_capability() ) ) {
				self::reset_status();
				wp_safe_redirect( self::step_url( 1 ) );
				exit;
			}
		}

		// Handle Skip Action (GET)
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Existence check; nonce verified on next line.
		if ( isset( $_GET['mail_doctor_onboarding_skip'] ) && self::is_onboarding_request() ) {
			if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'mail_doctor_onboarding_skip' ) ) {
				wp_die( esc_html__( 'Security check failed.', 'mail-doctor' ) );
			}

			if ( current_user_can( Admin::required_capability() ) ) {
				self::update_status(
					array(
						'dismissed'    => true,
						'completed'    => false,
						'current_step' => 1,
					)
				);
				wp_safe_redirect( Admin::page_url() );
				exit;
			}
		}

		if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Early exit check only; value sanitized via (int) cast on line 214.
		if ( empty( $_POST['mail_doctor_onboarding_step'] ) ) {
			return;
		}

		if ( ! current_user_can( Admin::required_capability() ) ) {
			return;
		}

		check_admin_referer( 'mail_doctor_onboarding_step' );

		$step = (int) $_POST['mail_doctor_onboarding_step'];

		switch ( $step ) {
			case 1:
				self::process_step_one();
				break;
			case 2:
				self::process_step_two();
				break;
			case 3:
				self::process_step_three();
				break;
			case 4:
				self::process_step_four();
				break;
		}
	}

	/**
	 * Handle provider selection.
	 *
	 * @return void
	 */
	protected static function process_step_one(): void {
		// Nonce verification is handled in handle_post() before calling this method.
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified in handle_post().
		$provider = '';
		if ( isset( $_POST['onboarding_provider'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified via check_admin_referer() in handle_post() before this method is called.
			$provider = sanitize_key( wp_unslash( $_POST['onboarding_provider'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified in handle_post() before this method is called.
		}

		$preset = self::provider_preset( $provider );

		if ( $preset ) {
			Settings::update( $preset );
		}

		self::update_status(
			array(
				'provider'     => $provider,
				'current_step' => 2,
			)
		);

		wp_safe_redirect( self::step_url( 2 ) );
		exit;
	}

	/**
	 * Handle SMTP credentials save.
	 *
	 * @return void
	 */
	protected static function process_step_two(): void {
		// Nonce verification is handled in handle_post() before calling this method.
		// phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified in handle_post().
		$data = array(
			'smtp_host'              => isset( $_POST['smtp_host'] ) ? sanitize_text_field( wp_unslash( $_POST['smtp_host'] ) ) : '',
			'smtp_port'              => isset( $_POST['smtp_port'] ) ? absint( wp_unslash( $_POST['smtp_port'] ) ) : 587,
			'smtp_encryption'        => isset( $_POST['smtp_encryption'] ) ? sanitize_text_field( wp_unslash( $_POST['smtp_encryption'] ) ) : '',
			'smtp_username'          => isset( $_POST['smtp_username'] ) ? sanitize_text_field( wp_unslash( $_POST['smtp_username'] ) ) : '',
			'smtp_password'          => isset( $_POST['smtp_password'] ) ? sanitize_text_field( wp_unslash( $_POST['smtp_password'] ) ) : '',
			'from_email'             => isset( $_POST['from_email'] ) ? sanitize_email( wp_unslash( $_POST['from_email'] ) ) : '',
			'from_name'              => isset( $_POST['from_name'] ) ? sanitize_text_field( wp_unslash( $_POST['from_name'] ) ) : '',
			'transport'              => isset( $_POST['transport'] ) ? sanitize_key( wp_unslash( $_POST['transport'] ) ) : 'smtp',
			'mailgun_api_key'        => isset( $_POST['mailgun_api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['mailgun_api_key'] ) ) : '',
			'mailgun_api_domain'     => isset( $_POST['mailgun_api_domain'] ) ? sanitize_text_field( wp_unslash( $_POST['mailgun_api_domain'] ) ) : '',
			'mailgun_api_endpoint'   => isset( $_POST['mailgun_api_endpoint'] ) ? sanitize_text_field( wp_unslash( $_POST['mailgun_api_endpoint'] ) ) : '',
			'sendgrid_api_key'       => isset( $_POST['sendgrid_api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['sendgrid_api_key'] ) ) : '',
			'postmark_api_token'     => isset( $_POST['postmark_api_token'] ) ? sanitize_text_field( wp_unslash( $_POST['postmark_api_token'] ) ) : '',
			'sparkpost_api_key'      => isset( $_POST['sparkpost_api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['sparkpost_api_key'] ) ) : '',
			'sparkpost_api_endpoint' => isset( $_POST['sparkpost_api_endpoint'] ) ? sanitize_text_field( wp_unslash( $_POST['sparkpost_api_endpoint'] ) ) : '',
			'ses_api_key'            => isset( $_POST['ses_api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['ses_api_key'] ) ) : '',
			'ses_api_secret'         => isset( $_POST['ses_api_secret'] ) ? sanitize_text_field( wp_unslash( $_POST['ses_api_secret'] ) ) : '',
			'ses_api_session_token'  => isset( $_POST['ses_api_session_token'] ) ? sanitize_text_field( wp_unslash( $_POST['ses_api_session_token'] ) ) : '',
			'ses_api_region'         => isset( $_POST['ses_api_region'] ) ? sanitize_text_field( wp_unslash( $_POST['ses_api_region'] ) ) : 'us-east-1',
			'generic_api_endpoint'   => isset( $_POST['generic_api_endpoint'] ) ? esc_url_raw( wp_unslash( $_POST['generic_api_endpoint'] ) ) : '',
			'generic_api_method'     => isset( $_POST['generic_api_method'] ) ? sanitize_text_field( wp_unslash( $_POST['generic_api_method'] ) ) : 'POST',
			'generic_api_auth_token' => isset( $_POST['generic_api_auth_token'] ) ? sanitize_text_field( wp_unslash( $_POST['generic_api_auth_token'] ) ) : '',
		);
		// phpcs:enable WordPress.Security.NonceVerification.Missing

		Settings::update( $data );

		self::update_status(
			array(
				'current_step' => 3,
			)
		);

		wp_safe_redirect( self::step_url( 3 ) );
		exit;
	}

	/**
	 * Handle domain diagnostics confirmation.
	 *
	 * @return void
	 */
	protected static function process_step_three(): void {
		self::update_status(
			array(
				'current_step' => 4,
			)
		);

		wp_safe_redirect( self::step_url( 4 ) );
		exit;
	}

	/**
	 * Finish onboarding.
	 *
	 * @return void
	 */
	protected static function process_step_four(): void {
		self::update_status(
			array(
				'current_step' => 4,
				'completed'    => true,
				'dismissed'    => false,
			)
		);

		Migrations::maybe_upgrade( MAIL_DOCTOR_VERSION );

		add_settings_error(
			'order_mail_doctor',
			'onboarding_complete',
			__( 'Mail Doctor setup is complete. You can adjust settings at any time.', 'mail-doctor' ),
			'updated'
		);

		wp_safe_redirect( Admin::page_url() );
		exit;
	}

	/**
	 * Render the onboarding page.
	 *
	 * @return void
	 */
	public static function render_page(): void {
		if ( ! current_user_can( Admin::required_capability() ) ) {
			wp_die( esc_html__( 'You do not have permission to manage Mail Doctor settings.', 'mail-doctor' ) );
		}

			$mail_doctor_settings               = Settings::all();
			$mail_doctor_status                 = self::get_status();
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only step navigation.
			$mail_doctor_step                   = max( 1, min( 4, isset( $_GET['step'] ) ? absint( wp_unslash( $_GET['step'] ) ) : (int) $mail_doctor_status['current_step'] ) );
			$mail_doctor_status['current_step'] = $mail_doctor_step;
			self::update_status( array( 'current_step' => $mail_doctor_step ) );

		$mail_doctor_providers         = self::provider_presets();
		$mail_doctor_dns               = array();
		$mail_doctor_transport_options = Admin::get_transport_options();
		$mail_doctor_ses_regions       = Admin::get_ses_regions();

		if ( $mail_doctor_step >= 3 ) {
			$mail_doctor_domain = '';
			if ( ! empty( $mail_doctor_settings['from_email'] ) && false !== strpos( $mail_doctor_settings['from_email'], '@' ) ) {
				$parts              = explode( '@', $mail_doctor_settings['from_email'] );
				$mail_doctor_domain = end( $parts );
			}
			$mail_doctor_dns = Checks::dns_summary( $mail_doctor_domain );
		}

		include MAIL_DOCTOR_PATH . 'templates/admin/onboarding.php';
	}

	/**
	 * Display notice prompting users to complete onboarding.
	 *
	 * @return void
	 */
	public static function maybe_prompt_notice(): void {
		if ( ! current_user_can( Admin::required_capability() ) || ! self::needs_onboarding() || self::is_onboarding_request() ) {
			return;
		}

		$link = esc_url( self::step_url( self::get_status()['current_step'] ?? 1 ) );

		$message = sprintf(
			/* translators: %s: onboarding link. */
			esc_html__( 'Mail Doctor needs a quick setup. %s to complete the onboarding wizard.', 'mail-doctor' ),
			sprintf(
				'<a href="%s">%s</a>',
				$link,
				esc_html__( 'Start now', 'mail-doctor' )
			)
		);

		echo '<div class="notice notice-warning"><p>' . wp_kses( $message, array( 'a' => array( 'href' => array() ) ) ) . '</p></div>';
	}

	/**
	 * Build step URL.
	 *
	 * @param int $step Step number.
	 * @return string
	 */
	public static function step_url( int $step ): string {
		return add_query_arg(
			array(
				'page' => self::PAGE_SLUG,
				'step' => max( 1, min( 4, $step ) ),
			),
			admin_url( 'admin.php' )
		);
	}

	/**
	 * Provider preset map.
	 *
	 * @return array<string, array<string, mixed>>
	 */
	protected static function provider_presets(): array {
		return Provider_Presets::all();
	}

	/**
	 * Retrieve preset data for provider.
	 *
	 * @param string $provider Provider key.
	 * @return array<string, mixed>
	 */
	protected static function provider_preset( string $provider ): array {
		return Provider_Presets::get( $provider );
	}

	/**
	 * Reset onboarding progress so users can rerun the wizard.
	 *
	 * @return void
	 */
	protected static function reset_status(): void {
		update_option(
			self::OPTION_KEY,
			array(
				'completed'    => false,
				'dismissed'    => false,
				'current_step' => 1,
				'provider'     => '',
			)
		);
	}
}
