<?php

class WPO_Updater {
	
	private $wpo_update_api;
	private $plugin_item_name;
	private $plugin_file;
	private $plugin_license_slug;
	private $plugin_version;
	private $plugin_author;
	private $license_key;
	private $edd_updater;
	
	public function __construct( $_item_name, $_file, $_license_slug, $_version, $_author ) {
		$this->wpo_update_api		= apply_filters( 'wpovernight_api_url', 'https://wpovernight.com/license-api/' );
		$this->plugin_item_name		= $_item_name;
		$this->plugin_file			= $_file;
		$this->plugin_license_slug	= $_license_slug;
		$this->plugin_version		= $_version;
		$this->plugin_author		= $_author;

		$wpo_license_keys = get_option('wpocore_settings', array());
		$this->license_key = isset($wpo_license_keys[$this->plugin_license_slug]) ? trim($wpo_license_keys[$this->plugin_license_slug]) : '';
		
		if( !class_exists( '\\WPO\\EDD_SL_Plugin_Updater' ) ) {
			// load the EDD updater class
			include( dirname( __FILE__ ) . '/EDD_SL_Plugin_Updater.php' );
		}

		$this->load_edd_updater();

		add_filter( 'wpocore_licenses_general', array( $this, 'add_license' ));
		add_filter( 'wpocore_license_check_'.$this->plugin_license_slug, array( $this, 'check_license' ), 10, 1 );
		add_action( 'wp_ajax_wpo_sidekick_licence_key_action_'.$this->plugin_license_slug, array($this, 'remote_license_actions' ));
		add_filter( 'http_response', array( $this, 'unauthorized_response'), 10, 3 );
	}

