<?php

class HappyForms_Message_Blocklist {

	private static $instance;
	private static $hooked = false;

	public $save_action = 'happyforms_save_message_blocklist';
	public $save_nonce = 'happyforms-validation-message-blocklist';
	public $option = 'happyforms_blocklist';

	public static function instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}

		self::$instance->hook();

		return self::$instance;
	}

	public function hook() {
		if ( self::$hooked ) {
			return;
		}

		self::$hooked = true;

		add_action( 'wp_ajax_' . $this->save_action, array( $this, 'save_settings' ) );
	}

	public function get_defaults() {
		$defaults = array(
			'block_language' => 0,
			'language' => '',
			'block_emails' => 0,
			'emails' => '',
		);

		return $defaults;
	}

	public function read( $as_array = false ) {
		$blocklist = get_option( $this->option, '' );
		$blocklist = wp_parse_args( $blocklist, $this->get_defaults() );
		$blocklist = array_map( 'wp_unslash', $blocklist );

		if ( $as_array ) {
			$blocklist['language'] = explode( "\n", $blocklist['language'] );
			$blocklist['emails'] = explode( "\n", $blocklist['emails'] );
			$blocklist['language'] = array_filter( $blocklist['language'] );
			$blocklist['emails'] = array_filter( $blocklist['emails'] );
		}

		return $blocklist;
	}

	public function write( $blocklist ) {
		$defaults = $this->get_defaults();
		$blocklist = array_intersect_key( $blocklist, $defaults );
		$blocklist = wp_parse_args( $blocklist, $defaults );
		$blocklist['emails'] = $this->sanitize_email_keys( $blocklist['emails'] );
		$blocklist['language'] = $this->sanitize_language_keys( $blocklist['language'] );

		update_option( $this->option, $blocklist );
	}

	public function sanitize_email_keys( $emails ) {
		$lines = explode( "\n", $emails );
		$lines = array_map( 'trim', $lines );
		$lines = array_filter( $lines, function( $line ) {
			return ( ! preg_match( '/\s/', $line ) );
		} );
		$lines = array_filter( $lines );
		$emails = implode( "\n", $lines );

		return $emails;
	}

	public function sanitize_language_keys( $language ) {
		$lines = explode( "\n", $language );
		$lines = array_map( 'trim', $lines );
		$lines = array_filter( $lines, function( $line ) {
			return ( ! preg_match( '/[^\p{L} ]/u', $line ) );
		} );
		$lines = array_map( function( $line ) {
			$line = preg_replace( '/\s+/u', ' ', $line );
			return $line;
		}, $lines );
		$lines = array_filter( $lines );
		$language = implode( "\n", $lines );

		return $language;
	}

	public function save_settings() {
		if ( ! check_ajax_referer( $this->save_action, $this->save_nonce ) ) {
			return;
		}

		$blocklist = isset( $_REQUEST['blocklist'] ) ? $_REQUEST['blocklist'] : array();
		$this->write( $blocklist );

		ob_start();
		require_once( happyforms_get_include_folder() . '/templates/admin-settings-blocklist.php' );
		$response = ob_get_clean();

		wp_send_json_success( array(
			'html' => $response,
			'message' => __( 'Changes saved.', 'happyforms' ),
		) );
	}

	public function includes_payment( $form, $request ) {
		$payment_part = happyforms_get_form_controller()->get_first_part_by_type( $form, 'payments' );

		if ( ! $payment_part ) {
			return;
		}

		$payment_part_id = $payment_part['id'];
		$payment_part_name = happyforms_get_part_name( $payment_part, $form );
		$payment_part_value = $request[$payment_part_name];
		$price = isset( $payment_part_value['price'] ) ? $payment_part_value['price'] : '';
		$price = floatval( $price );
		$includes_payment = $price > 0;

		return $includes_payment;
	}

	public function check_value_email( $value, $keys ) {
		$value = trim( $value );

		foreach( $keys as $key ) {
			$key = preg_quote( $key, '#' );
			$pattern = "#$key#i";
			
			if ( preg_match( $pattern, $value ) ) {
				return true;
			}
		}

		return false;
	}

	public function check_value_text( $value, $keys ) {
		$values = is_array( $value ) ? $value : array( $value );

		$values = array_map( function( $value ) {
			$value = preg_replace( '/<[^>]*>/u', ' ', $value );
			$value = preg_replace( '/[^\p{L} ]/u', '', $value );
			$value = preg_replace( '/\s+/u', ' ', $value );
			$value = trim( $value );

			return $value;
		}, $values );
		$values = array_filter( $values );
		
		foreach( $keys as $key ) {
			foreach( $values as $value ) {
				$pattern = '/\b' . $key . '\b/miu';
				
				if ( preg_match( $pattern, $value ) ) {
					return true;
				}
			}
		}

		return false;
	}

	public function check_value( $part, $form, $message, $blocklist ) {
		$part_id = $part['id'];
		$part_type = $part['type'];

		if ( ! isset( $message['parts'][$part_id] ) ) {
			return false;
		}

		switch( $part_type ) {
			case 'email':
				return $this->check_value_email( $message['parts'][$part_id], $blocklist['emails'] );
				break;
			case 'single_line_text':
			case 'multi_line_text':
			case 'rich_text':
				return $this->check_value_text( $message['parts'][$part_id], $blocklist['language'] );
				break;
			case 'narrative':
				$part_name = happyforms_get_part_name( $part, $form );
				return $this->check_value_text( $message['request'][$part_name], $blocklist['language'] );
				break;
			case 'signature':
				$part_name = happyforms_get_part_name( $part, $form );
				return $this->check_value_text( $message['request'][$part_name]['signature'], $blocklist['language'] );
				break;
			case 'radio':
				if ( $part['other_option'] ) {
					$part_name = happyforms_get_part_name( $part, $form );
					$part_value = $message['request'][$part_name];
					return $this->check_value_text( $part_value[1], $blocklist['language'] );
				}
			case 'checkbox':
				if ( $part['other_option'] ) {
					$part_name = happyforms_get_part_name( $part, $form );
					$part_value = $message['request'][$part_name];
					$part_value = is_array( $part_value ) ? end( $part_value ) : $part_value;
					return $this->check_value_text( $part_value[1], $blocklist['language'] );
				}
				
				break;
		}
	}

	public function check_message( $message, $form, $request ) {
		$is_spam = false;

		if ( $this->includes_payment( $form, $request ) ) {
			return $is_spam;
		}

		$blocklist = $this->read( true );

		if ( empty( $blocklist['language'] ) && empty( $blocklist['emails'] ) ) {
			return $is_spam;
		}

		foreach( $form['parts'] as $part ) {
			$is_spam = $this->check_value( $part, $form, $message, $blocklist );

			if ( $is_spam ) {
				break;
			}
		}

		if ( $is_spam ) {
			happyforms_update_meta( $message['ID'], 'read', 2 );
			happyforms_get_message_controller()->update_counters();
		}

		return $is_spam;
	}

}

if ( ! function_exists( 'happyforms_get_message_blocklist' ) ):

function happyforms_get_message_blocklist() {
	return HappyForms_Message_Blocklist::instance();
}

endif;

happyforms_get_message_blocklist();
