<?php
if ( ! defined( 'ABSPATH' ) ) {
	die( 'You are not allowed to call this page directly.' );
}

class FormShieldForms {

	/**
	 * If auto-protection is on, get and protect all forms with HP
	 *
	 * @return Void
	 */
	public static function init() {

	}

	/**
	 * Save configuration to enable/disable forms to be protected with HP
	 *
	 * @param String $form_id - Form ID to enable/disable
	 * @param Integer $enabled - Boolean Int (1 === enabled)
	 * @param Boolean $unattended - If unattended, don't output HTML on enabling forms
	 *
	 * @return Void
	 */
	public static function enable_forms( $form_id, $enabled, $unattended = false ) {
		$options = FormShield::get_options();
		
				// Handle unprotect request or allow protection of unlimited forms
		if ( ! $enabled ) {
			// Disable form protection (don't remove it completely)
			if ( isset( $options['formshield_forms'][ $form_id ] ) ) {
				$options['formshield_forms'][ $form_id ]['form_enabled'] = 0;
				$alert_type = 'success';
			} else {
				$alert_type = 'error';
			}
		} else {
			// Add or enable form protection
			if ( ! isset( $options['formshield_forms'][ $form_id ] ) ) {
				// New form - try to determine type from detected forms
				$form_type = 'Unknown';
				$form_name = 'Form #' . $form_id;
				
				// Check if this form exists in detected_forms
				if (isset($options['detected_forms']) && is_array($options['detected_forms'])) {
					foreach ($options['detected_forms'] as $detected_form) {
						if ($detected_form['id'] === $form_id) {
							$form_type = $detected_form['type'];
							$form_name = $detected_form['name'];
							break;
						}
					}
				}
				
				// If still unknown, try to determine from form ID
				if ($form_type === 'Unknown') {
					if (strpos($form_id, 'cf7-') === 0) {
						$form_type = 'скенер';
					} elseif (strpos($form_id, 'ninja-') === 0) {
						$form_type = 'ninja_forms';
					} elseif (strpos($form_id, 'wpforms-') === 0) {
						$form_type = 'wpforms';
					} elseif (strpos($form_id, 'gravity_') === 0) {
						$form_type = 'gravityforms';
					} elseif (strpos($form_id, 'divi_') === 0) {
						$form_type = 'divi';
					} elseif (strpos($form_id, 'comments_') === 0) {
						$form_type = 'comments';
					}
				}
				
				$options['formshield_forms'][ $form_id ] = array(
					'form_enabled' => 1,
					'form_type'    => $form_type,
					'form_name'    => $form_name,
					'form_date'    => current_time( 'mysql' )
				);
			} else {
				// Existing form - enable it
				$options['formshield_forms'][ $form_id ]['form_enabled'] = 1;
			}
			$alert_type = 'success';
		}
		
		// Update options
		FormShield::update_options($options);
		
		// Show admin notice
		$current_action = $enabled ? 'enable' : 'disable';
		FormShieldUtils::show_wp_admin_notice( $current_action . 'd form #' . $form_id, 'notice-' . $alert_type . ' is-dismissible' );
	}

	/**
	 * Get a count of all protected forms
	 *
	 * @return Integer
	 */
	public static function get_protected_forms_ct() {
		$options            = form_shield()->get_options();
		$protected_forms_ct = 0;

		if ( isset( $options['formshield_forms'] ) && is_array( $options['formshield_forms'] ) ) {
			foreach ( $options['formshield_forms'] as $form ) {
				if ( ! empty( $form['form_enabled'] ) ) {
					$protected_forms_ct++;
				}
			}
		}

		return $protected_forms_ct;
	}

