<?php
/**
 * Email Delivery settings defaults, normalization, and accessors.
 *
 * @package EmailSmtp
 * @since 1.1.0
 */

namespace EmailSmtp\Includes;

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

final class SettingsSchema {

	public const MIGRATION_VERSION = 2;

	/**
	 * @return array<string, mixed>
	 */
	public static function defaults(): array {
		$admin_email = sanitize_email( (string) get_option( 'admin_email' ) );
		$blogname    = sanitize_text_field( (string) get_option( 'blogname' ) );

		return [
			'provider'          => 'wordpress',
			'migration_version' => 0,
			'smtp_host'         => '',
			'smtp_port'         => '587',
			'smtp_encryption'   => 'tls',
			'smtp_auth'         => '1',
			'smtp_username'     => '',
			'smtp_password'     => '',
			'smtp_autotls'      => '1',
			'smtp_timeout'      => '30',
			'smtp_allow_self_signed' => '0',
			'from_email'        => $admin_email,
			'from_name'         => $blogname,
			'reply_to_email'    => '',
			'reply_to_name'     => '',
			'return_path'       => '',
			'set_return_path'   => '1',
			'override_from'     => '1',
			'force_from_email'  => '1',
			'force_from_name'   => '1',
			'default_content_type' => 'text/html',
			'default_charset'   => 'UTF-8',
			'smtp_debug'        => '0',
			'sendgrid_api_key'  => '',
			'sendgrid_region'   => 'global',
			'mailgun_api_key'   => '',
			'mailgun_domain'    => '',
			'mailgun_region'    => 'us',
			'brevo_api_key'     => '',
			'postmark_server_token' => '',
			'postmark_message_stream' => 'outbound',
			'mailersend_api_token' => '',
			'resend_api_key'    => '',
			'sparkpost_api_key' => '',
			'sparkpost_region'  => 'us',
			'elastic_email_api_key' => '',
			'smtp2go_api_key'   => '',
			'smtp2go_region'    => 'global',
			'mailjet_api_key'   => '',
			'mailjet_secret_key'=> '',
			'netcore_api_key'   => '',
			'netcore_region'    => 'us',
			'mandrill_api_key'  => '',
			'emailit_api_key'   => '',
			'sendlayer_api_key' => '',
			'smtpcom_api_key'   => '',
			'smtpcom_channel'   => '',
			'maileroo_api_key'  => '',
			'turbo_smtp_consumer_key'    => '',
			'turbo_smtp_consumer_secret' => '',
			'turbo_smtp_region'          => 'us',
			'mail_baby_api_key' => '',
			'aws_access_key_id' => '',
			'aws_secret_access_key' => '',
			'aws_region'        => 'us-east-1',
			'aws_configuration_set' => '',
			'aws_credential_source' => 'keys',
			'google_client_id'      => '',
			'google_client_secret'  => '',
			'google_access_token'   => '',
			'google_refresh_token'  => '',
			'google_token_expires'  => '0',
			'google_connected_email' => '',
			'microsoft_client_id'   => '',
			'microsoft_client_secret' => '',
			'microsoft_tenant'      => 'common',
			'microsoft_access_token' => '',
			'microsoft_refresh_token' => '',
			'microsoft_token_expires' => '0',
			'microsoft_connected_email' => '',
			'fallback_enabled'   => '0',
			'fallback_provider'  => '',
			'fallback_on'        => 'retry_safe',
			'retry_max_attempts' => '0',
			'webhook_enabled'    => '0',
			'webhook_secret'     => '',
			'webhook_bird_signing_secret' => '',
			'webhook_sendgrid_verification_key' => '',
			'failure_alert_enabled' => '0',
			'failure_alert_email'   => '',
			'failure_alert_webhook' => '',
			'auto_retry_failed'     => '0',
			/**
			 * When enabled, outbound mail is not delivered. Attempts are still logged.
			 * Global (not per-connection).
			 */
			'simulation_mode'       => '0',
			'connections'              => [],
			'default_connection_id'    => '',
			'fallback_connection_id'   => '',
			'connection_status' => 'not_configured',
			'last_success_at'   => '',
			'last_failure_at'   => '',
			'last_failure_message' => '',
		];
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return array<string, mixed>
	 */
	public static function normalize( array $settings ): array {
		$settings = array_merge( self::defaults(), $settings );
		$settings = SettingsMigrator::ensure_migrated( $settings );

		$provider = self::sanitize_provider_id( (string) ( $settings['provider'] ?? 'wordpress' ) );
		if ( CredentialManager::is_from_constant( 'WP_POWERSUITE_MAIL_PROVIDER' ) ) {
			$constant_provider = sanitize_key( (string) constant( 'WP_POWERSUITE_MAIL_PROVIDER' ) );
			if ( in_array( $constant_provider, ProviderRegistry::ids(), true ) ) {
				$provider = $constant_provider;
			}
		}
		$settings['provider'] = $provider;

		$settings['smtp_host'] = SmtpSettingsHelper::sanitizeHost(
			CredentialManager::is_from_constant( 'WP_POWERSUITE_SMTP_HOST' )
				? (string) constant( 'WP_POWERSUITE_SMTP_HOST' )
				: (string) ( $settings['smtp_host'] ?? '' )
		);

		$port = CredentialManager::is_from_constant( 'WP_POWERSUITE_SMTP_PORT' )
			? (int) constant( 'WP_POWERSUITE_SMTP_PORT' )
			: (int) ( $settings['smtp_port'] ?? 587 );
		$settings['smtp_port'] = (string) max( 1, min( 65535, $port > 0 ? $port : 587 ) );

		$encryption = sanitize_key( (string) ( $settings['smtp_encryption'] ?? 'tls' ) );
		$settings['smtp_encryption'] = in_array( $encryption, [ 'tls', 'ssl', 'none', '' ], true )
			? ( $encryption === 'none' ? '' : $encryption )
			: 'tls';

		$settings['smtp_auth'] = self::bool_flag( $settings['smtp_auth'] ?? '1' );
		$settings['smtp_username'] = sanitize_text_field(
			CredentialManager::is_from_constant( 'WP_POWERSUITE_SMTP_USERNAME' )
				? (string) constant( 'WP_POWERSUITE_SMTP_USERNAME' )
				: (string) ( $settings['smtp_username'] ?? '' )
		);

		$settings['smtp_autotls'] = self::bool_flag( $settings['smtp_autotls'] ?? '1' );
		$settings['smtp_allow_self_signed'] = self::bool_flag( $settings['smtp_allow_self_signed'] ?? '0' );
		$settings['smtp_timeout'] = (string) max( 5, min( 120, (int) ( $settings['smtp_timeout'] ?? 30 ) ) );

		$settings['override_from']    = self::bool_flag( $settings['override_from'] ?? '1' );
		$settings['force_from_email'] = self::bool_flag( $settings['force_from_email'] ?? $settings['override_from'] );
		$settings['force_from_name']  = self::bool_flag( $settings['force_from_name'] ?? $settings['override_from'] );
		$settings['set_return_path']  = self::bool_flag( $settings['set_return_path'] ?? '1' );

		$from_email = sanitize_email( (string) ( $settings['from_email'] ?? '' ) );
		$settings['from_email'] = is_email( $from_email ) ? $from_email : sanitize_email( (string) get_option( 'admin_email' ) );
		$settings['from_name']  = SmtpSettingsHelper::sanitizeFromName( (string) ( $settings['from_name'] ?? '' ) );

		$reply = sanitize_email( (string) ( $settings['reply_to_email'] ?? '' ) );
		$settings['reply_to_email'] = is_email( $reply ) ? $reply : '';
		$settings['reply_to_name']  = SmtpSettingsHelper::sanitizeFromName( (string) ( $settings['reply_to_name'] ?? '' ) );

		$return_path = sanitize_email( (string) ( $settings['return_path'] ?? '' ) );
		$settings['return_path'] = is_email( $return_path ) ? $return_path : '';

		$content_type = sanitize_text_field( (string) ( $settings['default_content_type'] ?? 'text/html' ) );
		$settings['default_content_type'] = in_array( $content_type, [ 'text/plain', 'text/html' ], true ) ? $content_type : 'text/html';
		$settings['default_charset'] = sanitize_text_field( (string) ( $settings['default_charset'] ?? 'UTF-8' ) ) ?: 'UTF-8';

		$settings['smtp_debug'] = in_array( (string) ( $settings['smtp_debug'] ?? '0' ), [ '0', '1', '2' ], true )
			? (string) $settings['smtp_debug']
			: '0';

		$settings['sendgrid_region'] = in_array( sanitize_key( (string) ( $settings['sendgrid_region'] ?? 'global' ) ), [ 'global', 'eu' ], true )
			? sanitize_key( (string) $settings['sendgrid_region'] )
			: 'global';
		$settings['mailgun_region'] = in_array( sanitize_key( (string) ( $settings['mailgun_region'] ?? 'us' ) ), [ 'us', 'eu' ], true )
			? sanitize_key( (string) $settings['mailgun_region'] )
			: 'us';
		$settings['sparkpost_region'] = in_array( sanitize_key( (string) ( $settings['sparkpost_region'] ?? 'us' ) ), [ 'us', 'eu' ], true )
			? sanitize_key( (string) $settings['sparkpost_region'] )
			: 'us';
		$settings['netcore_region'] = in_array( sanitize_key( (string) ( $settings['netcore_region'] ?? 'us' ) ), [ 'us', 'eu' ], true )
			? sanitize_key( (string) $settings['netcore_region'] )
			: 'us';
		$settings['turbo_smtp_region'] = in_array( sanitize_key( (string) ( $settings['turbo_smtp_region'] ?? 'us' ) ), [ 'us', 'eu' ], true )
			? sanitize_key( (string) $settings['turbo_smtp_region'] )
			: 'us';
		$settings['smtp2go_region'] = in_array( sanitize_key( (string) ( $settings['smtp2go_region'] ?? 'global' ) ), [ 'global', 'us', 'eu', 'au' ], true )
			? sanitize_key( (string) $settings['smtp2go_region'] )
			: 'global';
		$settings['mailgun_domain'] = SmtpSettingsHelper::sanitizeHost( (string) ( $settings['mailgun_domain'] ?? '' ) );
		$settings['postmark_message_stream'] = sanitize_text_field( (string) ( $settings['postmark_message_stream'] ?? 'outbound' ) ) ?: 'outbound';
		$settings['smtpcom_channel'] = sanitize_text_field( (string) ( $settings['smtpcom_channel'] ?? '' ) );

		$aws_region = sanitize_key(
			CredentialManager::is_from_constant( 'WP_POWERSUITE_AWS_REGION' )
				? (string) constant( 'WP_POWERSUITE_AWS_REGION' )
				: (string) ( $settings['aws_region'] ?? 'us-east-1' )
		);
		$settings['aws_region'] = preg_match( '/^[a-z0-9-]+$/', $aws_region ) ? $aws_region : 'us-east-1';
		$settings['aws_configuration_set'] = sanitize_text_field( (string) ( $settings['aws_configuration_set'] ?? '' ) );
		$settings['aws_credential_source'] = in_array( sanitize_key( (string) ( $settings['aws_credential_source'] ?? 'keys' ) ), [ 'keys', 'env' ], true )
			? sanitize_key( (string) $settings['aws_credential_source'] )
			: 'keys';

		$settings['google_client_id'] = sanitize_text_field(
			CredentialManager::is_from_constant( 'WP_POWERSUITE_GOOGLE_CLIENT_ID' )
				? (string) constant( 'WP_POWERSUITE_GOOGLE_CLIENT_ID' )
				: (string) ( $settings['google_client_id'] ?? '' )
		);
		$settings['microsoft_client_id'] = sanitize_text_field(
			CredentialManager::is_from_constant( 'WP_POWERSUITE_MICROSOFT_CLIENT_ID' )
				? (string) constant( 'WP_POWERSUITE_MICROSOFT_CLIENT_ID' )
				: (string) ( $settings['microsoft_client_id'] ?? '' )
		);
		$tenant = sanitize_text_field( (string) ( $settings['microsoft_tenant'] ?? 'common' ) );
		$settings['microsoft_tenant'] = preg_match( '/^[a-zA-Z0-9._-]+$/', $tenant ) ? $tenant : 'common';
		$settings['google_connected_email'] = is_email( (string) ( $settings['google_connected_email'] ?? '' ) )
			? sanitize_email( (string) $settings['google_connected_email'] )
			: '';
		$settings['microsoft_connected_email'] = is_email( (string) ( $settings['microsoft_connected_email'] ?? '' ) )
			? sanitize_email( (string) $settings['microsoft_connected_email'] )
			: '';
		$settings['google_token_expires']    = (string) max( 0, (int) ( $settings['google_token_expires'] ?? 0 ) );
		$settings['microsoft_token_expires'] = (string) max( 0, (int) ( $settings['microsoft_token_expires'] ?? 0 ) );

		$settings['fallback_enabled'] = self::bool_flag( $settings['fallback_enabled'] ?? '0' );
		$fallback_provider = sanitize_key( (string) ( $settings['fallback_provider'] ?? '' ) );
		if ( $fallback_provider !== '' && ! in_array( $fallback_provider, ProviderRegistry::ids(), true ) ) {
			$fallback_provider = '';
		}
		if ( $fallback_provider === 'wordpress' || $fallback_provider === (string) ( $settings['provider'] ?? '' ) ) {
			$fallback_provider = '';
		}
		$settings['fallback_provider'] = $fallback_provider;
		$settings['fallback_on'] = in_array( sanitize_key( (string) ( $settings['fallback_on'] ?? 'retry_safe' ) ), [ 'retry_safe', 'always' ], true )
			? sanitize_key( (string) $settings['fallback_on'] )
			: 'retry_safe';
		$settings['retry_max_attempts'] = (string) max( 0, min( 2, (int) ( $settings['retry_max_attempts'] ?? 0 ) ) );
		$settings['webhook_enabled'] = self::bool_flag( $settings['webhook_enabled'] ?? '0' );
		$settings['webhook_sendgrid_verification_key'] = sanitize_textarea_field( (string) ( $settings['webhook_sendgrid_verification_key'] ?? '' ) );
		$settings['failure_alert_enabled'] = self::bool_flag( $settings['failure_alert_enabled'] ?? '0' );
		$alert_email = sanitize_email( (string) ( $settings['failure_alert_email'] ?? '' ) );
		$settings['failure_alert_email'] = is_email( $alert_email ) ? $alert_email : '';
		$webhook = esc_url_raw( trim( (string) ( $settings['failure_alert_webhook'] ?? '' ) ) );
		$settings['failure_alert_webhook'] = ( $webhook !== '' && FailureNotifier::is_allowed_webhook_url( $webhook ) ) ? $webhook : '';
		$settings['auto_retry_failed'] = self::bool_flag( $settings['auto_retry_failed'] ?? '0' );
		$settings['simulation_mode']   = self::bool_flag( $settings['simulation_mode'] ?? '0' );

		// Ensure secret keys exist as strings.
		foreach ( CredentialManager::secret_keys() as $secret_key ) {
			if ( ! isset( $settings[ $secret_key ] ) ) {
				$settings[ $secret_key ] = '';
			}
		}

		$before_version = (int) ( $settings['migration_version'] ?? 0 );
		$settings       = ConnectionStore::ensure( $settings );

		$settings['migration_version'] = max( $before_version, self::MIGRATION_VERSION );
		if ( $before_version < self::MIGRATION_VERSION ) {
			$settings['_migration_dirty'] = true;
		}

		return $settings;
	}

	/**
	 * Sanitize a stored provider ID without remapping unknowns to PHP Mail.
	 *
	 * Empty becomes wordpress (the install default). Unknown IDs are kept so
	 * the router can fail closed instead of silently using local mail.
	 */
	public static function sanitize_provider_id( string $raw ): string {
		$provider = sanitize_key( $raw );

		return $provider !== '' ? $provider : 'wordpress';
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return array<string, mixed>
	 */
	public static function sender_bag( array $settings ): array {
		return [
			'from_email'           => $settings['from_email'] ?? '',
			'from_name'            => $settings['from_name'] ?? '',
			'reply_to_email'       => $settings['reply_to_email'] ?? '',
			'reply_to_name'        => $settings['reply_to_name'] ?? '',
			'return_path'          => $settings['return_path'] ?? '',
			'set_return_path'      => $settings['set_return_path'] ?? '1',
			'override_from'        => $settings['override_from'] ?? '0',
			'force_from_email'     => $settings['force_from_email'] ?? '0',
			'force_from_name'      => $settings['force_from_name'] ?? '0',
			'default_content_type' => $settings['default_content_type'] ?? 'text/html',
			'default_charset'      => $settings['default_charset'] ?? 'UTF-8',
		];
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return array<string, mixed>
	 */
	public static function provider_bag( array $settings, string $provider_id ): array {
		switch ( $provider_id ) {
			case 'smtp':
				$password = (string) ( $settings['smtp_password'] ?? '' );
				if ( CredentialManager::is_from_constant( 'WP_POWERSUITE_SMTP_PASSWORD' ) ) {
					$password = CredentialManager::encrypt( (string) constant( 'WP_POWERSUITE_SMTP_PASSWORD' ) );
				}
				return [
					'smtp_host'              => $settings['smtp_host'] ?? '',
					'smtp_port'              => $settings['smtp_port'] ?? '587',
					'smtp_encryption'        => $settings['smtp_encryption'] ?? 'tls',
					'smtp_auth'              => $settings['smtp_auth'] ?? '1',
					'smtp_username'          => $settings['smtp_username'] ?? '',
					'smtp_password'          => $password,
					'smtp_autotls'           => $settings['smtp_autotls'] ?? '1',
					'smtp_timeout'           => $settings['smtp_timeout'] ?? '30',
					'smtp_allow_self_signed' => $settings['smtp_allow_self_signed'] ?? '0',
					'smtp_debug'             => $settings['smtp_debug'] ?? '0',
				];

			case 'sendgrid':
				return [
					'sendgrid_api_key' => $settings['sendgrid_api_key'] ?? '',
					'sendgrid_region'  => $settings['sendgrid_region'] ?? 'global',
				];

			case 'mailgun':
				return [
					'mailgun_api_key' => $settings['mailgun_api_key'] ?? '',
					'mailgun_domain'  => $settings['mailgun_domain'] ?? '',
					'mailgun_region'  => $settings['mailgun_region'] ?? 'us',
				];

			case 'brevo':
				return [ 'brevo_api_key' => $settings['brevo_api_key'] ?? '' ];

			case 'postmark':
				return [
					'postmark_server_token'   => $settings['postmark_server_token'] ?? '',
					'postmark_message_stream' => $settings['postmark_message_stream'] ?? 'outbound',
				];

			case 'mailersend':
				return [ 'mailersend_api_token' => $settings['mailersend_api_token'] ?? '' ];

			case 'resend':
				return [ 'resend_api_key' => $settings['resend_api_key'] ?? '' ];

			case 'sparkpost':
				return [
					'sparkpost_api_key' => $settings['sparkpost_api_key'] ?? '',
					'sparkpost_region'  => $settings['sparkpost_region'] ?? 'us',
				];

			case 'elastic-email':
				return [ 'elastic_email_api_key' => $settings['elastic_email_api_key'] ?? '' ];

			case 'smtp2go':
				return [
					'smtp2go_api_key' => $settings['smtp2go_api_key'] ?? '',
					'smtp2go_region'  => $settings['smtp2go_region'] ?? 'global',
				];

			case 'mailjet':
				return [
					'mailjet_api_key'    => $settings['mailjet_api_key'] ?? '',
					'mailjet_secret_key' => $settings['mailjet_secret_key'] ?? '',
				];

			case 'netcore':
				return [
					'netcore_api_key' => $settings['netcore_api_key'] ?? '',
					'netcore_region'  => $settings['netcore_region'] ?? 'us',
				];

			case 'mandrill':
				return [ 'mandrill_api_key' => $settings['mandrill_api_key'] ?? '' ];

			case 'emailit':
				return [ 'emailit_api_key' => $settings['emailit_api_key'] ?? '' ];

			case 'sendlayer':
				return [ 'sendlayer_api_key' => $settings['sendlayer_api_key'] ?? '' ];

			case 'smtpcom':
				return [
					'smtpcom_api_key' => $settings['smtpcom_api_key'] ?? '',
					'smtpcom_channel' => $settings['smtpcom_channel'] ?? '',
				];

			case 'maileroo':
				return [ 'maileroo_api_key' => $settings['maileroo_api_key'] ?? '' ];

			case 'turbo-smtp':
				return [
					'turbo_smtp_consumer_key'    => $settings['turbo_smtp_consumer_key'] ?? '',
					'turbo_smtp_consumer_secret' => $settings['turbo_smtp_consumer_secret'] ?? '',
					'turbo_smtp_region'          => $settings['turbo_smtp_region'] ?? 'us',
				];

			case 'mail-baby':
				return [ 'mail_baby_api_key' => $settings['mail_baby_api_key'] ?? '' ];

			case 'amazon-ses':
				return [
					'aws_access_key_id'       => $settings['aws_access_key_id'] ?? '',
					'aws_secret_access_key'   => $settings['aws_secret_access_key'] ?? '',
					'aws_region'              => $settings['aws_region'] ?? 'us-east-1',
					'aws_configuration_set'   => $settings['aws_configuration_set'] ?? '',
					'aws_credential_source'   => $settings['aws_credential_source'] ?? 'keys',
				];

			case 'google':
				return [
					'google_client_id'       => $settings['google_client_id'] ?? '',
					'google_client_secret'   => $settings['google_client_secret'] ?? '',
					'google_access_token'    => $settings['google_access_token'] ?? '',
					'google_refresh_token'   => $settings['google_refresh_token'] ?? '',
					'google_token_expires'   => $settings['google_token_expires'] ?? '0',
					'google_connected_email' => $settings['google_connected_email'] ?? '',
				];

			case 'microsoft':
				return [
					'microsoft_client_id'       => $settings['microsoft_client_id'] ?? '',
					'microsoft_client_secret'   => $settings['microsoft_client_secret'] ?? '',
					'microsoft_tenant'          => $settings['microsoft_tenant'] ?? 'common',
					'microsoft_access_token'    => $settings['microsoft_access_token'] ?? '',
					'microsoft_refresh_token'   => $settings['microsoft_refresh_token'] ?? '',
					'microsoft_token_expires'   => $settings['microsoft_token_expires'] ?? '0',
					'microsoft_connected_email' => $settings['microsoft_connected_email'] ?? '',
				];

			default:
				return [];
		}
	}

	/**
	 * @param mixed $value
	 */
	private static function bool_flag( $value ): string {
		return ! empty( $value ) && (string) $value !== '0' ? '1' : '0';
	}
}
