<?php
/**
 * WP System Email Handler - Port from Fluent Security
 *
 * @package CustomWpEmails
 */

namespace CustomWpEmails\Includes;

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

class WPSystemEmailHandler {

	private string $temp_email_subject = '';

	private bool $pending_admin_email_headers = false;

	public function register(): void {
		add_filter( 'wp_new_user_notification_email_admin', [ $this, 'maybe_alter_user_registration_admin' ], 99, 3 );
		add_filter( 'wp_new_user_notification_email', [ $this, 'maybe_alter_user_registration_email' ], 99, 3 );
		add_filter( 'retrieve_password_notification_email', [ $this, 'maybe_alter_password_reset_email' ], 99, 4 );
		add_filter( 'new_user_email_content', [ $this, 'maybe_alter_email_change_confirmation' ], 99, 2 );
		add_filter( 'email_change_email', [ $this, 'maybe_alter_email_changed' ], 99, 3 );
		add_filter( 'wp_send_new_user_notification_to_admin', [ $this, 'maybe_disable_admin_email' ], 10, 2 );
		add_filter( 'wp_password_change_notification_email', [ $this, 'maybe_alter_password_change_notification' ], 99, 3 );
		add_filter( 'comment_notification_text', [ $this, 'maybe_alter_comment_notification' ], 99, 2 );
		add_filter( 'comment_notification_subject', [ $this, 'maybe_alter_comment_notification_subject' ], 99, 2 );
		add_filter( 'comment_notification_headers', [ $this, 'maybe_alter_comment_notification_headers' ], 99, 2 );
		add_filter( 'comment_moderation_text', [ $this, 'maybe_alter_comment_moderation' ], 99, 2 );
		add_filter( 'comment_moderation_subject', [ $this, 'maybe_alter_comment_moderation_subject' ], 99, 2 );
		add_filter( 'comment_moderation_headers', [ $this, 'maybe_alter_comment_moderation_headers' ], 99, 2 );
		add_filter( 'new_admin_email_content', [ $this, 'maybe_alter_admin_email_change_content' ], 99, 2 );
		add_filter( 'new_admin_email_subject', [ $this, 'maybe_alter_admin_email_change_subject' ], 99, 1 );
		add_filter( 'notify_post_author', [ $this, 'maybe_disable_comment_notification' ], 10, 2 );
		add_filter( 'notify_moderator', [ $this, 'maybe_disable_comment_moderation' ], 10, 2 );
		add_action( 'init', [ $this, 'maybe_remove_password_change_notification' ], 5 );
	}

	public function maybe_disable_admin_email( bool $send, \WP_User $user ): bool {
		$setting = SystemEmailService::get_email_settings_by_type( 'user_registration_to_admin' );
		return ( $setting['status'] ?? '' ) === 'disabled' ? false : $send;
	}

	public function maybe_disable_comment_notification( bool $maybe_notify, string $comment_id ): bool {
		$setting = SystemEmailService::get_email_settings_by_type( 'comment_notification_to_author' );
		return ( $setting['status'] ?? '' ) === 'disabled' ? false : $maybe_notify;
	}

	public function maybe_disable_comment_moderation( bool $maybe_notify, int $comment_id ): bool {
		$setting = SystemEmailService::get_email_settings_by_type( 'comment_moderation_to_admin' );
		return ( $setting['status'] ?? '' ) === 'disabled' ? false : $maybe_notify;
	}

	public function maybe_alter_email_change_subject( array $atts ): array {
		if ( empty( $this->temp_email_subject ) ) {
			return $atts;
		}
		$atts['subject'] = $this->temp_email_subject;
		$atts['headers'] = SystemEmailService::build_mail_headers( $atts['headers'] ?? [] );
		$this->temp_email_subject = '';
		remove_filter( 'wp_mail', [ $this, 'maybe_alter_email_change_subject' ], 99 );
		return $atts;
	}