	public function license_is_active() {
		if( empty($this->license_key) ) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * Register License settings
	 */
	public function add_license( $settings ) {
		$plugin_settings = array(
			$this->plugin_license_slug => array(
				'id' => $this->plugin_license_slug,
				'name' => $this->plugin_item_name, // currently not translated, this would require passing an additional paramter because the item_name has to correspond to the updater item name
				'desc' => __( '', 'wpovernight-sidekick' ),
				'type' => 'text',
				'size' => 'regular',
				'std'  => ''
			)
		);

		return array_merge( $settings, $plugin_settings );
	}
	
	/**
	 * Load the EDD Updater class
	 */
	public function load_edd_updater() {
		// get license key
		if ($this->plugin_item_name == 'WP Overnight Sidekick' ) {
			// sidekick license key hardcoded!
			$license_key = 'b945b2e6a0ef88d5cb4b57e38ae97add';
		} else {
			// get license key from settings db if entered
			$license_key = isset($this->license_key) ? $this->license_key : '';
		}

		// fix wrong file locations
		$file_remap = array (
			'WC Bulk Order Form – Prepopulated' => defined('BOF_PP_FILE') ? BOF_PP_FILE : '',
		);

		if (!empty($file_remap[$this->plugin_item_name])) {
			$this->plugin_file = $file_remap[$this->plugin_item_name];
		}

		// setup the updater
		if (!empty($license_key)) {
			$this->edd_updater = new \WPO\EDD_SL_Plugin_Updater( $this->wpo_update_api, $this->plugin_file, array( 
					'version' 	=> $this->plugin_version,	// current version number
					'license' 	=> $license_key, 			// license key (used get_option above to retrieve from DB)
					'item_name' => $this->plugin_item_name, // name of this plugin
					'author' 	=> $this->plugin_author  	// author of this plugin
				)
			);
		}
	}

	public function check_license() {
		if ( !empty( $this->license_key ) ) {
			// data to send in our API request
			$api_params = array( 
				'edd_action'=> 'check_license', 
				'license' 	=> $this->license_key, 
				'item_name' => urlencode( $this->plugin_item_name ), // the name of our product in EDD
			);
			$response = $this->edd_api_action( $api_params );
			return $response;
		};
	}

	/************************************
	* Activate/deactivate license key
	*************************************/

	public function remote_license_actions() {

		check_ajax_referer( "generate_wpo_sidekick", 'security' );

		if (empty($_POST['remote_edd_action']) || empty($_POST['license_key'])) {
			return;
		}

		// retrieve the license from the database
		$wpocore_settings = get_option('wpocore_settings');
		$wpocore_settings[$this->plugin_license_slug] = $license = $_POST['license_key'];
		update_option( 'wpocore_settings', $wpocore_settings );
 
		// data to send in our API request
		$api_params = array( 
			'edd_action' => $_POST['remote_edd_action'], 
			'license'    => $_POST['license_key'], 
			'item_name'  => urlencode( $this->plugin_item_name ), // the name of our product in EDD
			'url'        => home_url(), // License server has a fallback to the User-Agent, but this could have been filtered so we can't rely on it
		);

		$response = $this->edd_api_action( $api_params );

		if (isset($response->wp_error)) {
			/* translators: 1. error message, 2. error code, 3. host IP  */
			$message = sprintf( __( 'API Error: %1$s (%2$s), IP: %3$s', 'wpovernight-sidekick' ), $response->wp_error, $response->error_code, $this->get_host_ip() );
			$response->action_message = $message;
			$response->license_state = 'incomplete';
			$response->license_state_message = __( 'unknown', 'wpovernight-sidekick' );
			$response->license_info = '-';
			echo json_encode($response);
			die();
		}
		
		// activate or deactivate
		if (in_array($_POST['remote_edd_action'], array('activate_license','deactivate_license'))) {
			update_option( $this->plugin_license_slug, $response );
		}

		if (isset($response->expires)) {
			if ( $response->expires == 'lifetime') {
				$exp_date = __( 'Forever', 'wpovernight-sidekick' );
			} else {
				$exp_date = date_i18n( get_option( 'date_format' ), strtotime($response->expires));
			}
		}

		switch ( $response->license ) {
			case 'valid':
				$response->action_message = __( 'Activated your license for this site.', 'wpovernight-sidekick' );
				$response->license_state = 'valid';
				$response->license_state_message = __( 'valid', 'wpovernight-sidekick' );
				/* translators: 1. expiration date, 2. active sites count, 3. license limit count  */
				$response->license_info = sprintf( __( 'This license is valid until: %1$s (Active sites: %2$s / %3$s)', 'wpovernight-sidekick' ), $exp_date, $response->site_count, $response->license_limit);
				break;
			case 'deactivated':
				$response->action_message = __( 'Deactivated your license for this site.', 'wpovernight-sidekick' );
				$response->license_state = 'invalid';
				$response->license_state_message = __( 'valid', 'wpovernight-sidekick' );
				// get activation count & limit
				$api_params = array( 
					'edd_action'=> 'check_license', 
					'license' 	=> $_POST['license_key'], 
					'item_name' => urlencode( $this->plugin_item_name ), // the name of our product in EDD
				);
				$check_response = $this->edd_api_action( $api_params );
				$exp_date = date_i18n( get_option( 'date_format' ), strtotime($check_response->expires));
				$license_limit = $check_response->license_limit;
				$site_count = $check_response->site_count;
				$response->license_info = sprintf( __( 'This license is valid until: %1$s (Active sites: %2$s / %3$s)', 'wpovernight-sidekick' ), $exp_date, $site_count, $license_limit);
				break;
			case 'expired':
				$response->license_state = 'invalid';
				$response->license_state_message = __( 'expired', 'wpovernight-sidekick' );	
				$response->license_info = __( 'This license was valid until: ' . $exp_date, 'wpovernight-sidekick' );
				break;
			case 'site_inactive':
				$response->license_state = 'valid';
				$response->license_state_message = __( 'valid', 'wpovernight-sidekick' );
				$response->license_info = sprintf( __( 'This license is valid until: %1$s (Active sites: %2$s / %3$s)', 'wpovernight-sidekick' ), $exp_date,  $response->site_count, $response->license_limit);
				break;
			case 'failed':
				$response->action_message = __( 'Deactivated your license for this site.', 'wpovernight-sidekick' );
				$response->license_state = 'invalid';
				$response->license_state_message = __( 'invalid', 'wpovernight-sidekick' );
				$response->license_info = '';
				break;
			case 'invalid':
				if ($response->error == 'missing') {
					$response->action_message = __( 'Your license key was incorrect.', 'wpovernight-sidekick' );
					$response->license_state = 'incomplete';
					$response->license_state_message = __( 'invalid', 'wpovernight-sidekick' );
					$response->license_info = 	__( 'Please enter the correct license key.', 'wpovernight-sidekick' );
				} elseif ($response->error == 'expired') {
					$response->action_message = __( 'Your license key is expired.', 'wpovernight-sidekick' );
					$response->license_state = 'incomplete';
					$response->license_state_message = __( 'expired', 'wpovernight-sidekick' );
					/* translators: expiration date */
					$response->license_info = sprintf( __( 'This license was valid until: %s', 'wpovernight-sidekick' ), $exp_date );
				} elseif ($response->error == 'no_activations_left') {
					/* translators: <a> tags */
					$response->action_message = sprintf( __( '<strong>No Activations Left</strong> &mdash; Please visit %1$sMy Account%2$s to upgrade your license or deactivate a previous activation.', 'wpovernight-sidekick' ), '<a href="https://wpovernight.com/my-account/" target="_blank">', '</a>' );
					$response->license_state = 'incomplete';
					$response->license_state_message = __( 'invalid', 'wpovernight-sidekick' );
					$response->license_info = '';
				} else {
					$response->action_message = __( 'Please enter the correct license key.', 'wpovernight-sidekick' );
					$response->license_info = '';
					$response->license_state = 'incomplete';
					$response->license_state_message = __( 'invalid', 'wpovernight-sidekick' );
				}
				break;
			default:
				break;
		}

		echo json_encode($response);
		die();
	}

	public function edd_api_action( $api_params ) {
	 
		// Call the custom API.
		$response = wp_remote_get( esc_url_raw( add_query_arg( $api_params, $this->wpo_update_api ) ), array( 'timeout' => 15, 'sslverify' => true ) );

 		// file_put_contents( dirname(dirname(__FILE__)) .'/request.txt', esc_url( add_query_arg( $api_params, $this->wpo_update_api ) ) ); // API debugging
 		// file_put_contents( dirname(dirname(__FILE__)) .'/response.txt', print_r($response,true)); // API debugging

		// make sure the response came back okay
		if ( is_wp_error( $response ) ) {
			$error_response = new stdClass();
			$error_response->wp_error = $response->get_error_message();
			$error_response->error_code = $response->get_error_code();
			return $error_response;
		}
		if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
			$error_response = new stdClass();
			$error_body = wp_remote_retrieve_body( $response );
			if ( strpos($error_body, 'Wordfence') !== false ) {
				$error_response->wp_error = 'Your site host is blocked by the Wordfence network, please contact support@wpovernight.com with this error message.';
			} else {
				$error_response->wp_error = esc_html( sanitize_text_field( strip_tags( $error_body ) ) );
			}
			
			$error_response->error_code = wp_remote_retrieve_response_code( $response );
			return $error_response;
		}
		// decode the license data
		$response = json_decode( wp_remote_retrieve_body( $response ) );

		return $response;
	}