	/**
	 * Get form submissions count
	 *
	 * @param String $form_id - form id
	 * @param Integer $human_ct - Number of valid form entries
	 * @param Boolean $no_ct_tracked - When a form builder doesn't track submissions
	 *
	 * @return String (HTML)
	 */
	public static function get_form_submissions_ct( $form_id, $human_ct, $no_ct_tracked = false ) {
		$options = FormShield::get_options();
		if ( is_array( $options ) && array_key_exists( 'formshield_forms', $options ) ) {
			$recorded_human_ct   = $no_ct_tracked ? 'N/A' : $human_ct;
			$recorded_suspicious = 0;
			if ( isset( $options['formshield_forms'][ $form_id ]['suspicious_ct'] ) ) {
				$recorded_suspicious = ( null == $options['formshield_forms'][ $form_id ]['suspicious_ct'] ) ? 0 : $options['formshield_forms'][ $form_id ]['suspicious_ct'];
			}
			$recorded_total = $no_ct_tracked ? 'N/A' : ( $human_ct + $recorded_suspicious );

			return '<div class="label-row text-center row"><div class="col-lg-4"><span class="label label-success"><span class="fa fa-check"></span> <span>Human</span> <span class="badge">' . $recorded_human_ct . '</span></span></div><div class="col-lg-4"><span class="label label-danger"><span class="fa fa-exclamation-circle"></span> <span>Suspicious</span> <span class="badge">' . $recorded_suspicious . '</span></span></div><div class="col-lg-4"><span class="label label-default"><span class="fa fa-balance-scale"></span> <span>Total</span> <span class="badge">' . $recorded_total . '</span></span></div></div>';
		}
	}

	/**
	 * Get latest form activity
	 *
	 * @param String $form_id - form id
	 * @param String $last_entry - Date/Time string of the last human/valid form entry
	 *
	 * @return String
	 */
	public static function get_latest_form_activity( $form_id, $last_entry ) {
		$options = FormShield::get_options();
		if ( is_array( $options ) && array_key_exists( 'formshield_forms', $options ) ) {
			$last_suspicious_activity = isset( $options['formshield_forms'][ $form_id ]['last_suspicious_activity'] ) ? $options['formshield_forms'][ $form_id ]['last_suspicious_activity'] : null;
			if ( null != $last_suspicious_activity ) {
				if ( $last_suspicious_activity > $last_entry ) {
					// If suspicious activity is the latest
					return FormShieldUtils::time_ago( $last_suspicious_activity );
				} else {
					// Otherwise show the latest human activity
					return FormShieldUtils::time_ago( $last_entry );
				}
			} else {
				// Otherwise show the latest human activity if there is any
				return ( null != $last_entry ) ? FormShieldUtils::time_ago( $last_entry ) : 'never';
			}
		}
	}

	/**
	 * Build the table data for the forms.
	 *
	 * @return array
	 */
	public static function forms_list() {

		$forms_list = apply_filters( 'formshield_forms_list', array() );
		
		$options = FormShield::get_options();

		// Get a count of all initially protected forms
		if ( isset( $options['formshield_forms'] ) && ! array_key_exists( 'protected_forms_ct', $options ) ) {
			self::get_protected_forms_ct();
		}

		return $forms_list;
	}

	/**
	 * Check if a plugin is installed and active
	 *
	 * @param string $plugin_type
	 * @return bool
	 */
	private static function is_plugin_installed($plugin_type) {
		switch ($plugin_type) {
			case 'ninja_forms':
			case 'ninja-forms':
				return is_plugin_active('ninja-forms/ninja-forms.php');
			case 'скенер':
			case 'contact form 7':
			case 'contact-form-7':
			case 'wpcf7':
				return is_plugin_active('contact-form-7/wp-contact-form-7.php');
			case 'wpforms':
				return is_plugin_active('wpforms-lite/wpforms.php') || is_plugin_active('wpforms/wpforms.php');
			case 'gravityforms':
			case 'gravity-forms':
				return is_plugin_active('gravityforms/gravityforms.php');
			case 'comments':
			case 'wordpress-comments':
				return true; // WordPress comments are always available
			case 'divi':
			case 'divi-contact-form':
				return true; // Divi forms are part of Divi theme
			default:
				return true; // Default to true for unknown types
		}
	}

