<?php
/**
 * Eventon License class
 * @version 4.9.10
 */


class EVO_Product_Lic extends EVO_Product{

	public $code;
	public $error_msg;
	private $licence_key;

	public function __construct($slug){
		$this->slug = $slug;
		$this->init = false;
		$this->load();
	}
	
	// check purchase code correct format
		// @version 2.4
		public function purchase_key_format($key) {
			$key = trim($key);

		    // Check if key contains hyphens
		    if (!strpos($key, '-')) return false;

		    // Split once
		    if (substr_count($key, '-') !== 4)  return false;
		    $parts = explode('-', $key);
		    if (count($parts) !== 5) return false;

		    // Case 1: MyEventON Direct License → starts with EVO
	        if (preg_match('/^EVO/i', $parts[0])) {
	            if (strlen($parts[0]) !== 11 || strtoupper(substr($parts[0], 0, 3)) !== 'EVO') {
	                return false; // EVO + exactly 8 hex chars
	            }

	            $uuidFirst8 = substr($parts[0], 3); // after "EVO"
        		if (!ctype_xdigit($uuidFirst8))  return false;

	            // Check remaining segments length
		        if (strlen($parts[1]) !== 4 || strlen($parts[2]) !== 4 ||
		            strlen($parts[3]) !== 4 || strlen($parts[4]) !== 12) {
		            return false;
		        }

	            // Reconstruct UUID 
	            $uuid = $uuidFirst8 . '-' . $parts[1] . '-' . $parts[2] . '-' . $parts[3] . '-' . $parts[4];
	            
	            return $this->is_strict_uuid_v4($uuid) && !$this->is_fake_looking_key($uuid);
	        }

	        // Case 2: Standard Envato/CodeCanyon license key (no EVO prefix)
	        else {
	            $uuid = $key;
	            if( $this->slug === 'eventon' ){
	            	// Must be exactly 8-4-4-4-12 and all hex
			        if (strlen($parts[0]) !== 8 || strlen($parts[1]) !== 4 ||
			            strlen($parts[2]) !== 4 || strlen($parts[3]) !== 4 ||
			            strlen($parts[4]) !== 12) {
			            return false;
			        }
	            	return $this->is_strict_uuid_v4($uuid) && !$this->is_fake_looking_key($uuid);
	            }	
	            // addons licenses must have EVO            
	        }
	        return false;
		}

		// Check for licekse key format is valid
			private function is_strict_uuid_v4( $uuid ){
				//EVO_Debug($uuid);
				$pattern = '/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i';
    			return (bool) preg_match($pattern, $uuid);
			}
			public function is_valid_format($key){
				
				$key = trim($key);
				$pattern = '/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i';
			    $pattern2 = "/^(\w{8})-(\w{4})-(\w{4})-(\w{4})-(\w{12})$/";
			    $r1 = (bool) preg_match($pattern, $key);

				if( !$r1){
					return (bool) preg_match( $pattern2, $key );
				}else{
					return $r1;
				}
				
			}
			private function is_fake_looking_key($uuid){
			    $clean = str_replace('-', '', strtoupper($uuid));

			    // Block all identical characters: AAAAAAAA..., 00000000..., FFFFFFFF...
			    if (preg_match('/^(.)\1{31}$/', $clean)) {
			        return true;
			    }

			    // Block repetitive short patterns: 12341234..., ABCDABCD..., etc.
			    if (substr($clean, 16) === substr($clean, 0, 16)) return true;

			    // Block common test/fake patterns
			    $fake_patterns = [
			        '11111111111111111111111111111111',
			        '22222222222222222222222222222222',
			        '33333333333333333333333333333333',
			        '44444444444444444444444444444444',
			        '55555555555555555555555555555555',
			        '66666666666666666666666666666666',
			        '77777777777777777777777777777777',
			        '88888888888888888888888888888888',
			        '99999999999999999999999999999999',
			        '00000000000000000000000000000000',
			        'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
			        'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
			        'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC',
			        'DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD',
			        'EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE',
			        'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
			        '1234567890ABCDEF1234567890ABCDEF',
			        'DEADDEADDEADDEADDEADDEADDEADDEAD',
			        'CAFEBABECAFEBABECAFEBABECAFEBABE',
			    ];

			    if (in_array($clean, $fake_patterns, true)) {
			        return true;
			    }

			    // Optional: Block keys with very low entropy (e.g. 1111-2222-...)
			    $unique_chars = count(array_unique(str_split($clean)));
			    if ($unique_chars <= 4) {
			        return true; // Too few unique hex chars → fake
			    }

			    return false;
			}

