<?php
/**
 * License Handler
 *
 * Handles WP Ultimo activation.
 *
 * @package WP_Ultimo
 * @subpackage License
 * @since 2.0.0
 */

namespace WP_Ultimo;

use WP_Site;
use WP_Ultimo\Dependencies\Psr\Log\LogLevel;

// Exit if accessed directly
defined('ABSPATH') || exit;

/**
 * Handles WP Ultimo activation.
 *
 * @since 2.0.0
 */
class License {

	use \WP_Ultimo\Traits\Singleton;

	/**
	 * The option key used to store the license data.
	 *
	 * @var string
	 */
	protected string $option_key = 'license_key';

	/**
	 * Instantiate the necessary hooks.
	 *
	 * @since 2.0.0
	 * @return void
	 */
	public function init() {
		/*
		 * Register forms for license activation.
		 */
		update_option('WP_ULTIMO_LICENSE_KEY', 'e2eb9ef2bc348ed239b4ad59974c6f51');
		
		$this->register_forms();

		$this->setup_activator();

	} // end init;
 /**
  * Request a support signature to the API.
  *
  * This confirms ownership of the license and allows us
  * to display past conversations with confidence that the
  * customer is who they say they is.
  *
  * @since 2.0.7
  * @return string|\WP_Error
  */
 public function request_support_signature() {

		$signature_url = wu_with_license_key('https://api.wpultimo.com/signature');

		$response = wp_remote_get($signature_url);

		if (is_wp_error($response)) {

			return $response;

		} // end if;

		$body = wp_remote_retrieve_body($response);

		$data = (array) json_decode($body, true);

		$signature = wu_get_isset($data, 'signature', 'no_signature');

		return $signature;

	} // end request_support_signature;

	/**
	 * Registers the form and handler to license activation.
	 *
	 * @since 2.0.0
	 * @return void
	 */
	public function register_forms() {

		if (function_exists('wu_register_form')) {

			add_filter('removable_query_args', array($this, 'add_activation_to_removable_query_list'));

			add_action('load-wp-ultimo_page_wp-ultimo-settings', array($this, 'add_successful_activation_message'));

			wu_register_form('license_activation', array(
				'render'  => array($this, 'render_activation_form'),
				'handler' => array($this, 'handle_activation_form'),
			));

			wu_register_form('license_deactivation', array(
				'render'  => array($this, 'render_deactivation_form'),
				'handler' => array($this, 'handle_deactivation_form'),
			));

		} // end if;

	} // end register_forms;

	/**
	 * Adds our query arg to the removable list.
	 *
	 * @since 2.0.0
	 *
	 * @param array $args The current list of removable query args.
	 * @return array
	 */
	public function add_activation_to_removable_query_list($args) {

		$args[] = 'wp-ultimo-activation';

		return $args;

	} // end add_activation_to_removable_query_list;

	/**
	 * Adds a successful message when activation is successful.
	 *
	 * @since 2.0.0
	 * @return void
	 */
	public function add_successful_activation_message() {

		if (wu_request('wp-ultimo-activation') === 'success') {

			WP_Ultimo()->notices->add(__('WP Ultimo successfully activated!', 'wp-ultimo'), 'success', 'network-admin', false, array());

		} // end if;

	} // end add_successful_activation_message;

	/**
	 * Render the license activation form.
	 *
	 * @since 2.0.0
	 * @return void
	 */
	public function render_activation_form() {

		$fields = array(
			'license_key'   => array(
				'type'        => 'text',
				'title'       => __('Your License Key', 'wp-ultimo'),
				'desc'        => __('Enter your license key here. You received your license key via email when you completed your purchase. Your license key usually starts with "sk_".', 'wp-ultimo'),
				'placeholder' => __('e.g. sk_******************', 'wp-ultimo'),
			),
			'submit_button' => array(
				'type'            => 'submit',
				'title'           => __('Activate', 'wp-ultimo'),
				'placeholder'     => __('Activate', 'wp-ultimo'),
				'value'           => 'save',
				'classes'         => 'button button-primary wu-w-full',
				'wrapper_classes' => 'wu-items-end',
				'html_attr'       => array(
					'v-bind:disabled' => '!confirmed',
				),
			),
		);

		$form = new \WP_Ultimo\UI\Form('total-actions', $fields, array(
			'views'                 => 'admin-pages/fields',
			'classes'               => 'wu-modal-form wu-widget-list wu-striped wu-m-0 wu-mt-0',
			'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-m-0 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid',
		));

		$form->render();

	} // end render_activation_form;