	/** @param array{to?:string,subject?:string,message?:string,headers?:string|array} $defaults */
	public function maybe_alter_password_reset_email( array $defaults, string $key, string $user_login, $user_data ): array {
		$setting = SystemEmailService::get_email_settings_by_type( 'password_reset_to_user' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $defaults;
		}
		$user_data->_password_reset_key_ = $key;
		$email  = $setting['email'] ?? [];
		$parser = new SmartCodeParser();
		$defaults['subject'] = $parser->parse(
			SystemEmailService::resolve_email_field( $email, 'subject', (string) ( $defaults['subject'] ?? '' ) ),
			$user_data
		);
		$defaults['message'] = SystemEmailService::with_html_template(
			$parser->parse(
				SystemEmailService::resolve_email_field( $email, 'body', (string) ( $defaults['message'] ?? '' ) ),
				$user_data
			),
			null,
			$user_data
		);
		$defaults['headers'] = SystemEmailService::build_mail_headers( $defaults['headers'] ?? [] );
		return $defaults;
	}

	/** @param array<string, mixed> $defaults */
	public function maybe_alter_user_registration_email( array $defaults, \WP_User $user, string $blogname ): array {
		$setting = SystemEmailService::get_email_settings_by_type( 'user_registration_to_user' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $defaults;
		}
		$key = get_password_reset_key( $user );
		if ( is_wp_error( $key ) ) {
			return $defaults;
		}
		$user->_password_reset_key_ = $key;
		$email  = $setting['email'] ?? [];
		$parser = new SmartCodeParser();
		$defaults['subject'] = $parser->parse(
			SystemEmailService::resolve_email_field( $email, 'subject', (string) ( $defaults['subject'] ?? '' ) ),
			$user
		);
		$defaults['message'] = SystemEmailService::with_html_template(
			$parser->parse(
				SystemEmailService::resolve_email_field( $email, 'body', (string) ( $defaults['message'] ?? '' ) ),
				$user
			),
			null,
			$user
		);
		$defaults['headers'] = SystemEmailService::build_mail_headers( $defaults['headers'] ?? [] );
		return $defaults;
	}

	/** @param array<string, mixed> $defaults */
	public function maybe_alter_user_registration_admin( array $defaults, \WP_User $user, string $blogname ): array {
		$setting = SystemEmailService::get_email_settings_by_type( 'user_registration_to_admin' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $defaults;
		}
		$email  = $setting['email'] ?? [];
		$parser = new SmartCodeParser();
		$defaults['subject'] = $parser->parse(
			SystemEmailService::resolve_email_field( $email, 'subject', (string) ( $defaults['subject'] ?? '' ) ),
			$user
		);
		$defaults['message'] = SystemEmailService::with_html_template(
			$parser->parse(
				SystemEmailService::resolve_email_field( $email, 'body', (string) ( $defaults['message'] ?? '' ) ),
				$user
			),
			null,
			$user
		);
		$defaults['headers'] = SystemEmailService::build_mail_headers( $defaults['headers'] ?? [] );
		return $defaults;
	}

	public function maybe_alter_email_change_confirmation( string $email_body, $new_user_email ): string {
		$setting = SystemEmailService::get_email_settings_by_type( 'email_change_notification_to_user' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $email_body;
		}
		$user = wp_get_current_user();
		if ( ! $user || ! $user->ID ) {
			return $email_body;
		}
		$email    = $setting['email'] ?? [];
		$defaults = SystemEmailService::get_email_defaults()['email_change_notification_to_user']['email'] ?? [];
		$parser   = new SmartCodeParser();
		$subject  = $parser->parse(
			SystemEmailService::resolve_email_field( $email, 'subject', (string) ( $defaults['subject'] ?? '' ) ),
			$user
		);
		$this->temp_email_subject = $subject;
		add_filter( 'wp_mail', [ $this, 'maybe_alter_email_change_subject' ], 99, 1 );
		$body = $parser->parse(
			SystemEmailService::resolve_email_field( $email, 'body', (string) ( $defaults['body'] ?? $email_body ) ),
			$user
		);
		return SystemEmailService::with_html_template( $body, null, $user );
	}