	// get license code for all liceneses
		public function get_lics_code(){	}

	// Actions
		// deactivate
			function deactivate(){
				$this->set_prop('status','inactive');
				$this->force_package_update('dettach');	
				return true;			
			}
			function remote_deactivate($__data){
				$output = array();

				//if($this->slug == 'eventon') return false;

				$url= $this->api_url_base(). 'request=deactivation&email='.$__data['email'].'&licence_key='.$__data['key'].'&instance=0&product_id='.$__data['product_id'];

				$request = wp_remote_get($url);
				
				if( is_wp_error($request)){
					$output['error_code'] = 30; return $output;
				}
				if($request['response']['code'] !==200){
					$output['error_code'] = 31; return $output;
				}
				
				$output['result'] = (!empty($request['body']))? json_decode($request['body']): $request; 				
				return $output;
			}

		// save license data only 
			function save_license_data(){
				if(empty($_POST['type'])) return false;

				if( $_POST['type'] == 'main'){
					$data_array = array(
						'envato_username'=>'envato_username',
						'email'=>'envato_username', // since 4.9.10
						'envato_api_key'=>'envato_api_key',
						'key'=>'key',
					);
				}else
				if($_POST['type'] == 'addon'){
					$data_array = array(
						'instance'=>'instance',
						'email'=>'email',
						'key'=>'key',
						'ID'=>'product_id'
					);
				}

				foreach($data_array as $var=>$field){
					if(!isset($_POST[ $field ])) continue;
					$this->set_prop($var , $_POST[ $field ]);
				}

			}

	
	// Returns		
		// check if the license key was validated remotely
		public function remotely_validated(){			
			return ($this->get_prop('remote_validity') && $this->get_prop('remote_validity') == 'valid' && $this->get_prop('status') && $this->get_prop('status') =='active')?
				true: false;
		}
		public function get_license(){
			return $this->get_prop('key')? $this->get_prop('key'): false;
		}
		public function get_partial_license(){				
			$key = $this->get_license();
			if(!empty($key )){
				if($this->slug=='eventon'){
					$valid_key = $this->purchase_key_format($key);
					if($valid_key){
						$parts = explode('-', $key);
						return '****-'.$parts[4];
					}else{
						$this->deactivate($slug);
						return 'n/a';
					}
				}else{
					// for addons
					return 'xxxxxxxx-xxxx-xxxx-xxxx-';
				}
			}else{return '--';}
		}
	
		// for AJAX
		// return api url 
			protected function get_api_url($args){
				$url = '';

				$instance = base64_encode(get_site_url());	
				$licence_key = trim( $args['key'] );
				$user_id = 	'';
				if( !empty( $args['email'])) $user_id = $args['email'];	
				if( !empty( $args['envato_username'])) $user_id = $args['envato_username'];	

				$product_id = $this->slug;
				if( !empty( $args['product_id'])) $product_id = $args['product_id'];

				$url = $this->api_url_base(). 'request=activation&email='.$user_id.'&licence_key='.$args['key'].'&product_id='.$product_id.'&instance='.$instance;

				return $url;
			}

			function api_url_base(){
				return 'https://get.myeventon.com/activations/?';
			}