	/**
	 * Handle license activation form submission.
	 *
	 * @since 2.0.0
	 * @return void
	 */
	public function handle_activation_form() {

		$license = License::get_instance();

		$activation_results = $license->activate(wu_request('license_key'));

		if (isset($activation_results->error)) {

			$activation_results = new \WP_Error('error', $activation_results->error);

		} // end if;

		if (is_wp_error($activation_results)) {

			wp_send_json_error($activation_results);

		} // end if;

		wp_send_json_success(array(
			'redirect_url' => add_query_arg('wp-ultimo-activation', 'success', wu_get_current_url()),
		));

	} // end handle_activation_form;

	/**
	 * Render the license activation form.
	 *
	 * @since 2.0.0
	 * @return void
	 */
	public function render_deactivation_form() {

		$fields = array(
			'confirm'       => array(
				'type'      => 'toggle',
				'title'     => __('Confirm the remove of your license key', 'wp-ultimo'),
				'desc'      => __('This action can not be undone.', 'wp-ultimo'),
				'html_attr' => array(
					'v-model' => 'confirmed',
				),
			),
			'submit_button' => array(
				'type'            => 'submit',
				'title'           => __('Remove License', 'wp-ultimo'),
				'value'           => 'save',
				'classes'         => 'button button-primary wu-w-full',
				'wrapper_classes' => 'wu-items-end',
				'html_attr'       => array(
					'v-bind:disabled' => '!confirmed',
				),
			),
		);

		$form = new \WP_Ultimo\UI\Form('total-actions', $fields, array(
			'views'                 => 'admin-pages/fields',
			'classes'               => 'wu-modal-form wu-widget-list wu-striped wu-m-0 wu-mt-0',
			'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-m-0 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid',
			'html_attr'             => array(
				'data-wu-app' => 'true',
				'data-state'  => wu_convert_to_state(array(
					'confirmed' => false,
				)),
			),
		));

		$form->render();

	} // end render_deactivation_form;

	/**
	 * Handle license activation form submission.
	 *
	 * @since 2.0.0
	 * @return void
	 */
	public function handle_deactivation_form() {

		$license = License::get_instance();

		if (!$this->deactivate()) {

			$activation_results = new \WP_Error('error', __('Error deactivating license.', 'wp-ultimo'));

			wp_send_json_error($activation_results);

		} // end if;

		wp_send_json_success(array(
			'redirect_url' => wu_get_current_url(),
		));

	} // end handle_deactivation_form;

	/**
	 * Sets up the activator instance.
	 *
	 * @since 2.0.0
	 * @return void
	 */
	protected function setup_activator() {
		return true;

		if (!defined('WP_ULTIMO_PLUGIN_DIR') || defined('WP_TESTS_MULTISITE')) {

			return;

		} // end if;

		if (!(is_main_site()) && !is_network_admin()) {

			return;

		} // end if;

		if (!$this->allowed() && defined('WP_ULTIMO_LICENSE_KEY') && WP_ULTIMO_LICENSE_KEY) {
			/**
			 * Checks if init has run. If so, delay execution.
			 *
			 * @since 2.0.11
			 */
			$action = did_action('init') ? 'shutdown' : 'init';

			add_action($action, function() {

				$this->activate(WP_ULTIMO_LICENSE_KEY);

			});

		} // end if;

	} // end setup_activator;
 /**
  * Tries to perform a license activation.
  *
  * @since 2.0.0
  *
  * @param string $license_key The customer license key.
  * @return bool|\WP_Error
  */
 public function activate($license_key) {
	 return true;

		if (!$license_key) {

			return new \WP_Error('missing-license', __('License key is required.', 'wp-ultimo'));

		} // end if;

		try {

			$response = $this->license_api_request('/activate', array(
				'license_key'   => $license_key,
				'instance_name' => defined('DOMAIN_CURRENT_SITE') ? DOMAIN_CURRENT_SITE : get_home_url(wu_get_main_site_id()),
			), 'POST');

			if ($response->error) {

				return new \WP_Error('invalid-license', $response->error);

			} // end if;

			wu_save_option($this->option_key, $response);

		} catch (\Throwable $e) {

			wu_log_add('license', $e->getMessage(), LogLevel::ERROR);

			return new \WP_Error('general-error', __('An unexpected error occurred.', 'wp-ultimo'));

		} // end try;

		return true;

	} // end activate;

