<?php
/**
 * SMTP settings admin page.
 *
 * @package SubmissionInbox
 */

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

/**
 * Renders and saves SMTP settings.
 */
class SUBIN_SmtpSettingsPage {
	const SAVE_NONCE_ACTION = 'subin_save_smtp_settings';
	const SAVE_NONCE_NAME   = 'subin_smtp_settings_nonce';
	const TEST_NONCE_ACTION = 'subin_send_test_email';
	const TEST_NONCE_NAME   = 'subin_test_email_nonce';

	/**
	 * Settings repository.
	 *
	 * @var SUBIN_SettingsRepository
	 */
	private $settings;

	/**
	 * Constructor.
	 *
	 * @param SUBIN_SettingsRepository $settings Settings repository.
	 */
	public function __construct( SUBIN_SettingsRepository $settings ) {
		$this->settings = $settings;
	}

	/**
	 * Render page.
	 *
	 * @return void
	 */
	public function render() {
		if ( ! current_user_can( SUBIN_AdminMenu::CAPABILITY ) ) {
			wp_die( esc_html__( 'You do not have permission to perform this action.', 'submission-inbox' ) );
		}

		$this->safe_admin_redirect( admin_url( 'admin.php?page=subin-settings&subin_settings_tab=sending' ) );
	}

	/**
	 * Render SMTP settings inside the main Settings page.
	 *
	 * @return void
	 */
	public function render_embedded() {
		$settings = $this->settings->all();
		$this->render_configuration_warnings( $settings );
		$this->render_settings_form( $settings );
		$this->render_test_email_form();
	}

