<?php
/**
 * IP Deny
 * @package apptivo-business-site
 * @author  RajKumar <rmohanasundaram[at]apptivo[dot]com>
 */
if(!defined('AWP_PLUGIN_BASEPATH')){ define('AWP_PLUGIN_BASEPATH',plugin_dir_path(__FILE__)); }
if(!defined('AWP_INC_DIR')){ define('AWP_INC_DIR', AWP_PLUGIN_BASEPATH . '/inc'); }
require_once AWP_INC_DIR . '/config.php';
require_once AWP_LIB_DIR . '/Plugin.php';
/**
 * Class AWP_IPDeny
 */
add_action('wp_ajax_nopriv_delete_ipbannedaccount', 'delete_ipbannedaccount');
add_action('wp_ajax_delete_ipbannedaccount', 'delete_ipbannedaccount');

/* function delete_ipbannedaccount() {
	error_log('AJAX triggered');
	global $wpdb;
	$id_input = isset($_POST['ip_id']) ? (int) $_POST['ip_id'] : 0;
	$id = sanitize_text_field(wp_unslash($id_input));
	$table_name=  $wpdb->prefix.'absp_ipdeny';
	$result = $wpdb->query( $wpdb->prepare( "DELETE FROM {$table_name} WHERE ID = %d", $id ) );

	if ($result)	{
		// Invalidate related cache (if used elsewhere)
		wp_cache_delete( $id, 'delete_ipbannedaccount_cache' );
		echo "Success::".esc_attr($id);

	} else {
		echo esc_html( $wpdb->last_error );
	}
	die();   
} */

function delete_ipbannedaccount() {
	if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'delete_ipbanned_nonce')) {
		wp_send_json_error('Invalid nonce');
	}

	global $wpdb;
	$ip_id = isset($_POST['ip_id']) ? intval($_POST['ip_id']) : 0;
	$table = $wpdb->prefix . 'absp_ipdeny';

	// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We are checking table existence safely
	$deleted = $wpdb->delete($table, ['ID' => $ip_id]);

	if ($deleted) {
		// Invalidate any cached data related to this table
		wp_cache_delete('list_table_cache');
		wp_send_json_success(['deleted_id' => $ip_id]);
	} else {
		wp_send_json_error('Could not delete');
	}
}

class AWP_IPDeny extends AWP_Base
{	
	function __construct()
    {
    	
    }
    
    function &instance()
    {
        static $instances = array();
        if (!isset($instances[0])) {
            $class = __CLASS__;
            $instances[0] =  new $class();
        }        
        return $instances[0];
    }
        