	/**
	 * Get all forms for the dashboard
	 *
	 * @return array
	 */
	public static function get_forms() {
		$forms = array();
		$options = FormShield::get_options();
		
		// Секция 1: Скенер (винаги включен)
		$scanner_id = 'frontend_detector';
		$scanner_blocked_attempts = 0;
		if (isset($options['formshield_forms'][$scanner_id]['blocked_attempts'])) {
			$scanner_blocked_attempts = intval($options['formshield_forms'][$scanner_id]['blocked_attempts']);
		}
		
		$forms['scanner'] = array(
			'id' => $scanner_id,
			'name' => __('Скенер на сайта', 'formshield'),
			'plugin' => 'FormShield Detector',
			'type' => 'скенер',
			'enabled' => 1, // Винаги включен
			'blocked_attempts' => $scanner_blocked_attempts,
			'page_id' => 0,
			'location' => 'FormShield Detection System',
			'is_scanner' => true // Маркер че това е скенер
		);
		
		// Секция 2: Коментари (винаги включени)
		$forms['comments'] = array();
		
		// Секция 3: Плъгини и форми (могат да се включват/изключват)
		$forms['plugins'] = array();
		
		// Прилагаме филтъра за интеграции (включително WordPress коментари)
		$integration_forms = apply_filters('formshield_forms_list', array());
		
		// Организираме формите по секции
		foreach ($integration_forms as $integration_form) {
			$form_type = $integration_form['type'];
			$form_id = isset($integration_form['id']) ? $integration_form['id'] : '';
			
			// Извличаме реалните blocked_attempts от опциите
			if (!empty($form_id) && isset($options['formshield_forms'][$form_id]['blocked_attempts'])) {
				$integration_form['blocked_attempts'] = intval($options['formshield_forms'][$form_id]['blocked_attempts']);
			} else {
				$integration_form['blocked_attempts'] = 0;
			}
			
			// Определяме в коя секция да добавим формата
			if (in_array($form_type, ['comments', 'wordpress-comments'])) {
				// Коментари - винаги включени
				$integration_form['enabled'] = 1;
				$integration_form['is_comments'] = true;
				$forms['comments'][] = $integration_form;
			} else {
				// Плъгини и форми - могат да се включват/изключват
				$forms['plugins'][] = $integration_form;
			}
		}
		
		// Ако няма коментари, добавяме поне един примерен
		if (empty($forms['comments'])) {
			$comments_id = 'wordpress_comments';
			$comments_blocked_attempts = 0;
			if (isset($options['formshield_forms'][$comments_id]['blocked_attempts'])) {
				$comments_blocked_attempts = intval($options['formshield_forms'][$comments_id]['blocked_attempts']);
			}
			
			$forms['comments'][] = array(
				'id' => $comments_id,
				'name' => 'WordPress Comments',
				'plugin' => 'WordPress Core',
				'type' => 'comments',
				'enabled' => 1, // Винаги включени
				'blocked_attempts' => $comments_blocked_attempts,
				'page_id' => 0,
				'location' => 'All pages with comments enabled',
				'is_comments' => true
			);
		}
		
		return $forms;
	}
	
	    /**
     * Get the actual location (page title) for a form
     *
     * @param string $form_id
     * @param array $form_data
     * @return array Returns array with 'title' and 'page_id'
     */
    private static function get_form_location($form_id, $form_data) {
        $result = array(
            'title' => isset($form_data['form_name']) ? $form_data['form_name'] : 'Unknown Page',
            'page_id' => 0
        );
        
        // If we have a page_id, get the page title
        if (isset($form_data['page_id']) && !empty($form_data['page_id'])) {
            $page = get_post($form_data['page_id']);
            if ($page) {
                $result['title'] = $page->post_title;
                $result['page_id'] = $page->ID;
                return $result;
            }
        }
        
        // For Divi forms, extract page ID from form ID
        if (strpos($form_id, 'divi_') !== false) {
            $page_id = str_replace('divi_', '', $form_id);
            if (is_numeric($page_id)) {
                $page = get_post($page_id);
                if ($page) {
                    $result['title'] = $page->post_title;
                    $result['page_id'] = $page->ID;
                    return $result;
                }
            }
        }
        
        // For Contact Form 7, search for where it's used
        if (strpos($form_id, 'cf7-') !== false) {
            $form_id_number = str_replace('cf7-', '', $form_id);
            $page_info = self::find_contact_form_7_page($form_id_number);
            if ($page_info && isset($page_info['page_id'])) {
                $page = get_post($page_info['page_id']);
                if ($page) {
                    $result['title'] = $page->post_title;
                    $result['page_id'] = $page->ID;
                    return $result;
                }
            }
        }
        
        // For WPForms, search for where it's used
        if (strpos($form_id, 'wpforms_') !== false) {
            $form_id_number = str_replace('wpforms_', '', $form_id);
            $page_url = self::find_wpforms_page($form_id_number);
            if ($page_url) {
                $page_id = url_to_postid($page_url);
                if ($page_id) {
                    $page = get_post($page_id);
                    if ($page) {
                        $result['title'] = $page->post_title;
                        $result['page_id'] = $page_id;
                        return $result;
                    }
                }
            }
        }
        
        // For Gravity Forms, search for where it's used
        if (strpos($form_id, 'gravity_') !== false) {
            $form_id_number = str_replace('gravity_', '', $form_id);
            $page_url = self::find_gravity_forms_page($form_id_number);
            if ($page_url) {
                $page_id = url_to_postid($page_url);
                if ($page_id) {
                    $page = get_post($page_id);
                    if ($page) {
                        $result['title'] = $page->post_title;
                        $result['page_id'] = $page_id;
                        return $result;
                    }
                }
            }
        }
        
        // For Ninja Forms, search for where it's used
        if (strpos($form_id, 'ninja_') !== false) {
            $form_id_number = str_replace('ninja_', '', $form_id);
            $page_url = self::find_ninja_forms_page($form_id_number);
            if ($page_url) {
                $page_id = url_to_postid($page_url);
                if ($page_id) {
                    $page = get_post($page_id);
                    if ($page) {
                        $result['title'] = $page->post_title;
                        $result['page_id'] = $page_id;
                        return $result;
                    }
                }
            }
        }
        
        return $result;
    }
	