		// remote validation 
			function remote_validation($args){				

				if(!isset($args['key'])) return false;

				$url = $this->get_api_url($args);

				$licence_key = $args['key'];

				$output = array();
				$output['error_code'] = 11;
				$output['status'] = 'bad';
				$output['api_url'] = $url;

				$response = wp_remote_post( $url,
					array(
						'headers'=> array(
							'User-Agent' => "Purchase code verification on ".get_site_url()
						),
						'timeout' => 20,
						'headers_data' => false,
					)
				);

				//echo $url;
				//print_r($response);			
				
				if ( is_wp_error( $response ) ){
					$output['error_code'] = 23; 
					$this->record(23,'remote_validation_failed', 'URL:'.$url);
					return $output;
				}

				if ( $response['response']['code'] == 403 || ( !empty($response['response']['status_code'] ) && $response['response']['status_code'] == 403 ) 
				){
					$output['error_code'] = 163; 
					$this->record(163,'remote_validation_failed', 'URL:'.$url);
					return $output;
				}
				if ( $response['response']['code'] == 404 ) {
					$output['error_code'] = 164; 
					$this->record(164,'remote_validation_failed', 'URL:'.$url);
					return $output;
				}
				// not acceptable => fallback to curl
				if ( $response['response']['code'] == 406 ) {
					
					$output['error_code'] = 406;
					$this->record(21,'remote_validation_failed', 'URL:'.$url);
					return $output;
				}


				// 
				if ( $response['response']['code'] !== 200 ) {
					$output['error_code'] = 21;
					$this->record(21,'remote_validation_failed', 'URL:'.$url);
					return $output;
				}


				$json = json_decode( $response['body'], true );
				
				//print_r($json);

				
				// for eventon main plugin via codecanyon @updated 4.9.7
				if($this->slug == 'eventon' && strpos($licence_key, 'EVO') !== 0){	
					if ( ! $json || ! isset( $json['item'] ) ) {
						$output['error_code'] = 03; 
						return $output;
					}

					if( empty($json['item']) || !is_array($json['item'])){
						$output['error_code'] = 02; 
						return $output;
					}
					
					if( !empty($json['item']['id']) && $json['item']['id'] !='1211017'){
						$output['error_code'] = 22; 
						return $output;
					}

					// update other values
					if(!empty($json['buyer'])){ 
						$this->set_prop( 'buyer', $json['buyer']);
						$output['status'] = 'good';
					}

					$this->set_prop('remote_validity','valid' );

				}else{ 
				// for addons & eventon Full
					if ( !$json ){	
						$output['error_code'] = 30; 
						return $output; 
					}
					
					if ( !empty( $json['error'] ) ){
						$output['error_remote_msg'] = $json['error'];
						if( isset( $json['additional info'])) $output['error_additional_info'] = $json['additional info'];
						$output['error_code'] = isset( $json['code'])?  $json['code']: 11; 
						$this->record($output['error_code'],'remote_validation_error', 'URL:'.$url);
						return $output;
					}

					// remote validated
					if( isset($json['activated']) && $json['activated'] == true){
						$this->set_prop('remote_validity','valid' );
						$this->set_prop('key',$licence_key );
						$output['status'] = 'good';
						$this->dl_updater();
					}	
				}

				// output include
				// status, error_remote_msg, error_code, api_url
				return $output;
			}

		// auto validation checker
			function check_validity(){
				$rv = $this->get_prop('remote_validity');

				if($rv == 'valid') return true;
				if($rv == 'local'){

					if(!$this->get_prop('key')) return false;

					$args = array(
						'key'=> $this->get_prop('key'),
						'email'	=> $this->get_prop('email'),
						'product_id'	=> $this->get_prop('ID'),
						'instance'	=> $this->get_prop('instance'),
					);

					$remote_validate = $this->remote_validation($args);
				}
			}

		// use curl as fallback for remote post
			private function remote_get_eventon_curl( $url ){
				if ( !function_exists( 'curl_init' ) ) {
					return false;
				}

				$ch = curl_init();
			    curl_setopt( $ch, CURLOPT_URL, $url );
			    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
			    curl_setopt( $ch, CURLOPT_TIMEOUT, 20 ); // Adjust timeout as needed
			    $response = curl_exec( $ch );
			    if ( curl_errno( $ch ) ) {
			        //echo 'cURL Error: ' . curl_error( $ch );
			        return false;
			    }
			    curl_close( $ch );
			    return json_decode( $response );
			}

		// download link updater
			function dl_updater(){
				if($this->has_update()){
					$PRODS = new evo_prods();
					$PRODS->get_remote_prods_data();
				}
			}

		// kriyathmaka karanna
			public function evo_kriyathmaka_karanna(){
				$this->set_prop('status', 'active');
				$this->force_package_update('append');	
			}
			// site eka ethulen withrak kriyathmana karanna
			public function evo_kriyathmaka_karanna_athulen(){
				$this->set_prop('status', 'active');
				$this->set_prop('remote_validity', 'local');
			}