	function settings() {
		$IPSettings = new AWP_Request();
		global $wpdb;
		$table_name = $wpdb->prefix . "absp_ipdeny";
		$sanitized_table_name = esc_sql($table_name);
		$error = [];
		$ip_address = '';
		$ip_address1 = '';
		$ip_address2 = '';
		$ip_type = 'Single';

		if (isset($_POST['absp_ip']) && !empty($_POST['absp_ip'])) {
			if ( isset($_POST['awp_ipdeny_config_form_nonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['awp_ipdeny_config_form_nonce'])), 'awp_ipdeny_config_form_action') ) {
				$ip_type = $IPSettings->get_string("ip_type");

				if ($ip_type === 'Single') {
					$ip_address = $IPSettings->get_string("ip_address");
					if (!$ip_address) {
						// $error .= "<div>Please Enter IP Address.</div>";
						$error[] = "Please Enter IP Address.";
					} elseif (!validateIpAddress($ip_address)) {
						// $error .= "<div>Please Enter Valid IP Address.</div>";
						$error[] = "Please Enter Valid IP Address.";
					}
				} else {
					$ip_address1 = $IPSettings->get_string("ip_address1");
					$ip_address2 = $IPSettings->get_string("ip_address2");

					if(!$ip_address1) {
						// $error .= "<div>Please Enter Starting IP Address.</div>";
						$error[] = "Please Enter Starting IP Address.";
					} elseif (!validateIpAddress($ip_address1)) {
						// $error .= "<div>Please Enter Valid Starting IP Address.</div>";
						$error[] = "Please Enter Valid Starting IP Address.";
					}

					if (!$ip_address2) {
						// $error .= "<div>Please Enter Ending IP Address.</div>";
						$error[] = "Please Enter Ending IP Address.";
					} elseif (!validateIpAddress($ip_address2)) {
						// $error .= "<div>Please Enter Valid Ending IP Address.</div>";
						$error[] = "Please Enter Valid Ending IP Address.";
					}

					if(empty($error)) {
						$start_ip = ip2long($ip_address1);
						$end_ip = ip2long($ip_address2);
						if ($end_ip <= $start_ip) {
							// $error .= "<div>Ending IP Address Should be greater than Starting IP Address.</div>";
							$error[] = "Ending IP Address Should be greater than Starting IP Address.";
						} else {
							$ip_address = $ip_address1 . '-' . $ip_address2;
						}
					}
				}

				if (empty($error)) {
					// Sanitize final IP address for saving
					if ($ip_type === 'Single') {
						$ip_address = sanitize_text_field(wp_unslash($_POST['ip_address'] ?? ''));
					} else {
						$ip_address = sanitize_text_field($ip_address1) . '-' . sanitize_text_field($ip_address2);
					}

					$cache_key = 'banned_ip_' . md5($ip_address);
					$selected_results = wp_cache_get($cache_key);

					if ($selected_results === false) {
						// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is hardcoded and escaped
						// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We are checking table existence safely
						$selected_results = $wpdb->get_results(
							$wpdb->prepare("SELECT * FROM {$sanitized_table_name} WHERE ip_address = %s", $ip_address)
						);
						wp_cache_set($cache_key, $selected_results);
					}

					if (!empty($selected_results)) {
						wp_cache_delete($cache_key);
						//$error = '<div>This IP Address already banned, Please change Your IP.</div>';
						$error[] = 'This IP Address already banned, Please change Your IP.';
					}
				}

				if (empty($error)) {
					// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We are checking table existence safely
					$result = $wpdb->insert(
						$table_name,
						['ip_address' => $ip_address, 'ip_type' => $ip_type],
						['%s', '%s']
					);

					if ($result) {
						echo '<div class="error" style="border:none;background:none;color:green;font-weight:bold;font-size:16px;">Successfully Added</div>';
						$ip_address = $ip_address1 = $ip_address2 = '';
						$ip_type = 'Single';
					}
				} else {
					//echo '<div class="error">' . esc_html($error) . '</div>';
					echo '<div class="error">' . implode('<br>', array_map('esc_html', $error)) . '</div>';
				}
			}
		}

		$single_select = ($ip_type === 'Single') ? ' selected="selected"' : '';
		$range_select = ($ip_type === 'Range') ? ' selected="selected"' : '';

		echo '<div class="wrap"><h2>Block IP Addresses</h2></div>';
		echo '<form action="" method="post" name="absp_ip_address">';
		wp_nonce_field('awp_ipdeny_config_form_action', 'awp_ipdeny_config_form_nonce');

		echo '<table class="form-table"><tbody>
			<tr valign="top">
			<th valign="top"><label for="ip_type">IP Type </label></th>
			<td valign="top">
				<select id="ip_type" name="ip_type">
					<option value="Single" ' . esc_attr($single_select) . '>Single</option>
					<option value="Range" ' . esc_attr($range_select) . '>Range</option>
			</td>
			</tr>

			<tr valign="top" id="single_ip">
			<th valign="top"><label for="ip_address">IP Address </label></th>
			<td valign="top">
				<input type="text" value="' . esc_attr($ip_address) . '" id="ip_address" name="ip_address" style="width: 250px;">
				<span class="description">(eg:100.100.100.100)</span>
			</td>
			</tr>

			<tr valign="top" id="range_ip" style="display:none;">
			<th valign="top"><label for="ip_address1">IP Range </label></th>
			<td valign="top">
				<input type="text" value="' . esc_attr($ip_address1) . '" id="ip_address1" name="ip_address1" style="width: 250px;">
				<span class="description">Starting IP (eg:100.100.100.100)</span><br/>
				<input type="text" value="' . esc_attr($ip_address2) . '" id="ip_address2" name="ip_address2" style="width: 250px;">
				<span class="description">Ending IP (eg:100.100.100.110)</span>
			</td>
			</tr>

			<tr>
			<td colspan="2">
				<p class="submit">
					<input type="submit" value="Save" class="button-primary" id="absp_ip" name="absp_ip">
				</p>
			</td>
		</tr>

		</tbody></table></form>';

		// Call list table
		$this->list_table();
	}
    
    /*IP Address Lists*/
	/* function list_table() {
		global $wpdb;
		$table_name = $wpdb->prefix . "absp_ipdeny";  //table Name
		$cache_key = 'list_table_cache';
		$Results = wp_cache_get( $cache_key );

		if ( false === $Results ) {
			$Results = $wpdb->get_results("SELECT * FROM {$table_name} ORDER BY cur_timestamp DESC");
			wp_cache_set( $cache_key, $Results );
		}

		if( $Results ) {
			wp_cache_delete( 'list_table_cache' );
		}
		$datas = '';
		if(empty($Results)) {
			$datas = ' <tr ><td colspan="3" style="text-align:center;color:#f00;" >No data available.</td>';
		} else {
			foreach($Results as $selected_results):
			$datas .= '<tr id="tr_'.$selected_results->ID.'" >';
			$datas .= '<td>'.$selected_results->ip_address .'</td>';
			$datas .= '<td>'.$selected_results->ip_type .'</td>';
			$datas .= '<td><a href="javascript:delete_ipbanned('.$selected_results->ID.')" >Delete</a></td>';
			$datas .= '</tr>';
			endforeach;
		}
		
		echo '<div style="width:600px;" class="wrap">
			<h2>Blocked IP Addresses</h2>
			<table class="widefat plugins" width="700" cellspacing="0" cellpadding="0">
				<thead><tr><th>IP Address</th><th>IP Type</th><th>Action</th></tr></thead>
				<tfoot><tr><th>IP Address</th><th>IP Type</th><th>Action</th></tr></tfoot>
				<tbody>' . wp_kses_post($datas) . '</tbody>
			</table>
		</div>';
	} */
	function list_table() {
		global $wpdb;

		// Enqueue your external JS file
		wp_enqueue_script('apptivo-ipdeny-js', plugins_url('assets/js/apptivo-business-plugin.js', dirname(__FILE__)), array('jquery'), '1.0.0', true);


		// Localize script with AJAX URL + Nonce
		wp_localize_script('apptivo-ipdeny-js', 'ipdeny_ajax', array(
			'ajax_url' => admin_url('admin-ajax.php'),
			'nonce'    => wp_create_nonce('delete_ipbanned_nonce')
		));

		$table_name = $wpdb->prefix . "absp_ipdeny";
		$sanitized_table_name = esc_sql($table_name);
		$cache_key = 'list_table_cache';
		$Results = wp_cache_get($cache_key);

		if ( false === $Results ) {
			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is hardcoded and escaped
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We are checking table existence safely
			$Results = $wpdb->get_results("SELECT * FROM {$sanitized_table_name} ORDER BY cur_timestamp DESC");
			wp_cache_set( $cache_key, $Results );
		}

		if ( $Results ) {
			wp_cache_delete( 'list_table_cache' );
		}

		$datas = '';
		if (empty($Results)) {
			$datas = ' <tr><td colspan="3" style="text-align:center;color:#f00;">No data available.</td></tr>';
		} else {
			foreach ($Results as $selected_results) {
				$datas .= '<tr id="tr_' . esc_attr($selected_results->ID) . '">';
				$datas .= '<td>' . $selected_results->ip_address . '</td>';
				$datas .= '<td>' . esc_html($selected_results->ip_type) . '</td>';
				$datas .= '<td><a href="#" class="delete-ip-btn" data-id="' . esc_attr($selected_results->ID) . '">Delete</a></td>';
				$datas .= '</tr>';
			}
		}

		echo '<div style="width:600px;" class="wrap">
			<h2>Blocked IP Addresses</h2>
			<table class="widefat plugins" width="700" cellspacing="0" cellpadding="0">
				<thead><tr><th>IP Address</th><th>IP Type</th><th>Action</th></tr></thead>
				<tfoot><tr><th>IP Address</th><th>IP Type</th><th>Action</th></tr></tfoot>
				<tbody>' . wp_kses_post($datas) . '</tbody>
			</table>
		</div>';
	}
}

function validateIpAddress($ip_addr)
{
	
	//first of all the format of the ip address is matched
	if(preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/",$ip_addr))
	{
		//now all the intger values are separated
		$parts=explode(".",$ip_addr);
		//now we need to check each part can range from 0-255
		foreach($parts as $ip_parts)
		{
			if(intval($ip_parts)>255 || intval($ip_parts)<0)
			return false; //if number is not within range of 0-255
		}
		return true;
	} else {
		return false; //if format of ip address doesn't matches
	}
}

function check_blockip()
{
	global $wpdb;
	$table_name = $wpdb->prefix . "absp_ipdeny";  //table Name
	$sanitized_table_name = esc_sql($table_name);
	if ( ! absp_table_exists( $table_name ) ) {
		return false;
	}

	$visitorIp = trim( get_RealIpAddr() ); // Add trim for safety

	// Cache keys
	$single_cache_key = 'banned_ip_singles';
	$range_cache_key  = 'banned_ip_ranges';

	// Get cached single IPs
	$single_results = wp_cache_get( $single_cache_key );
	if ( false === $single_results ) {
		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is hardcoded and escaped
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We are checking table existence safely
		$single_results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$sanitized_table_name} WHERE ip_type = %s", 'Single' ) );
		wp_cache_set( $single_cache_key, $single_results );
	}
	$singles = array();
	$singles = array_map( 'trim', wp_list_pluck( $single_results, 'ip_address' ) );

	// Check if visitor IP is in single IPs
	if ( in_array( $visitorIp, $singles, true ) ) {
		return "E_IP";
	}

	// Get cached range IPs
	$range_results = wp_cache_get( $range_cache_key );
	if ( false === $range_results ) {
		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is hardcoded and escaped
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We are checking table existence safely
		$range_results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$sanitized_table_name} WHERE ip_type = %s", 'Range' ) );
		wp_cache_set( $range_cache_key, $range_results );
	}

	$ranges = wp_list_pluck( $range_results, 'ip_address' );
	$visit_ip = ip2long( $visitorIp );

	foreach ( $ranges as $range_ip ) {
		$rangeparts = explode( '-', $range_ip );
		$start_ip = ip2long($rangeparts[0]);
		$end_ip = ip2long($rangeparts[1]);
		$start_ip. '-' .$end_ip;
		if( $visit_ip >= $start_ip && $visit_ip <= $end_ip ) {
			return "E_IP";
		}
	}
	return false;
}

function get_RealIpAddr() {
	if (!empty($_SERVER['HTTP_CLIENT_IP'])) {   //check ip from shared internet
		$ip = isset($_SERVER['HTTP_CLIENT_IP']) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_CLIENT_IP'] ) ) : "";
	} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {   //check if ip is passed from a proxy
		$ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) : "";
	} else {
		$ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : "";
	}

	// In some cases, multiple IP addresses might be present in the X-Forwarded-For header
	// The client's IP address is usually the first one in the list
	if (strpos($ip, ',') !== false){
		$ips = explode(',', $ip);
		$ip = trim($ips[0]);
	}
	return $ip;
}

function absp_table_exists($tableName) {
	global $wpdb;
	$cache_key = 'absp_table_exists_' . md5( $tableName );
	$cached_result = wp_cache_get( $cache_key );

	// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We are checking table existence safely
	$db= $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $tableName ) );

	$result = ( $db === $tableName );

	wp_cache_set( $cache_key, $result );

	return $result;
}
?>