	    /**
     * Find where a Contact Form 7 form is used
     *
     * @param int $form_id
     * @return array|false Array with page_id and page_url if found, false otherwise
     */
    public static function find_contact_form_7_page($form_id) {
        $cache_key = 'formshield_cf7_page_' . (int) $form_id;
        $cached    = wp_cache_get($cache_key, 'formshield');
        if (false !== $cached) {
            return $cached;
        }

        $posts = get_posts(array(
            'post_type'      => array('page', 'post'),
            'post_status'    => 'publish',
            'posts_per_page' => 50,
            'fields'         => 'ids',
        ));

        $result = false;
        foreach ($posts as $post_id) {
            $content = get_post_field('post_content', $post_id);
            if (
                strpos($content, '[contact-form-7 id="' . $form_id . '"') !== false ||
                strpos($content, 'contact-form-7 id=' . $form_id) !== false
            ) {
                $result = array('page_id' => $post_id, 'page_url' => get_permalink($post_id));
                break;
            }
        }

        wp_cache_set($cache_key, $result, 'formshield', 300);
        return $result;
    }
	
	/**
	 * Find where a WPForms form is used
	 *
	 * @param int $form_id
	 * @return string|false
	 */
	private static function find_wpforms_page($form_id) {
		$cache_key = 'formshield_wpf_page_' . (int) $form_id;
		$cached    = wp_cache_get($cache_key, 'formshield');
		if (false !== $cached) {
			return $cached;
		}

		$posts  = get_posts(array('post_type' => array('page', 'post'), 'post_status' => 'publish', 'posts_per_page' => 50, 'fields' => 'ids'));
		$result = false;
		foreach ($posts as $post_id) {
			$content = get_post_field('post_content', $post_id);
			if (strpos($content, '[wpforms id="' . $form_id . '"') !== false || strpos($content, 'wpforms id=' . $form_id) !== false) {
				$result = get_permalink($post_id);
				break;
			}
		}

		wp_cache_set($cache_key, $result, 'formshield', 300);
		return $result;
	}
	
	/**
	 * Find where a Gravity Forms form is used
	 *
	 * @param int $form_id
	 * @return string|false
	 */
	private static function find_gravity_forms_page($form_id) {
		$cache_key = 'formshield_gf_page_' . (int) $form_id;
		$cached    = wp_cache_get($cache_key, 'formshield');
		if (false !== $cached) {
			return $cached;
		}

		$posts  = get_posts(array('post_type' => array('page', 'post'), 'post_status' => 'publish', 'posts_per_page' => 50, 'fields' => 'ids'));
		$result = false;
		foreach ($posts as $post_id) {
			$content = get_post_field('post_content', $post_id);
			if (strpos($content, '[gravityform id="' . $form_id . '"') !== false || strpos($content, 'gravityform id=' . $form_id) !== false) {
				$result = get_permalink($post_id);
				break;
			}
		}

		wp_cache_set($cache_key, $result, 'formshield', 300);
		return $result;
	}
	