	/**
	 * Deactivated the current license.
	 *
	 * @since 2.0.11
	 * @return bool
	 */
	public function deactivate(): bool {

		try {

			$license = wu_get_option($this->option_key);

			if (!$license) {

				return false;

			} // end if;

			$response = $this->license_api_request('/deactivate', array(
				'license_key' => $license->secret_key,
				'instance_id' => $license->instance,
			), 'POST');

			wu_save_option($this->option_key, false);

		} catch (\Throwable $e) {

			return false;

		} // end try;

		return true;

	} // end deactivate;

	/**
	 * Checks if this copy of the plugin was activated.
	 *
	 * @since 2.0.0
	 *
	 * @todo: Check if we should use the plan here and if we should use the product ID.
	 *
	 * @param string $plan Plan to check against.
	 * @return bool
	 */
	public function allowed($plan = 'wpultimo') {

		$license = $this->get_license();

		if ($this->get_license() === false) {

			return false;

		} // end if;

		return $license->valid;

	} // end allowed;

	/**
	 * Returns the customer of the current license.
	 *
	 * @since 2.0.0
	 * @return object|false
	 */
	public function get_customer() {

		$license = $this->get_license();

		if ($license === false) {

			return false;

		} // end if;

		return $license->customer;

	} // end get_customer;

	/**
	 * Returns the license object.
	 *
	 * @since 2.0.0
	 * @return object|false
	 */
	public function get_license() {

		$license = wu_get_option($this->option_key, null) ?? $this->get_fs_license();

		if (!$license) {

			return false;

		} // end if;

		if ($license->timestamp + 86400 < time()) {

			try {

				$validated_license = $this->license_api_request('/validate', array(
					'license_key' => $license->secret_key,
					'instance_id' => $license->instance,
				), 'POST');

			} catch (\Throwable $e) {

				wu_log_add('license', $e->getMessage(), LogLevel::ERROR);

				return false;

			} // end try;

			$validated_license->secret_key = $license->secret_key;
			$validated_license->instance   = $license->instance;

			wu_save_option($this->option_key, $validated_license);

			$license = $validated_license;

		} // end if;

		return $license;

	} // end get_license;

	/**
	 * Returns a license based om freemius license.
	 *
	 * @return object|false
	 */
	protected function get_fs_license() {

		$account = get_blog_option(get_main_site_id(), 'fs_accounts');

		if (empty($account) || !isset($account['sites']) || !isset($account['sites']['wp-ultimo'])) {

			return false;

		} // end if;

		$account_site = get_object_vars($account['sites']['wp-ultimo']);
		$license_id   = $account_site['license_id'];
		$fs_accounts  = get_site_option('fs_accounts', array());
		$fs_id        = 2963;

		if (empty($fs_accounts) || !isset($fs_accounts['all_licenses']) || !isset($fs_accounts['all_licenses'][$fs_id])) {

			return false;

		} // end if;

		$licenses = $fs_accounts['all_licenses'][$fs_id];

		foreach ($licenses as $fs_license) {

			$fs_license = get_object_vars($fs_license);

			if ($fs_license['id'] === $license_id) {

				$license = new \stdClass();

				$license->timestamp  = 0;
				$license->secret_key = $fs_license['secret_key'];
				$license->instance   = $fs_license['id'];

				return $license;

			} // end if;

		} // end foreach;

		return false;

	} // end get_fs_license;
 /**
  * Returns the license key used to activate this copy.
  *
  * @since 2.0.0
  * @return string|false
  */
 public function get_license_key() {

		$license = $this->get_license();

		return $license && $license->secret_key ? $license->secret_key : false;

	} // end get_license_key;