	public function unauthorized_response($response, $args, $url) {
		if ( ! is_wp_error($response) && is_array($response) && isset($response['response']) && is_array($response['response']) ) {
			if (isset($response['response']['code']) && $response['response']['code'] == 401 ) {
				// we have a 401 response, check if it's ours
				$license_server = 'https://wpovernight.com';
				if (strpos($url, $license_server) !== false && strpos($url, 'package_download') !== false) {
					// this is our request

					// extract values from token
					$url_parts = parse_url( $url );
					$paths     = array_values( explode( '/', $url_parts['path'] ) );
					$token  = end( $paths );
					$values = explode( ':', base64_decode( $token ) );
					if ( count( $values ) !== 6 ) {
						$response['response']['message'] = __( 'Invalid token supplied', 'wpovernight-sidekick' );
						return $response;
					}
					$expires        = $values[0];
					$license_key    = $values[1];
					$download_id    = (int) $values[2];
					$url            = str_replace( '@', ':', $values[4] );
					$download_beta  = (bool) $values[5];

					// Check_license response with the above vars
					// data to send in our API request
					$api_params = array(
						'edd_action' => 'check_license',
						'url'		=> $url,
						'license' 	=> $license_key, 
						'item_id'	=> $download_id,
					);

					if ( $check_response = $this->edd_api_action( $api_params ) ) {
						if ( isset($check_response->license) ) {
							switch( $check_response->license ) {
								case 'expired':
									$message = __( 'Your license has expired, please renew it to install this update.', 'wpovernight-sidekick' );
									break;
								case 'inactive':
								case 'site_inactive':
									/* translators: site URL */
									$message = sprintf( __( 'Your license has not been activated for this site (%s), please activate it first.', 'wpovernight-sidekick' ), str_replace( array('http://','https://'), '', $url ) );
									break;
								case 'disabled':
									$message = __( 'Your license has been disabled.', 'wpovernight-sidekick' );
									break;
								case 'valid':
									$message = "";
									break;
								default:
									$message = __( 'Your license could not be validated.', 'wpovernight-sidekick' );
									break;
							}
						} elseif ( isset($check_response->wp_error) ) {
							$message = sprintf( __( 'API Error: %1$s (%2$s), IP: %3$s', 'wpovernight-sidekick' ), $check_response->wp_error, $check_response->error_code, $this->get_host_ip() );
						}
					} else {
						$message = __( 'License key expired or not activated for URL', 'wpovernight-sidekick' );
					}

					$response['response']['message'] = $message;

					return $response;

				}
			}
		}
		return $response;
	}

	public function get_host_ip() {
		$response = wp_remote_get( 'https://icanhazip.com', array( 'timeout' => 15, 'sslverify' => true ) );
		if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
			$ip = __( 'unknown', 'wpovernight-sidekick' );
		} else {
			$ip = wp_remote_retrieve_body( $response );
			// get v4 if we only have v6
			if ( strpos($ip, ':') !== false ) {
				$response = wp_remote_get( 'https://ipv4.icanhazip.com', array( 'timeout' => 15, 'sslverify' => true ) );
				if ( !is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) == 200 ) {
					$ipv4 = wp_remote_retrieve_body( $response );
					$ip = "{$ip} / {$ipv4}";
				}
			}
		}
		return $ip;
	}
}