	/**
	 * Find where a Ninja Forms form is used
	 *
	 * @param int $form_id
	 * @return string|false
	 */
	private static function find_ninja_forms_page($form_id) {
		$cache_key = 'formshield_nf_page_' . (int) $form_id;
		$cached    = wp_cache_get($cache_key, 'formshield');
		if (false !== $cached) {
			return $cached;
		}

		$posts  = get_posts(array('post_type' => array('page', 'post'), 'post_status' => 'publish', 'posts_per_page' => 50, 'fields' => 'ids'));
		$result = false;
		foreach ($posts as $post_id) {
			$content = get_post_field('post_content', $post_id);
			if (strpos($content, '[ninja_form id="' . $form_id . '"') !== false || strpos($content, 'ninja_form id=' . $form_id) !== false) {
				$result = get_permalink($post_id);
				break;
			}
		}

		wp_cache_set($cache_key, $result, 'formshield', 300);
		return $result;
	}

	/**
	 * Validates form submission using content-based spam detection.
	 * Honeypot checks happen earlier in each integration and never reach this function.
	 * This function checks the actual message content for known spam patterns.
	 *
	 * @return bool True = block (spam detected), False = allow (clean submission).
	 */
	public static function fail_form_validation() {
		$options      = FormShield::get_options();
		$wp_hp_debug  = ! empty( $options['wp_hp_debug'] );

		$spam_reason = self::is_content_spam(); // '' = clean, non-empty string = spam reason
		$failed      = '' !== $spam_reason;

		// Check behavioral score stored by the JS AJAX pre-check (if it ran within last 5 min).
		if ( ! $failed ) {
			$ip = formshield_get_validated_ip( 'Unknown' );
			if ( 'Unknown' !== $ip ) {
				$behavioral_score = get_transient( 'formshield_behavioral_' . md5( $ip ) );
				if ( false !== $behavioral_score && (int) $behavioral_score >= 70 ) {
					$spam_reason = 'behavioral_score:' . (int) $behavioral_score;
					$failed      = true;
				}
			}
		}

		if ( $wp_hp_debug ) {
			$latest_submissions = ! empty( $options['latest_submissions'] ) ? $options['latest_submissions'] : array();
			if ( count( $latest_submissions ) >= FORMSHIELD_LOG_LIMIT ) {
				array_pop( $latest_submissions );
			}
			$sanitized_request = array();
			// phpcs:ignore WordPress.Security.NonceVerification.Missing
			foreach ( $_POST as $key => $value ) {
				if ( in_array( $key, array( '_wpcf7', '_wpnonce', 'form_id' ), true ) ) {
					$sanitized_request[ $key ] = sanitize_text_field( $value );
				} else {
					$sanitized_request[ $key ] = '***REDACTED***';
				}
			}
			array_unshift( $latest_submissions, array(
				'request'           => $sanitized_request,
				'response'          => array( 'signal' => $failed ? 'SPAM' : 'CLEAN', 'reason' => $spam_reason ),
				'failed_validation' => $failed ? 'Yes' : 'No',
			) );
			$options['latest_submissions'] = $latest_submissions;
			form_shield()->update_options( $options );
		}

		return $failed;
	}