	/** @param array<string, mixed> $defaults */
	public function maybe_alter_email_changed( array $defaults, array $old_user_data, array $updated_user_data ): array {
		$setting = SystemEmailService::get_email_settings_by_type( 'email_change_notification_after_confimation' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $defaults;
		}
		$user_obj = new \WP_User( $old_user_data['ID'] ?? 0 );
		$user_obj->_previous_email_address_ = $old_user_data['user_email'] ?? '';
		$email  = $setting['email'] ?? [];
		$parser = new SmartCodeParser();
		$defaults['subject'] = $parser->parse(
			SystemEmailService::resolve_email_field( $email, 'subject', (string) ( $defaults['subject'] ?? '' ) ),
			$user_obj
		);
		$defaults['message'] = SystemEmailService::with_html_template(
			$parser->parse(
				SystemEmailService::resolve_email_field( $email, 'body', (string) ( $defaults['message'] ?? '' ) ),
				$user_obj
			),
			null,
			$user_obj
		);
		$defaults['headers'] = SystemEmailService::build_mail_headers( $defaults['headers'] ?? [] );
		return $defaults;
	}

	public function maybe_remove_password_change_notification(): void {
		$setting = SystemEmailService::get_email_settings_by_type( 'password_change_to_admin' );
		if ( ( $setting['status'] ?? '' ) === 'disabled' ) {
			remove_action( 'after_password_reset', 'wp_password_change_notification' );
		}
	}

	/** @param array{to?:string,subject?:string,message?:string,headers?:string} $email */
	public function maybe_alter_password_change_notification( array $email, \WP_User $user, string $blogname ): array {
		$setting = SystemEmailService::get_email_settings_by_type( 'password_change_to_admin' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $email;
		}
		$email_config = $setting['email'] ?? [];
		$defaults     = SystemEmailService::get_email_defaults()['password_change_to_admin']['email'] ?? [];
		$parser       = new SmartCodeParser();
		$email['subject'] = $parser->parse(
			SystemEmailService::resolve_email_field( $email_config, 'subject', (string) ( $defaults['subject'] ?? '[{{site.name}}] Password Changed' ) ),
			$user
		);
		$body = $parser->parse(
			SystemEmailService::resolve_email_field( $email_config, 'body', (string) ( $defaults['body'] ?? '' ) ),
			$user
		);
		$email['message'] = SystemEmailService::with_html_template( $body, null, $user );
		$email['headers'] = SystemEmailService::build_mail_headers( $email['headers'] ?? [] );
		return $email;
	}

	public function maybe_alter_comment_notification( string $notify_message, string $comment_id ): string {
		$setting = SystemEmailService::get_email_settings_by_type( 'comment_notification_to_author' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $notify_message;
		}
		$comment = get_comment( $comment_id );
		if ( ! $comment ) {
			return $notify_message;
		}
		$post = get_post( $comment->comment_post_ID );
		$user = $post ? get_user_by( 'id', $post->post_author ) : null;
		$body = $this->build_comment_body( $setting, $notify_message, $user );
		return SystemEmailService::with_html_template( $body, null, $user );
	}

	public function maybe_alter_comment_notification_subject( string $subject, string $comment_id ): string {
		$setting = SystemEmailService::get_email_settings_by_type( 'comment_notification_to_author' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $subject;
		}
		$comment = get_comment( $comment_id );
		$post    = $comment ? get_post( $comment->comment_post_ID ) : null;
		$user    = $post ? get_user_by( 'id', $post->post_author ) : null;
		return $this->resolve_comment_subject( $setting, $subject, $user );
	}

	public function maybe_alter_comment_notification_headers( string $headers, string $comment_id ): string {
		$setting = SystemEmailService::get_email_settings_by_type( 'comment_notification_to_author' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $headers;
		}
		return implode( "\n", SystemEmailService::build_mail_headers( $headers ) );
	}

	public function maybe_alter_comment_moderation( string $notify_message, int $comment_id ): string {
		$setting = SystemEmailService::get_email_settings_by_type( 'comment_moderation_to_admin' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $notify_message;
		}
		$body = $this->build_comment_body( $setting, $notify_message, null );
		return SystemEmailService::with_html_template( $body, null, null );
	}