	/**
	 * Checks if the white-label mode was activated.
	 *
	 * @since 2.0.0
	 * @return boolean
	 */
	public function is_whitelabel() {

		$license = $this->get_license();

		return $license ? $license->is_whitelabeled : false;

	} // end is_whitelabel;

	/**
	 * Inverse of the is_whitelabel. Used in callbacks.
	 *
	 * @since 2.0.0
	 * @return boolean
	 */
	public function is_not_whitelabel() {

		return !$this->is_whitelabel();

	} // end is_not_whitelabel;
 /**
  * Returns the license key set as constant if it exists.
  *
  * @since 2.0.0
  * @return false|string
  */
 public function has_license_key_defined_as_constant() {

		return defined('WP_ULTIMO_LICENSE_KEY') ? WP_ULTIMO_LICENSE_KEY : false;

	} // end has_license_key_defined_as_constant;

	/**
	 * Sends a request to license API
	 *
	 * @since  2.4.0
	 * @param  string $endpoint Endpoint to send the call to.
	 * @param  array  $data     Array containing the params to the call.
	 * @param  string $method   HTTP method to use.
	 * @return object
	 */
	protected function license_api_request(string $endpoint, array $data, $method = 'GET') {

		$data['version'] = wu_get_isset($data, 'version', wu_get_version());

		$url = 'https://licenses.nextpress.us/api/licenses' . $endpoint;

		$post_fields = array(
			'blocking' => true,
			'timeout'  => 10,
			'method'   => $method,
			'body'     => $data,
			'headers'  => array(
				'Content-Type' => 'application/x-www-form-urlencoded',
				'Accept'       => 'application/json',
			),
		);

		if ($method === 'GET') {

			$url = add_query_arg($data, $url);
			$post_fields['body'] = null;

		} // end if;

		$response = wp_remote_request($url, $post_fields);

		if (is_wp_error($response)) {

			throw new \Exception($response->get_error_message());

		} // end if;

		$body = json_decode(wp_remote_retrieve_body($response));

		if (json_last_error() !== JSON_ERROR_NONE) {

			throw new \Exception(json_last_error_msg());

		} // end if;

		return $this->build_license_from_response($body);

	} // end license_api_request;

	/**
	 * Build a license object from the API response.
	 *
	 * @since 2.4.0
	 *
	 * @param object $response Response from the API.
	 * @return object
	 */
	protected function build_license_from_response(object $response): object {

		$status = array(
			'active',
			'trial',
			'lifetime',
			'golden-ticket',
		);

		$license = new \stdClass();
		$license->is_whitelabeled = false;
		$license->timestamp       = time();
		$license->secret_key      = property_exists($response, 'key') ? $response->key : null;
		$license->valid           = property_exists($response, 'status') ? in_array($response->status, $status, true) : false;
		$license->instance        = property_exists($response, 'instance') ? $response->instance : null;
		$license->error           = property_exists($response, 'error') ? $response->error : null;

		$name = explode(' ', property_exists($response, 'customer') ? $response->customer->name : '', 2);

		$license->customer        = new \stdClass();
		$license->customer->email = property_exists($response, 'customer') ? $response->customer->email : null;
		$license->customer->first = $name[0];
		$license->customer->last  = isset($name[1]) ? $name[1] : '';

		if (!$license->valid) {

			$response->status = property_exists($response, 'status') ? $response->status : null;

			switch ($response->status) {
       case 'expired':
           $license->error = __('License key expired', 'wp-ultimo');
           break;
       case 'limit-quota':
           $license->error = __('License key limit reached', 'wp-ultimo');
           break;
       default:
           $license->error = __('Invalid license key', 'wp-ultimo');
           break;
   }

		} // end if;

		return $license;

	} // end build_license_from_response;

} // end class License;