	/**
	 * Collects all user-submitted text from $_POST (skipping internal WP/CF7/FormShield fields)
	 * and checks it against known spam patterns.
	 *
	 * Returns '' if clean, or a non-empty reason string if spam was detected.
	 * Callers: cast to bool for block/allow; use the string for debug logging.
	 *
	 * Order of checks:
	 *   0. Whitelist  — any match → allow immediately
	 *   1. Custom blacklist phrases/domains from settings → block
	 *   2. 2 or more URLs → block
	 *   3. Built-in spam domains → block
	 *   4. Built-in spam phrases → block
	 *
	 * @return string Empty string = clean; non-empty = spam reason.
	 */
	private static function is_content_spam() {
		$text = self::collect_post_text();

		if ( empty( $text ) ) {
			return '';
		}

		$lower   = strtolower( $text );
		$options = FormShield::get_options();

		// --- 0. WHITELIST ---
		$whitelist_entries = self::parse_lines( isset( $options['spam_custom_whitelist'] ) ? $options['spam_custom_whitelist'] : '' );
		$own_host = wp_parse_url( home_url(), PHP_URL_HOST );
		if ( ! empty( $own_host ) ) {
			$whitelist_entries[] = strtolower( $own_host );
		}
		foreach ( $whitelist_entries as $entry ) {
			if ( ! empty( $entry ) && false !== strpos( $lower, $entry ) ) {
				return '';
			}
		}

		// --- 1. CUSTOM BLACKLIST ---
		$custom_blacklist = self::parse_lines( isset( $options['spam_custom_blacklist'] ) ? $options['spam_custom_blacklist'] : '' );
		foreach ( $custom_blacklist as $entry ) {
			if ( ! empty( $entry ) && false !== strpos( $lower, $entry ) ) {
				return 'custom_blacklist:' . $entry;
			}
		}

		// --- 2. Two or more URLs ---
		$url_count = preg_match_all( '/https?:\/\/\S+/i', $text );
		if ( $url_count !== false && $url_count >= 2 ) {
			return 'multiple_urls';
		}

		// --- 3. Built-in spam domains ---
		$spam_domains = array(
			// URL shorteners (common in spam)
			'bit.ly', 'tinyurl.com', 'ow.ly', 'goo.gl', 't.co', 'is.gd',
			'buff.ly', 'adf.ly', 'shorte.st', 'bc.vc', 'u.to', 'v.gd',
			'qr.net', 'short.link', 'rebrand.ly', 'rb.gy', 'cutt.ly',
			'tiny.cc', 'surl.li', 'shorturl.at', 'bl.ink', 'tny.im',
			// Gambling
			'casino', 'poker', 'slots', 'online-casino', 'sportsbetting',
			'baccarat', 'roulette-', 'blackjack-', 'casinobet', 'betmaster',
			// Loan / financial spam
			'payday-loan', 'paydayloan', 'loan-offer', 'loanoffer',
			'quickloan', 'fastloan', 'instantloan', 'creditoffer',
			'debtrelief', 'debtconsolidation', 'mortgageoffer',
			// Pharma
			'viagra', 'cialis', 'levitra', 'pharma', 'rxpill', 'onlinepharmacy',
			'buymedication', 'cheapmeds', 'pillonline',
			// Crypto spam
			'crypto-profit', 'nft-drop', 'airdrop.io', 'cryptomining',
			'bitcoininvestment', 'cryptoearning', 'freecrypto', 'freebitcoin',
			'cryptosignal', 'altcoin-', 'defi-profit',
			// SEO / traffic spam
			'marketingaged.com', 'seo-promo.net', 'trafficmaster.ru',
			'buyseotraffic', 'buywebtraffic', 'trafficbot', 'seoblast',
			'backlinksale', 'buybacklinks', 'rankbooster',
			// Adult
			'porn', 'xxx', 'adult-', 'sexchat', 'hotgirls', 'nakedcam',
			// Malware / phishing common patterns
			'download-now.net', 'freeware-', 'cracked-software',
			'keygen', 'serial-key', 'license-crack',
		);
		foreach ( $spam_domains as $domain ) {
			if ( false !== strpos( $lower, $domain ) ) {
				return 'spam_domain:' . $domain;
			}
		}

		// --- 4. Built-in spam phrases ---
		$spam_phrases = array(
			// Money / investment
			'make money fast', 'earn money online', 'work from home earn',
			'guaranteed returns', 'risk-free investment', 'passive income guaranteed',
			'double your money', 'triple your investment', 'earn from home',
			'financial freedom guaranteed', 'get rich quick',
			// Prize / lottery
			'click here to claim', 'you have been selected', 'congratulations you won',
			'you are a winner', 'claim your prize', 'claim your reward',
			'you have won', 'lucky winner', 'selected as winner',
			// Crypto
			'free crypto', 'free bitcoin', 'invest now', 'crypto opportunity',
			'bitcoin profit', 'ethereum giveaway', 'nft opportunity',
			// Deals
			'100% free', 'no credit check', 'act now limited', 'limited time offer',
			'buy cheap', 'order now discount', 'best price guaranteed',
			'lowest price online', 'exclusive deal today', 'offer expires',
			// Health spam
			'weight loss guaranteed', 'lose weight fast', 'burn fat overnight',
			'flat belly trick', 'secret diet', 'miracle pill',
			// Social media spam
			'buy followers', 'buy likes', 'buy subscribers', 'real followers cheap',
			'boost your instagram', 'boost your tiktok', 'youtube subscribers',
			// Click bait
			'click here now', 'click link below', 'visit our website now',
			'check out this link', 'see amazing results', 'watch this video',
			// Adult
			'meet singles', 'hot singles near', 'local hookup',
			// Misc high-confidence spam
			'enlargement', 'male enhancement', 'erectile', 'breast enhancement',
			'work from home no experience', 'easy money online',
		);
		foreach ( $spam_phrases as $phrase ) {
			if ( false !== strpos( $lower, $phrase ) ) {
				return 'spam_phrase:' . $phrase;
			}
		}

		return '';
	}

