<?php
/*
 * Developed By Devozon
 *
 * Check Out at https://devozon.com/
 * Email: support@devozon.com
 * Message: https://www.facebook.com/devozon
 *
 * Please feel free to contact me at any time if you need a custom script or any development work.
 *
 * Devozon Team:
 * Coded by Sanad Nabil
 * Theme by Ahmed Reda
 * Tested By Smith Carter
 *
 * Devozon All rights reserved
 * Copyright (c) 2023-2025.
 * Last Update 22 \ 6 \ 2025
 */

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

class FENSE_BPVT_RUN_SAVE_MODE
{
	public FENSE_BPVT_FUN $Fense_FUN;
	public string $AppKey;
	public stdClass $settings;
	public array $template;
	public string $ip;
	public stdClass $ipData;
	public string $dbKey = 'FENSE_BPVT_DEVOZON_';
	public string $dbDailyLimitKey;
	
	public function __construct()
	{
		if ( !defined( 'DONOTCACHEPAGE' ) ) {
			define( 'DONOTCACHEPAGE', true );
		}
		
		$this->ipData = new stdClass();
		
		$this->Fense_FUN = new FENSE_BPVT_FUN();
		
		$this->dbDailyLimitKey = $this->dbKey . 'is_daily_limit_reached';
	}
	
	public function loadAppKey()
	{
		$this->AppKey = get_option( 'FENSE_BPVT_DEVOZON_licence_key' );
		return $this->AppKey;
	}
	
	public function loadSettings()
	{
		/**  Load Settings */
		$this->settings = FENSE_BPVT_plugin_settings( $this->Fense_FUN );
		
		/**  Default Protection Mode is Message */
		if ( empty( $this->settings->protection_mode ) ) $this->settings->protection_mode = 'message';
		
		/**  Build Message Template */
		$this->template = [
			'English',
			$this->settings->message,
			$this->settings->disable_link,
			$this->settings->link,
			$this->settings->protection_mode,
			$this->settings->url,
		];
		
		/**  return settings */
		return $this->settings;
	}
	
	public function loadUserIp(): ?string
	{
		/** Get Visitor IP */
		$this->ip = $this->Fense_FUN->get_the_user_ip();
		
		return $this->ip;
	}
	
	public function isCache(): array
	{
		/**  Load Data From Cache if Exists */
		$Gip = get_transient( 'bpvt_ip_' . md5( $this->AppKey . '_' . $this->ip ) );
		$expires = is_array( $Gip ) && isset( $Gip['time'] ) ? (int)$Gip['time'] : 0;
		
		/** Exit if Data is Good */
		if ( time() < $expires ) {
			
			/** add ip data from cache to var */
			$this->ipData = $Gip['data'];
			
			/** check if country is blocked  */
			$country = $this->__country();
			
			return [ 'stop' => true, 'isProxy' => $country['isProxy'] ];
		}
		
		return [ 'stop' => false, 'isProxy' => false ];
	}
	
	public function loadData()
	{
		/** Load IP Data */
		$this->ipData = $this->Fense_FUN->Fense_data( $this->ip, $this->AppKey );
		
		/** Check if the Daily Limit Has Reached */
		$this->__saveDailyLimitReached();
		
		return $this->ipData;
	}
	
	public function __isDailyLimitReached(): bool
	{
		// Get current transient
		$transient = get_transient( $this->dbDailyLimitKey );
		$expires = is_array( $transient ) && isset( $transient['time'] ) ? (int)$transient['time'] : 0;
		
		// If expired or missing
		if ( time() >= $expires ) {
			return false;
		}
		
		return true;
	}
	
	public function __saveDailyLimitReached()
	{
		$message = 'Api Daily Limit Reached Upgrade Your Plan';
		
		// Skip if not a limit error
		if ( !in_array( $this->ipData->status, [ 'Error', 'error' ] ) || $this->ipData->message !== $message ) return null;
		
		// Get current transient
		$transient = get_transient( $this->dbDailyLimitKey );
		$expires = is_array( $transient ) && isset( $transient['time'] ) ? (int)$transient['time'] : 0;
		
		// If expired or missing, set new transient with 10min future expiry
		if ( time() >= $expires ) {
			set_transient( $this->dbDailyLimitKey, [ 'time' => time() + 600 ], 600 );
		}
	}
	
	public function __enableOn(): bool
	{
		if ( $this->settings->enable_on !== 'custom' ) {
			return false;
		}
		
		if ( !$this->settings->enable_on_logged && is_user_logged_in() ) {
			return true;
		}
		
		if ( !$this->settings->enable_on_posts && is_single() ) {
			return true;
		}
		
		if ( !$this->settings->enable_on_pages && is_page() ) {
			return true;
		}
		
		if ( !$this->settings->enable_on_login && isset( $GLOBALS['pagenow'] ) && $GLOBALS['pagenow'] === 'wp-login.php' ) {
			return true;
		}
		
		return false;
	}
	