	public function maybe_alter_comment_moderation_subject( string $subject, int $comment_id ): string {
		$setting = SystemEmailService::get_email_settings_by_type( 'comment_moderation_to_admin' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $subject;
		}
		return $this->resolve_comment_subject( $setting, $subject, null );
	}

	public function maybe_alter_comment_moderation_headers( string $headers, int $comment_id ): string {
		$setting = SystemEmailService::get_email_settings_by_type( 'comment_moderation_to_admin' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $headers;
		}
		return implode( "\n", SystemEmailService::build_mail_headers( $headers ) );
	}

	public function maybe_alter_admin_email_change_content( string $email_text, array $new_admin_email ): string {
		$setting = SystemEmailService::get_email_settings_by_type( 'admin_email_change_confirmation' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $email_text;
		}
		$defaults = SystemEmailService::get_email_defaults()['admin_email_change_confirmation']['email'] ?? [];
		$body     = SystemEmailService::resolve_email_field(
			$setting['email'] ?? [],
			'body',
			(string) ( $defaults['body'] ?? $email_text )
		);
		if ( $body === '' ) {
			return $email_text;
		}
		$user = wp_get_current_user();
		$body = ( new SmartCodeParser() )->parse( $body, $user );
		$this->pending_admin_email_headers = true;
		add_filter( 'wp_mail', [ $this, 'maybe_add_admin_email_change_headers' ], 99, 1 );
		return SystemEmailService::with_html_template( $body, null, $user );
	}

	public function maybe_alter_admin_email_change_subject( string $subject ): string {
		$setting = SystemEmailService::get_email_settings_by_type( 'admin_email_change_confirmation' );
		if ( ( $setting['status'] ?? '' ) !== 'active' ) {
			return $subject;
		}
		$defaults = SystemEmailService::get_email_defaults()['admin_email_change_confirmation']['email'] ?? [];
		$custom   = SystemEmailService::resolve_email_field( $setting['email'] ?? [], 'subject', (string) ( $defaults['subject'] ?? $subject ) );
		if ( $custom === $subject ) {
			return $subject;
		}
		return ( new SmartCodeParser() )->parse( $custom, wp_get_current_user() );
	}

	/** @param array{to?:mixed,subject?:string,message?:string,headers?:string|array} $atts */
	public function maybe_add_admin_email_change_headers( array $atts ): array {
		if ( ! $this->pending_admin_email_headers ) {
			return $atts;
		}
		$this->pending_admin_email_headers = false;
		remove_filter( 'wp_mail', [ $this, 'maybe_add_admin_email_change_headers' ], 99 );
		$atts['headers'] = SystemEmailService::build_mail_headers( $atts['headers'] ?? [] );
		return $atts;
	}

	/**
	 * Build comment email body from custom template or core message wrapper.
	 *
	 * @param array<string, mixed> $setting
	 * @param \WP_User|null        $user
	 */
	private function build_comment_body( array $setting, string $notify_message, $user ): string {
		$email_config = $setting['email'] ?? [];
		$custom_body  = trim( (string) ( $email_config['body'] ?? '' ) );
		$core_html    = '<div style="white-space:pre-wrap;font-family:inherit;">' . nl2br( esc_html( $notify_message ) ) . '</div>';

		if ( $custom_body === '' ) {
			return $core_html;
		}

		$body = str_replace(
			[ '##comment.message##', '{{comment.message}}' ],
			$core_html,
			$custom_body
		);
		return ( new SmartCodeParser() )->parse( $body, $user );
	}

	/**
	 * Resolve a customized comment subject with SmartCode support.
	 *
	 * @param array<string, mixed> $setting
	 * @param \WP_User|null        $user
	 */
	private function resolve_comment_subject( array $setting, string $fallback, $user ): string {
		$custom = trim( (string) ( $setting['email']['subject'] ?? '' ) );
		if ( $custom === '' ) {
			return $fallback;
		}
		return ( new SmartCodeParser() )->parse( $custom, $user );
	}
}