	/**
	 * Splits a multi-line textarea value into a trimmed, lowercased array of non-empty strings.
	 *
	 * @param string $raw Raw textarea value.
	 * @return string[]
	 */
	private static function parse_lines( $raw ) {
		if ( empty( $raw ) ) {
			return array();
		}
		$lines  = preg_split( '/\r?\n/', $raw );
		$result = array();
		foreach ( $lines as $line ) {
			$clean = strtolower( trim( $line ) );
			if ( '' !== $clean ) {
				$result[] = $clean;
			}
		}
		return $result;
	}

	/**
	 * Collects all plain-text user content from $_POST, skipping internal plugin / WP fields.
	 *
	 * @return string Concatenated, lowercased submission text.
	 */
	private static function collect_post_text() {
		$skip_prefixes = array( '_wpcf7', '_wp', 'formshield', 'g-recaptcha', 'action', 'nonce' );
		$parts         = array();

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		foreach ( $_POST as $key => $value ) {
			$skip = false;
			foreach ( $skip_prefixes as $prefix ) {
				if ( strpos( $key, $prefix ) === 0 ) {
					$skip = true;
					break;
				}
			}
			if ( $skip ) {
				continue;
			}
			if ( is_string( $value ) && ! empty( $value ) ) {
				$parts[] = sanitize_textarea_field( wp_unslash( $value ) );
			}
		}

		return implode( ' ', $parts );
	}

	/**
	 * Record suspicious form activity and attack statistics in one DB write.
	 *
	 * @param string $form_id    Form ID.
	 * @param string $attack_type spam|bot|injection|other (default 'other').
	 */
	public static function handle_suspicious_form_activity( $form_id, $attack_type = 'other' ) {
		$options = FormShield::get_options();
		if ( ! is_array( $options ) ) {
			return;
		}

		// Per-form counters.
		if ( ! isset( $options['formshield_forms'][ $form_id ] ) || ! is_array( $options['formshield_forms'][ $form_id ] ) ) {
			$options['formshield_forms'][ $form_id ] = array();
		}
		$form_data = &$options['formshield_forms'][ $form_id ];
		$form_data['suspicious_ct']            = ( isset( $form_data['suspicious_ct'] ) ? (int) $form_data['suspicious_ct'] : 0 ) + 1;
		$form_data['last_suspicious_activity'] = gmdate( 'Y-m-d H:i:s' );
		$form_data['blocked_attempts']         = ( isset( $form_data['blocked_attempts'] ) ? (int) $form_data['blocked_attempts'] : 0 ) + 1;

		// Global counters.
		$options['blocked_attempts'] = ( isset( $options['blocked_attempts'] ) ? (int) $options['blocked_attempts'] : 0 ) + 1;
		$options['last_attack']      = current_time( 'mysql' );

		if ( ! isset( $options['attack_types'] ) || ! is_array( $options['attack_types'] ) ) {
			$options['attack_types'] = array( 'spam' => 0, 'bot' => 0, 'injection' => 0, 'other' => 0 );
		}
		$valid_type = isset( $options['attack_types'][ $attack_type ] ) ? $attack_type : 'other';
		$options['attack_types'][ $valid_type ]++;

		// Single DB write.
		form_shield()->update_options( $options );
	}

	/**
	 * Record attack statistics for Analytics Overview.
	 * Kept for backward compatibility — delegates to handle_suspicious_form_activity.
	 *
	 * @param string $form_id    Form ID.
	 * @param string $attack_type spam|bot|injection|other.
	 */
	public static function record_attack_statistics( $form_id, $attack_type = 'other' ) {
		self::handle_suspicious_form_activity( $form_id, $attack_type );
	}