	// ADDON license SUBCRIPTIONS		
		function has_valid_subscription(){
			if( $this->kriyathmakada() ){
				$next_payment = $this->get_prop('next_payment');
				if($next_payment ){
					if( EVO()->calendar->utc_time < $next_payment  ){
						return true;
					}
				}

				// if next payment is past deactivate and check for validation
				$this->deactivate();
				$result = $this->verify_active_subscription();

				if(isset($result['status']) && $result['status'] == 'good') return true;
			}
			
			return false;
		}

		// check from eventon server whether the eventon addon has a valid active subscription
		function verify_active_subscription(){
			$key = $this->get_prop('key');

			if( !$key) return false;
			
			$data = array();
			$data['key'] = $key;
			$data['request'] = 'verify_subscription';

			$output = array(	'error_code'=> 150, 'status'=>'bad'	);

			$url = $this->subscription_api_url($data);
		
			$response = wp_remote_get( $url);
				
			if ( is_wp_error( $response ) ){
				$output['error_code'] = 23; 
				$this->record(23,$data['request'], $result->get_error_message());
				return $output;
			}

			if ( $response['response']['code'] !== 200 ) {
				$output['error_code'] = 21;
				$this->record(21,$data['request']);
				return $output;
			}

			//$json = json_decode( wp_remote_retrieve_body( $response['body'] ) );
			$json = json_decode( $response['body'] ,true );

			if ( empty($json) || !$json || !isset($json['status'])){
				$output['error_code'] = 30; 
				$this->record(30,$data['request']);
				return $output;
			}

			if (  $json['status'] == 'bad' ){
				$output['error_remote_var'] = $json['error_var'];				
				$output['error_code'] = $json['code']; 
				$this->record($json['code'],$data['request']);
				return $output;
			}

			if(  $json['status'] == 'inactive' ){
				$output['error_code'] = 151; 
				$this->record(151,$data['request'], (isset($json['error_var'])? $json['error_var']:''));
				if(isset($json['error_var'])) $output['error_remote_var'] = $json['error_var'];	
				return $output;
			}

			if(  $json['status'] == 'active' ){
				$output['status'] = 'good';
				$this->record(155,$data['request'], EVO_Error()->error_code( 155 ));

				if( isset($json['next_payment'])){
					$this->set_prop('next_payment',$json['next_payment'] );
				}
				$this->set_prop('remote_validity','valid' );
				$this->evo_kriyathmaka_karanna();
			}	

			// output include
			// status, error_code, error_remote_var
			return $output;
		}

		function remote_deactivate_subscription(){
			$output = array();

			$data = array();
			$data['key'] = $this->get_prop('key');
			$data['request'] = 'deactivate_subscription';

			$output = array();
			$output['error_code'] = 150;
			$output['status'] = 'bad';

			$url = $this->subscription_api_url($data);
			$output['url'] = $url;

			$request = wp_remote_get($url);

			if( is_wp_error($request)){
				$output['error_code'] = 161; return $output;
			}
			if($request['response']['code'] !==200){
				$output['error_code'] = 161; return $output;
			}
			
			$json = json_decode( $request['body'] ,true );

			if ( empty($json) || !$json || !isset($json['status'])){
				$output['error_code'] = 161; 
				$this->record(161,$data['request']);
				return $output;
			}

			if (  $json['status'] == 'bad' ){
				$output['error_code'] = 161; 
				$this->record($json['code'],$data['request']);
				return $output;
			}

			if(  $json['status'] == 'inactive' || $json['status'] == 'good' ){
				$output['status'] = 'good';
				$output['error_code'] = 162; 
				$this->record(162,$data['request'], EVO_Error()->error_code( 162 ));
			}	

			return $output;
		}

		function subscription_api_url($data){
			$instance = base64_encode(get_site_url());				
			return $this->subscription_api_url_base() . 'request=' . $data['request'] .'&key='. $data['key'] .'&instance=' . $instance ;
		}
		function subscription_api_url_base(){
			//return 'http://localhost/EVO/wp-json/ajde/evo-subscription?';
			return 'http://www.myeventon.com/wp-json/ajde/evo-subscription?';
		}
		private function record($code, $task,$data=''){
			EVO_Error()->record_gen_log($task, $this->slug, $code, $data );
		}

	
}