	/**
	 * Handle submitted SMTP page actions.
	 *
	 * @return void
	 */
	public function maybe_handle_post() {
		$request_method = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ?? '' ) );
		if ( 'POST' !== strtoupper( $request_method ) ) {
			return;
		}

		if ( ! current_user_can( SUBIN_AdminMenu::CAPABILITY ) ) {
			wp_die( esc_html__( 'You do not have permission to access this page.', 'submission-inbox' ) );
		}

		$action = sanitize_key( wp_unslash( $_POST['subin_smtp_action'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Action is routed to handlers that verify their own nonces.

		if ( 'save_settings' === $action ) {
			$this->save_settings();
			return;
		}

		if ( 'send_test_email' === $action ) {
			$this->send_test_email();
		}
	}

	/**
	 * Render SMTP settings form.
	 *
	 * @param array<string,mixed> $settings Settings.
	 * @return void
	 */
	private function render_settings_form( array $settings ) {
		?>
		<form method="post" action="">
			<input type="hidden" name="subin_smtp_action" value="save_settings" />
			<?php wp_nonce_field( self::SAVE_NONCE_ACTION, self::SAVE_NONCE_NAME ); ?>
			<div class="subin-settings-section">
				<h2>
					<?php esc_html_e( 'Sending settings', 'submission-inbox' ); ?>
					<?php SUBIN_View::help_tooltip( __( 'Controls how WordPress sends email from this site.', 'submission-inbox' ) ); ?>
				</h2>
			<table class="form-table" role="presentation">
				<tbody>
					<tr>
						<th scope="row"><?php esc_html_e( 'Enable SMTP', 'submission-inbox' ); ?></th>
						<td>
							<?php SUBIN_View::checkbox_field( 'enable_smtp', __( 'Use SMTP settings for WordPress emails', 'submission-inbox' ), (bool) $settings['enable_smtp'] ); ?>
						</td>
					</tr>
					<tr>
						<th scope="row">
							<label for="subin-from-email"><?php esc_html_e( 'From Email', 'submission-inbox' ); ?></label>
							<?php SUBIN_View::help_tooltip( __( 'The email address WordPress uses as the sender.', 'submission-inbox' ) ); ?>
						</th>
						<td><input type="email" id="subin-from-email" name="from_email" class="regular-text" value="<?php echo esc_attr( $settings['from_email'] ); ?>" /></td>
					</tr>
					<tr>
						<th scope="row"><label for="subin-from-name"><?php esc_html_e( 'From Name', 'submission-inbox' ); ?></label></th>
						<td><input type="text" id="subin-from-name" name="from_name" class="regular-text" value="<?php echo esc_attr( $settings['from_name'] ); ?>" /></td>
					</tr>
					<tr>
						<th scope="row"><label for="subin-notification-recipient-email"><?php esc_html_e( 'Default admin notification recipient', 'submission-inbox' ); ?></label></th>
						<td>
							<input type="email" id="subin-notification-recipient-email" name="notification_recipient_email" class="regular-text" value="<?php echo esc_attr( $settings['notification_recipient_email'] ); ?>" />
							<p class="description"><?php esc_html_e( 'Used for form admin notifications unless a form has a custom recipient.', 'submission-inbox' ); ?></p>
						</td>
					</tr>
				</tbody>
			</table>
			</div>
			<div class="subin-settings-section">
				<h2><?php esc_html_e( 'SMTP server', 'submission-inbox' ); ?></h2>
			<table class="form-table" role="presentation">
				<tbody>
					<tr>
						<th scope="row">
							<label for="subin-smtp-host"><?php esc_html_e( 'SMTP Host', 'submission-inbox' ); ?></label>
							<?php SUBIN_View::help_tooltip( __( 'The server used to send WordPress emails through SMTP.', 'submission-inbox' ) ); ?>
						</th>
						<td><input type="text" id="subin-smtp-host" name="smtp_host" class="regular-text" value="<?php echo esc_attr( $settings['smtp_host'] ); ?>" /></td>
					</tr>
					<tr>
						<th scope="row"><label for="subin-smtp-port"><?php esc_html_e( 'SMTP Port', 'submission-inbox' ); ?></label></th>
						<td><input type="number" id="subin-smtp-port" name="smtp_port" class="small-text" min="1" max="65535" value="<?php echo esc_attr( (string) $settings['smtp_port'] ); ?>" /></td>
					</tr>
					<tr>
						<th scope="row"><label for="subin-smtp-encryption"><?php esc_html_e( 'Encryption', 'submission-inbox' ); ?></label></th>
						<td>
							<select id="subin-smtp-encryption" name="smtp_encryption">
								<option value="none" <?php selected( $settings['smtp_encryption'], 'none' ); ?>><?php esc_html_e( 'None', 'submission-inbox' ); ?></option>
								<option value="ssl" <?php selected( $settings['smtp_encryption'], 'ssl' ); ?>><?php esc_html_e( 'SSL', 'submission-inbox' ); ?></option>
								<option value="tls" <?php selected( $settings['smtp_encryption'], 'tls' ); ?>><?php esc_html_e( 'TLS', 'submission-inbox' ); ?></option>
							</select>
						</td>
					</tr>
					<tr>
						<th scope="row"><?php esc_html_e( 'SMTP Auth', 'submission-inbox' ); ?></th>
						<td>
							<?php SUBIN_View::checkbox_field( 'smtp_auth', __( 'Require username and password authentication', 'submission-inbox' ), (bool) $settings['smtp_auth'] ); ?>
						</td>
					</tr>
					<tr>
						<th scope="row"><label for="subin-smtp-username"><?php esc_html_e( 'Username', 'submission-inbox' ); ?></label></th>
						<td><input type="text" id="subin-smtp-username" name="smtp_username" class="regular-text" value="<?php echo esc_attr( $settings['smtp_username'] ); ?>" autocomplete="off" /></td>
					</tr>
					<tr>
						<th scope="row">
							<label for="subin-smtp-password"><?php esc_html_e( 'Password', 'submission-inbox' ); ?></label>
							<?php SUBIN_View::help_tooltip( __( 'For security, the saved password is never shown in the field.', 'submission-inbox' ) ); ?>
						</th>
						<td>
							<input type="password" id="subin-smtp-password" name="smtp_password" class="regular-text" value="" placeholder="<?php echo esc_attr( $this->password_placeholder( $settings ) ); ?>" autocomplete="new-password" />
							<p class="description"><?php esc_html_e( 'The saved password is never printed into the page.', 'submission-inbox' ); ?></p>
						</td>
					</tr>
				</tbody>
			</table>
			</div>
			<?php submit_button( __( 'Save settings', 'submission-inbox' ) ); ?>
		</form>
		<?php
	}

	/**
	 * Render test email form.
	 *
	 * @return void
	 */
	private function render_test_email_form() {
		?>
		<div class="subin-settings-section">
			<h2><?php esc_html_e( 'Test Email', 'submission-inbox' ); ?></h2>
			<p><?php esc_html_e( 'Send a simple WordPress email using the current SMTP settings.', 'submission-inbox' ); ?></p>
			<form method="post" action="">
				<input type="hidden" name="subin_smtp_action" value="send_test_email" />
				<?php wp_nonce_field( self::TEST_NONCE_ACTION, self::TEST_NONCE_NAME ); ?>
				<table class="form-table" role="presentation">
					<tbody>
						<tr>
							<th scope="row"><label for="subin-test-email-to"><?php esc_html_e( 'Send test email to', 'submission-inbox' ); ?></label></th>
							<td><input type="email" id="subin-test-email-to" name="test_email_to" class="regular-text" value="" required /></td>
						</tr>
					</tbody>
				</table>
				<?php submit_button( __( 'Send Test Email', 'submission-inbox' ), 'secondary' ); ?>
			</form>
		</div>
		<?php
	}

	/**
	 * Save SMTP settings.
	 *
	 * @return void
	 */
	private function save_settings() {
		if ( ! $this->verify_nonce( self::SAVE_NONCE_ACTION, self::SAVE_NONCE_NAME ) ) {
			return;
		}

		$result = $this->settings->update_smtp_settings( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- SMTP settings nonce is verified above before this POST payload is sanitized by the repository.

		if ( is_wp_error( $result ) ) {
			add_settings_error(
				'subin_messages',
				$result->get_error_code(),
				$result->get_error_message(),
				'error'
			);
			return;
		}

		add_settings_error(
			'subin_messages',
			'subin_smtp_saved',
			__( 'Settings saved.', 'submission-inbox' ),
			'updated'
		);
	}

	/**
	 * Send a test email.
	 *
	 * @return void
	 */
	private function send_test_email() {
		if ( ! $this->verify_nonce( self::TEST_NONCE_ACTION, self::TEST_NONCE_NAME ) ) {
			return;
		}

		$recipient = sanitize_email( wp_unslash( $_POST['test_email_to'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Test email nonce is verified above.

		if ( '' === $recipient || ! is_email( $recipient ) ) {
			add_settings_error(
				'subin_messages',
				'subin_test_email_invalid_recipient',
				__( 'Enter a valid recipient email address.', 'submission-inbox' ),
				'error'
			);
			return;
		}

		$mail_error  = null;
		$failed_hook = function ( $wp_error ) use ( &$mail_error ) {
			if ( is_wp_error( $wp_error ) ) {
				$mail_error = $wp_error;
			}
		};

		add_action( 'wp_mail_failed', $failed_hook );

		$sent = wp_mail(
			$recipient,
			__( 'Submission Inbox Test Email', 'submission-inbox' ),
			__( 'This is a test email sent by Submission Inbox.', 'submission-inbox' )
		);

		remove_action( 'wp_mail_failed', $failed_hook );

		if ( $sent ) {
			add_settings_error(
				'subin_messages',
				'subin_test_email_sent',
				__( 'Test email was sent by WordPress. Please check the recipient mailbox.', 'submission-inbox' ),
				'updated'
			);
			return;
		}

		$message = __( 'Test email could not be sent.', 'submission-inbox' );

		if ( is_wp_error( $mail_error ) ) {
			$error_message = $this->sanitize_test_error( $mail_error->get_error_message() );
			if ( '' !== $error_message ) {
				$message .= ' ' . sprintf(
					/* translators: %s: sanitized mail error message. */
					__( 'Error: %s', 'submission-inbox' ),
					$error_message
				);
			}
		}

		add_settings_error(
			'subin_messages',
			'subin_test_email_failed',
			$message,
			'error'
		);
	}

	/**
	 * Render current configuration warnings.
	 *
	 * @param array<string,mixed> $settings Settings.
	 * @return void
	 */
	private function render_configuration_warnings( array $settings ) {
		if ( ! empty( $settings['enable_smtp'] ) && '' === (string) $settings['smtp_host'] ) {
			?>
			<div class="notice notice-warning">
				<p><?php esc_html_e( 'SMTP is enabled, but SMTP Host is empty.', 'submission-inbox' ); ?></p>
			</div>
			<?php
		}

		if ( '' !== (string) $settings['from_email'] && ! is_email( $settings['from_email'] ) ) {
			?>
			<div class="notice notice-warning">
				<p><?php esc_html_e( 'From Email must be a valid email address.', 'submission-inbox' ); ?></p>
			</div>
			<?php
		} elseif ( '' === (string) $settings['from_email'] ) {
			$admin_email = sanitize_email( (string) get_option( 'admin_email' ) );
			?>
			<div class="notice notice-warning">
				<p>
					<?php
					if ( is_email( $admin_email ) ) {
						printf(
							/* translators: %s: Site admin email address. */
							esc_html__( 'From Email is empty. WordPress will use the site admin email as the sender: %s.', 'submission-inbox' ),
							esc_html( $admin_email )
						);
					} else {
						esc_html_e( 'From Email is empty and the site admin email is not valid. Add a valid From Email before sending mail.', 'submission-inbox' );
					}
					?>
				</p>
			</div>
			<?php
		}

		if ( ! empty( $settings['smtp_auth'] ) && '' === (string) $settings['smtp_username'] ) {
			?>
			<div class="notice notice-warning">
				<p><?php esc_html_e( 'SMTP authentication is enabled, but Username is empty.', 'submission-inbox' ); ?></p>
			</div>
			<?php
		}
	}

	/**
	 * Verify a submitted nonce and show a controlled error.
	 *
	 * @param string $action Nonce action.
	 * @param string $name Nonce field name.
	 * @return bool
	 */
	private function verify_nonce( $action, $name ) {
		if ( isset( $_POST[ $name ] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ $name ] ) ), $action ) ) {
			return true;
		}

		add_settings_error(
			'subin_messages',
			'subin_security_check_failed',
			__( 'Security check failed. Please try again.', 'submission-inbox' ),
			'error'
		);

		return false;
	}

	/**
	 * Sanitize a mail error for admin display.
	 *
	 * @param string $message Error message.
	 * @return string
	 */
	private function sanitize_test_error( $message ) {
		$settings = $this->settings->all();
		$message  = wp_strip_all_tags( (string) $message );

		foreach ( array( 'smtp_password', 'smtp_username' ) as $key ) {
			if ( ! empty( $settings[ $key ] ) ) {
				$message = str_replace( (string) $settings[ $key ], '[redacted]', $message );
			}
		}

		$message = sanitize_text_field( $message );

		if ( function_exists( 'mb_substr' ) ) {
			return mb_substr( $message, 0, 180 );
		}

		return substr( $message, 0, 180 );
	}

	/**
	 * Get password placeholder text.
	 *
	 * @param array<string,mixed> $settings Settings.
	 * @return string
	 */
	private function password_placeholder( array $settings ) {
		return '' !== (string) $settings['smtp_password']
			? __( 'Password is saved. Leave blank to keep existing password.', 'submission-inbox' )
			: '';
	}

	/**
	 * Redirect from an admin page callback without header warnings.
	 *
	 * @param string $url Target URL.
	 * @return void
	 */
	private function safe_admin_redirect( $url ) {
		$url = esc_url_raw( $url );
		if ( ! headers_sent() ) {
			wp_safe_redirect( $url );
			exit;
		}

		wp_die(
			wp_kses_post(
				sprintf(
					/* translators: %s: redirect URL. */
					__( 'The request was processed. <a href="%s">Continue</a>.', 'submission-inbox' ),
					esc_url( $url )
				)
			),
			esc_html__( 'Redirect', 'submission-inbox' ),
			array( 'response' => 303 )
		);
		exit;
	}
}