	/**
	 * Record spam attack
	 *
	 * @param String $form_id - Form ID
	 * @param String $email - Email address (optional)
	 * @param String $content - Content sample (optional)
	 *
	 * @return Void
	 */
	public static function record_spam_attack( $form_id, $email = '', $content = '' ) {
		self::record_attack_statistics( $form_id, 'spam' );
		
	}

	/**
	 * Record bot attack
	 *
	 * @param String $form_id - Form ID
	 * @param String $user_agent - User agent string (optional)
	 * @param String $ip - IP address (optional)
	 *
	 * @return Void
	 */
	public static function record_bot_attack( $form_id, $user_agent = '', $ip = '' ) {
		self::record_attack_statistics( $form_id, 'bot' );
		
	}

	/**
	 * Record injection attack
	 *
	 * @param String $form_id - Form ID
	 * @param String $payload - Malicious payload (optional)
	 * @param String $field - Field name (optional)
	 *
	 * @return Void
	 */
	public static function record_injection_attack( $form_id, $payload = '', $field = '' ) {
		self::record_attack_statistics( $form_id, 'injection' );
		
	}

	/**
	 * Get uptime percentage based on last attack
	 *
	 * @return Integer - Uptime percentage (0-100)
	 */
	public static function get_uptime_percentage() {
		$options = FormShield::get_options();
		$last_attack = isset( $options['last_attack'] ) ? $options['last_attack'] : '';
		
		if ( empty( $last_attack ) ) {
			return 100; // No attacks recorded, assume 100% uptime
		}
		
		$last_attack_time = strtotime( $last_attack );
		$current_time = current_time( 'timestamp' );
		$time_since_attack = $current_time - $last_attack_time;
		
		// If no attack in last 24 hours, uptime is 100%
		if ( $time_since_attack > DAY_IN_SECONDS ) {
			return 100;
		}
		
		// Calculate uptime based on time since last attack
		// More recent attacks = lower uptime
		$uptime = max( 85, 100 - ( $time_since_attack / DAY_IN_SECONDS ) * 15 );
		
		return round( $uptime );
	}

	/**
	 * Returns the failed form validation error message.
	 *
	 * @return String
	 */
	public static function fail_form_error_message() {
		return apply_filters(
			'formshield_fail_validation_message',
			__( 'Sorry, we could not process your submission at this time. Please try again later.', 'formshield' )
		);
	}

	/**
	 * Show admin notice for forms in protected forms table
	 *
	 * @param String $form_id - Form ID to enable/disable
	 * @param Integer $enabled - Boolean Int (1 === enabled)
	 * @param String $alert_type - success/warning class for enable/disable form notices
	 *
	 * @return Void
	 */
	public static function show_protected_forms_admin_notice( $form_id, $enabled, $alert_type ) {
		$options                     = FormShield::get_options();
		$current_action              = $enabled ? 'enable' : 'disable';
		$hp_comm_forms_limit_reached = isset( $options['protected_forms_ct'] ) ? $options['protected_forms_ct'] > 0 : false;
		if ( ( isset( $options['wp_hp_premium_license'] ) && 1 == $options['wp_hp_premium_license'] ) || ! $enabled || ( $enabled && ! $hp_comm_forms_limit_reached ) ) {
			// Handle unprotect request or premium license request to protect more than 1 form
			FormShieldUtils::show_wp_admin_notice( $current_action . 'd form #' . $form_id, 'notice-' . $alert_type . ' is-dismissible' );
		} else {
			// Handle community plan forms limit reached
			FormShieldUtils::show_wp_admin_notice( 'Community version limit reached. Protecting more than one form requires a premium license.', 'notice-error is-dismissible' );
		}
	}

	/**
	 * AJAX handler for recording suspicious activity from Divi forms
	 */
	public static function record_suspicious_activity_ajax() {
		// Verify nonce
		formshield_verify_nonce_or_bail('formshield_form_enabled_change');

		$form_id = formshield_get_post_string('form_id');
		
		if ( $form_id ) {
			self::handle_suspicious_form_activity( $form_id );
			wp_send_json_success( 'Activity recorded' );
		} else {
			wp_send_json_error( 'Invalid form ID' );
		}
	}

}