	public function __country(): array
	{
		// no country → nothing to do
		if ( empty( $this->ipData->country ) ) {
			
			return [ 'stop' => false, 'isProxy' => false ];
		}
		
		$country = $this->ipData->country;
		
		// reverse‑disable: if country is in re_disable, show template
		if ( !empty( $this->settings->re_disable_country )
			&& in_array( $country, $this->settings->re_disable_country )
		) {
			return [ 'stop' => true, 'isProxy' => true ];
		}
		
		// reverse‑enable: if country NOT in re_enable, show template
		if ( !empty( $this->settings->re_enable_country )
			&& !in_array( $country, $this->settings->re_enable_country, true )
		) {
			return [ 'stop' => true, 'isProxy' => true ];
		}
		
		// strict disable: if country is in disable list, block silently
		if ( !empty( $this->settings->disable_country )
			&& in_array( $country, $this->settings->disable_country, true )
		) {
			return [ 'stop' => true, 'isProxy' => false ];
		}
		
		// strict enable: if country NOT in enable list, block silently
		if ( !empty( $this->settings->enable_country )
			&& !in_array( $country, $this->settings->enable_country, true )
		) {
			return [ 'stop' => true, 'isProxy' => false ];
		}
		
		// by default, nothing to block or override
		return [ 'stop' => false, 'isProxy' => false ];
	}
	
	public function __isAjaxCall(): bool
	{
		if ( function_exists( 'DOING_AJAX' ) && defined( 'DOING_AJAX' ) ) {
			return true;
		}
		
		return false;
	}
	
	public function __isCrawlersBot(): bool
	{
		if ( empty(
			$_SERVER['HTTP_USER_AGENT'] ) ||
			$this->settings->crawlers_bots == 'no' ||
			empty( $this->settings->crawlers_bots_data ) ||
			$this->settings->crawlers_bots_data == ''
		) return false;
		
		// build a regex of all your bots
		$pattern = '/(' . str_replace( ',', '|', $this->settings->crawlers_bots_data ) . ')/i';
		
		return (bool)preg_match( $pattern, $_SERVER['HTTP_USER_AGENT'] );
	}
	
	public function __isAdminOrLoggedIn(): bool
	{
		if ( current_user_can( 'manage_options' ) || is_user_logged_in() ) {
			return true;
		}
		
		return false;
	}
	
	public function __cleanUrl( $rawReferer ): ?string
	{
		if ( empty( $rawReferer ) ) return null;
		
		$parts = parse_url( trim( $rawReferer ), PHP_URL_HOST );
		if ( !$parts ) return null;
		
		$host = strtolower( preg_replace( '/^www\./i', '', $parts ) );
		$segments = explode( '.', $host );
		$count = count( $segments );
		
		if ( $count < 2 ) return $host;
		
		// take last two segments as domain + ext
		return $segments[ $count - 2 ] . '.' . $segments[ $count - 1 ];
	}
	
	public function __blockReferrerDomain(): ?string
	{
		// grab referrer or empty
		$rawReferer = $_SERVER['HTTP_REFERER'] ?? '';
		
		$host = $this->__cleanUrl( $rawReferer ) ?? 'direct';
		
		// ensure block_domains is an array
		$blocked = is_array( $this->settings->block_domains ) ? $this->settings->block_domains : [];
		
		// if host is blocked, return template
		if ( in_array( $host, $blocked ) ) {
			return true;
		}
		
		// not blocked
		return null;
	}
	
	public function __protection_mode(): array
	{
		/** Run Clean UP only on Proxy */
		if ( $this->ipData->proxy == 'yes' ) {
			
			/** Clean UP */
			FENSE_BPVT_FUN::cleanUP();
			
			return [
				'status' => true,
				'message' => $this->settings->message,
				'disable_link' => $this->settings->disable_link,
				'link' => $this->settings->link,
			];
		}
		
		return [ 'status' => false ];
	}
	
	public function __ipHandleWhitelistBlacklist(): bool
	{
		if ( $this->__Whitelist() ) return true;
		if ( $this->__Blacklist() ) return true;
		
		return false;
	}
	
	public function __Whitelist(): bool
	{
		if ( empty( $this->settings->ip_whitelisting_enable ) ) {
			return false;
		}
		
		$allowed = array_map( 'trim', explode( ',', $this->settings->ip_whitelisting ) );
		
		if ( in_array( $this->ip, $allowed, true ) ) {
			// IP is in the list
			return true;
		}
		
		$ipLong = ip2long( $this->ip );
		
		// if no Data break
		if ( empty( $this->settings->ip_whitelisting_range ) ) return false;
		
		foreach ( $this->settings->ip_whitelisting_range as $range ) {
			$from = ip2long( $range['from'] );
			$to = ip2long( $range['to'] );
			if ( $ipLong >= $from && $ipLong <= $to ) {
				return true;
			}
		}
		
		return false;
	}
	
	public function __Blacklist()
	{
		if ( empty( $this->settings->ip_blacklisting_enable ) ) {
			return false;
		}
		
		$blocked = array_map( 'trim', explode( ',', $this->settings->ip_blacklisting ) );
		$this->ipData->proxy = 'yes';
		
		if ( in_array( $this->ip, $blocked, true ) ) {
			// IP is in the list
			return $this->__protection_mode();
		}
		
		$ipLong = ip2long( $this->ip );
		
		// if no Data break
		if ( empty( $this->settings->ip_blacklisting_range ) ) return false;
		
		foreach ( $this->settings->ip_blacklisting_range as $range ) {
			$from = ip2long( $range['from'] );
			$to = ip2long( $range['to'] );
			if ( $ipLong >= $from && $ipLong <= $to ) {
				return $this->__protection_mode();
			}
		}
		
		return false;
	}
}
