<?php

namespace KaliForms\Inc\Utils;

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

use KaliForms\Inc\Backend\Notifications\Notification;

class KaliForms_Store
{
	/**
	 * Currend endpoint
	 *
	 * @var string
	 */
	public $api_url = 'https://www.kaliforms.com/';
	/**
	 * Plugin slug
	 *
	 * @var string
	 */
	public $slug = 'kaliforms-pro';
	/**
	 * Parent plugin slug
	 *
	 * @var string
	 */
	public $parent_slug = 'kaliforms';
	/**
	 * Known extensions
	 *
	 * @var array
	 */
	public $known_extensions = [];
	/**
	 * Extensions
	 *
	 * @var array
	 */
	public $extensions = [];
	/**
	 * Class constructor
	 */
	public function __construct()
	{
		add_action('admin_init', [$this, 'check_license']);
		add_action('admin_init', [$this, 'updater'], 0);

		$actions = $this->allowed_actions();
		$this->_register_allowed_actions($actions);

		add_filter($this->parent_slug . '_hook_external_notifications', [$this, '_register_global_notifications']);
	}
	/**
	 * Returns an instance of the plugin
	 *
	 * @return KaliForms_Store
	 */
	public static function get_instance()
	{
		static $inst;
		if (!$inst) {
			$inst = new KaliForms_Store();
		}

		return $inst;
	}
	/**
	 * Register allowed actions
	 *
	 * @param [type] $actions
	 * @return void
	 */
	protected function _register_allowed_actions($actions)
	{
		foreach ($actions['strict'] as $action) {
			if (!method_exists($this, $action)) {
				continue;
			}

			add_action(
				'wp_ajax_' . $this->parent_slug . '_' . $action,
				[$this, $action]
			);

			add_action(
				'wp_ajax_nopriv_' . $this->parent_slug . '_' . $action,
				[$this, 'denied']
			);
		}

		foreach ($actions['public'] as $action) {
			if (!method_exists($this, $action)) {
				continue;
			}

			add_action(
				'wp_ajax_' . $this->parent_slug . '_' . $action,
				[$this, $action]
			);

			add_action(
				'wp_ajax_nopriv_' . $this->parent_slug . '_' . $action,
				[$this, $action]
			);
		}
	}
	/**
	 * Returns a list of allowed actions
	 *
	 * @return array
	 */
	public function allowed_actions()
	{
		return [
			'strict' => [
				'install_plugin_from_store',
				'activate_plugin_from_store',
				'reload_extensions',
				'install_plugin',
				'activate_license_from_store',
				'deactivate_license_from_store',
				'add_master_key',
				'remove_master_key',
				'get_kf_auth',
				'delete_kf_auth',
				'set_old_licensing',
				'update_license_key_manually',
				'check_license_key_manually',
				'get_license_key',
				'activate_license_manually',
				'deactivate_license_manually'
			],
			'public' => [],
		];
	}
	/**
	 *  Deny access
	 */
	public function denied()
	{
		wp_die(esc_html__('Denied', 'kaliforms'));
	}
	/**
	 * Retrieves a list of plugins available for download/install from kali forms
	 *
	 * @return array
	 */
	public function get_needed_plugin_data()
	{
		$this->get_extensions();
		$this->get_installed_plugins();

		return $this->known_extensions;
	}
	/**
	 * Create an array of plugins
	 *
	 * @return void
	 */
	public function get_installed_plugins()
	{
		$this->known_extensions = [
			'kali-forms-pro' => '',
		];

		foreach ($this->extensions as $k => $v) {
			$this->known_extensions[$v['slug']] = '';
		}

		$plugins = get_plugins();
		foreach ($this->known_extensions as $k => $v) {
			$this->known_extensions[$k] = array_key_exists($k . '/' . $k . '.php', $plugins) ? 'installed' : 'not-installed';
			if ($this->known_extensions[$k] === 'installed') {
				$this->known_extensions[$k] = is_plugin_active($k . '/' . $k . '.php') ? 'active' : 'installed';
			}
		}
	}
	/**
	 * Gets extensions from the rest API
	 *
	 * @return void
	 */
	public function get_extensions()
	{
		$this->extensions = get_transient($this->slug . '_extensions');
		if (false === $this->extensions) {
			$this->extensions = [];
			$this->get_extensions_request();
		}
	}
	/**
	 * Make the request to our API
	 *
	 * @return void
	 */
	public function get_extensions_request()
	{
		$url      = KALIFORMS_EXTENSIONS_API;
		$response = wp_remote_get($url);

		if (!is_wp_error($response)) {
			$data = json_decode(wp_remote_retrieve_body($response), true);
			if (!empty($data) && is_array($data)) {
				set_transient($this->slug . '_extensions', $data, 2 * DAY_IN_SECONDS);

				$this->extensions = $data;
			}
		}
	}
	/**
	 * Reloads extensions
	 *
	 * @return void
	 */
	public function reload_extensions()
	{
		check_admin_referer('kaliforms_extensions_nonce', 'nonce');
		delete_transient('kaliforms_extensions');
		wp_die(json_encode(['status' => 'ok']));
	}
	/**
	 * Get KF Auth
	 *
	 * @return void
	 */
	public function get_kf_auth()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		$store = KaliForms_Store::get_instance();
		$auth  = $store->get_stored_auth();
		wp_die(json_encode([
			'status'      => 'ok',
			'accessToken' => !empty($auth['access_token']) ? $auth['access_token'] : null,
		]));
	}

	public function delete_kf_auth()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		$store = KaliForms_Store::get_instance();
		$store->deauthenticate();
		wp_die(json_encode([
			'status'      => 'ok',
			'accessToken' => null,
		]));
	}
	public function set_old_licensing()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		update_option('kaliforms_pro_old_licensing', $_POST['old_licensing']);
		wp_die(json_encode(['status' => 'ok']));
	}
	/**
	 * Add master key ( FOR LEGACY PURPOSES )
	 *
	 * @return void
	 */
	public function add_master_key()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		update_option('kaliforms_pro_license_key', wp_unslash($_POST['master_key']));
		update_option('kaliforms_pro_download_id', absint($_POST['download_id']));
		update_option('kaliforms_pro_license_status', 'valid');
		wp_die(json_encode(['status' => 'ok']));
	}
	/**
	 * Remove master key
	 *
	 * @return void
	 */
	public function remove_master_key()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		delete_option('kaliforms_pro_license_key');
		delete_option('kaliforms_pro_license_status');
		delete_option('kaliforms_pro_download_id');
		wp_die(json_encode(['status' => 'ok']));
	}
	/**
	 * Update master key manually
	 *
	 * @return void
	 */
	public function update_license_key_manually()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		update_option('kaliforms_pro_license_key', wp_unslash($_POST['license_key']));
		update_option('kaliforms_pro_license_status', 'waiting');
		wp_die(json_encode(['status' => 'ok']));
	}
	/**
	 * Check license key manually
	 *
	 * @return void
	 */
	public function check_license_key_manually()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		$license_data = $this->check_license_legacy();
		wp_die(json_encode(['data' => $license_data]));
	}
	/**
	 * Activates a license manually
	 *
	 * @return void
	 */
	public function activate_license_manually()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		$license = trim(get_option('kaliforms_pro_license_key'));
		// data to send in our API request
		$api_params = [
			'edd_action' => 'activate_license',
			'license'    => $license,
			'item_id'    => 218, // the name of our product in EDD
			'url'        => home_url(),
		];
		// Call the custom API.
		$response = wp_remote_post($this->api_url, ['timeout' => 15, 'sslverify' => false, 'body' => $api_params]);

		// make sure the response came back okay
		if (is_wp_error($response)) {
			wp_die('error');
		}

		$license_data = json_decode(wp_remote_retrieve_body($response));
		// $license_data->license will be either "valid" or "invalid"
		update_option('kaliforms_pro_license_status', $license_data->license);
		if ('valid' != $license_data->license) {
			wp_die('error');
		}
		wp_die('success');
	}
	/**
	 * Activates a license manually
	 *
	 * @return void
	 */
	public function deactivate_license_manually()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		$license = trim(get_option('kaliforms_pro_license_key'));
		// data to send in our API request
		$api_params = [
			'edd_action' => 'deactivate_license',
			'license'    => $license,
			'item_id'    => 218, // the name of our product in EDD
			'url'        => home_url(),
		];
		// Call the custom API.
		$response = wp_remote_post($this->api_url, ['timeout' => 15, 'sslverify' => false, 'body' => $api_params]);

		// make sure the response came back okay
		if (is_wp_error($response)) {
			wp_die('error');
		}

		$license_data = json_decode(wp_remote_retrieve_body($response));
		// $license_data->license will be either "valid" or "invalid"
		if ('deactivated' != $license_data->license) {
			wp_die('error');
		}
		update_option('kaliforms_pro_license_status', 'waiting');
		wp_die('success');
	}
	/**
	 * Get license key
	 *
	 * @return void
	 */
	public function get_license_key()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		wp_die(json_encode([
			'license_key'    => get_option('kaliforms_pro_license_key', ''),
			'license_status' => get_option('kaliforms_pro_license_status', ''),
		]));
	}
	/**
	 * Returns an activation url that will be used in javascript to activate
	 *
	 * @return void
	 */
	public function activate_plugin_from_store()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		if (!isset($_POST['download'])) {
			wp_die(json_encode(false));
		}
		$_POST['download'] = wp_unslash($_POST['download']);

		$activate_url = $this->_create_plugin_activation_url($_POST['download']);

		wp_die(json_encode(['url' => $activate_url]));
	}
	/**
	 * Creates a plugin activation URL
	 *
	 * @param [type] $name
	 * @return void
	 */
	protected function _create_plugin_activation_url($name)
	{
		$name            = strtolower(str_replace(' ', '-', $name));
		$plugin_basename = $name . '/' . $name . '.php';

		$activate_url = add_query_arg(
			[
				'action'        => 'activate',
				'plugin'        => rawurlencode($plugin_basename),
				'plugin_status' => 'all',
				'paged'         => '1',
				'_wpnonce'      => wp_create_nonce('activate-plugin_' . $plugin_basename),
			],
			admin_url('plugins.php')
		);

		return $activate_url;
	}
	/**
	 * Activates a license from store
	 *
	 * @return void
	 */
	public function activate_license_from_store()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		if (!isset($_POST['subscription'])) {
			wp_die(json_encode(false));
		}
	}
	/**
	 * Deactivates license from store
	 *
	 * @return void
	 */
	public function deactivate_license_from_store()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		if (!isset($_POST['subscription'])) {
			wp_die(json_encode(false));
		}
	}

	/**
	 * Install plugin from store
	 *
	 * @return void
	 */
	public function install_plugin_from_store()
	{
		check_admin_referer('kaliforms_store_nonce', 'nonce');
		$_POST['download_url'] = wp_unslash($_POST['download_url']);

		// Install the addon.
		if (isset($_POST['download_url'])) {
			$download_url = esc_url($_POST['download_url']);
			global $hook_suffix;
			// Let only plugins from our site.
			if (0 !== strpos($download_url, 'https://kaliforms.com')) {
				// Send back a response.
				wp_die(json_encode(false));
			}

			// Set the current screen to avoid undefined notices.
			set_current_screen();

			// We do not need any extra credentials if we have gotten this far, so let's install the plugin.
			require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';

			// Create the plugin upgrader with our custom skin.
			$installer = new \Plugin_Upgrader();
			$installer->install($download_url);

			// Flush the cache and return the newly installed plugin basename.
			wp_cache_flush();
			if ($installer->plugin_info()) {
				$plugin_basename = $installer->plugin_info();
				$activate_url    = add_query_arg(
					[
						'action'        => 'activate',
						'plugin'        => rawurlencode($plugin_basename),
						'plugin_status' => 'all',
						'paged'         => '1',
						'_wpnonce'      => wp_create_nonce('activate-plugin_' . $plugin_basename),
					],
					admin_url('plugins.php')
				);

				wp_die(json_encode([
					'plugin'       => $plugin_basename,
					'activate_url' => $activate_url,
				]));
			}
		}

		wp_die(json_encode(false));
	}

	/**
	 * Installs plugin
	 * @deprecated - everything will be moved to install_plugin_from_store
	 * @return void
	 */
	public function install_plugin()
	{
		check_admin_referer('kaliforms_extensions_nonce', 'nonce');

		// Install the addon.
		if (isset($_POST['download_url'])) {
			$download_url = esc_url($_POST['download_url']);
			global $hook_suffix;
			// Let only plugins from our site.
			if (0 !== strpos($download_url, 'https://kaliforms.com')) {
				// Send back a response.
				wp_die(json_encode(false));
			}

			// Set the current screen to avoid undefined notices.
			set_current_screen();

			// We do not need any extra credentials if we have gotten this far, so let's install the plugin.
			require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';

			// Create the plugin upgrader with our custom skin.
			$installer = new \Plugin_Upgrader();
			$installer->install($download_url);

			// Flush the cache and return the newly installed plugin basename.
			wp_cache_flush();
			if ($installer->plugin_info()) {
				$plugin_basename = $installer->plugin_info();
				$activate_url    = add_query_arg(
					array(
						'action'        => 'activate',
						'plugin'        => rawurlencode($plugin_basename),
						'plugin_status' => 'all',
						'paged'         => '1',
						'_wpnonce'      => wp_create_nonce('activate-plugin_' . $plugin_basename),
					),
					admin_url('plugins.php')
				);

				wp_die(json_encode([
					'plugin'       => $plugin_basename,
					'activate_url' => $activate_url,
				]));
			}
		}

		wp_die(json_encode(false));
	}

	/**
	 * Updater function
	 *
	 * @return void
	 */
	public function updater()
	{
		// retrieve our license key from the DB
		$license = get_option('kaliforms_pro_license_key');
		$status  = get_option('kaliforms_pro_license_status');

		// setup the updater
		new Plugin_Updater(
			$this->api_url,
			KALIFORMS_PRO_PLUGIN_FILE,
			[
				'version' => KALIFORMS_PRO_VERSION,
				'license' => $license,
				'item_id' => 218,
				'author'  => 'Kali Forms',
			],
			[
				'license_status' => $status,
				'admin_page_url' => admin_url('edit.php?post_type=kaliforms_forms&page=kaliforms-license'),
				'purchase_url'   => 'https://www.kaliforms.com/pricing',
				'plugin_title'   => 'Kali Forms Pro',
			]
		);
	}

	/**
	 * Check license action
	 *
	 * @return void
	 */
	public function check_license()
	{
		if (get_transient('kaliforms_pro_license_status_checking')) {
			return;
		}

		$license    = trim(get_option('kaliforms_pro_license_key'));
		$downloadId = get_option('kaliforms_pro_download_id');
		$api_params = [
			'edd_action' => 'check_license',
			'license'    => $license,
			'item_id'    => absint($downloadId),
			'url'        => home_url(),
		];

		// Call the custom API.
		$response = wp_remote_post(
			$this->api_url,
			[
				'timeout'   => 15,
				'sslverify' => false,
				'body'      => $api_params,
			]
		);

		if (is_wp_error($response)) {
			return false;
		}

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

		update_option('kaliforms_pro_license_data', $license_data);
		if ($license_data->license != 'valid') {
			delete_option('kaliforms_pro_license_status');
		}

		// Set to check again in 12 hours
		set_transient(
			'kaliforms_pro_license_status_checking',
			$license_data,
			(60 * 60 * 12)
		);
	}
	public function check_license_legacy()
	{
		if (get_transient('kaliforms_pro_license_status_checking')) {
			return get_transient('kaliforms_pro_license_status_checking');
		}

		$license = trim(get_option('kaliforms_pro_license_key'));

		$api_params = [
			'edd_action' => 'check_license',
			'license'    => $license,
			'item_id'    => 218,
			'url'        => home_url(),
		];

		// Call the custom API.
		$response = wp_remote_post(
			$this->api_url,
			[
				'timeout'   => 15,
				'sslverify' => false,
				'body'      => $api_params,
			]
		);
		if (is_wp_error($response)) {
			return false;
		}

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

		if ($license_data->license !== 'valid') {
			update_option('kaliforms_pro_license_status', 'waiting');
		}

		if ($license_data->license === 'valid') {
			update_option('kaliforms_pro_license_status', 'valid');
		}

		// Set to check again in 12 hours
		set_transient(
			'kaliforms_pro_license_status_checking',
			$license_data,
			(60 * 60 * 12)
		);

		return $license_data;
	}
	/**
	 * Make the actual request
	 *
	 * @param [type] $api_params
	 * @return void
	 */
	public function make_request($api_params)
	{
		$response = wp_remote_post($this->api_url, ['body' => $api_params, 'timeout' => 15, 'sslverify' => false]);
		if (is_wp_error($response)) {
			return false;
		}
		$license_data = json_decode(wp_remote_retrieve_body($response));
		return $license_data;
	}

	/**
	 * When we redirect back to wp backend, it means that we are authenticated.
	 */
	public function authenticate($data)
	{
		update_option($this->parent_slug . '_kf_auth', [
			'access_token'  => $data['access_token'],
			'refresh_token' => $data['refresh_token'],
			'timestamp'     => time(),
		]);
	}
	/**
	 * Removes option from database
	 *
	 * @return void
	 */
	public function deauthenticate()
	{
		delete_option($this->parent_slug . '_kf_auth');
		delete_option($this->parent_slug . '_pro_license_key');
		delete_option($this->parent_slug . '_pro_license_status');
	}
	/**
	 * Refreshes the token
	 *
	 * @param [type] $refresh_token
	 * @return void
	 */
	public function refresh_token($refresh_token, $repeat = true)
	{
		$request = wp_remote_get(
			KALIFORMS_API . 'store/refresh?refresh_token=' . $refresh_token,
			[
				'headers' => [
					'Cache-Control' => 'no-cache',
				],
			]
		);
		$response  = wp_remote_retrieve_body($request);
		$auth_data = json_decode($response, true);

		if ($auth_data === null && $repeat) {
			return $this->refresh_token($refresh_token, false);
		}

		$this->store_auth($auth_data);
		return $auth_data;
	}
	/**
	 * Gets the stored auth array
	 *
	 * @return void
	 */
	public function get_stored_auth()
	{
		$auth = get_option($this->parent_slug . '_kf_auth', false);
		if (!$auth) {
			return [];
		}

		if (time() > $auth['timestamp'] + 3600) {
			if (empty($auth['refresh_token'])) {
				return new \WP_Error('kf_no_refresh_token', esc_html__('Provide a refresh token.', 'kaliforms'));
			}

			$auth = $this->refresh_token($auth['refresh_token']);
		}

		return $auth;
	}
	/**
	 * Stores authentification data
	 *
	 * @param [type] $data
	 * @return void
	 */
	public function store_auth($data)
	{
		if (!isset($data['access_token']) && !isset($data['refresh_token'])) {
			return;
		}
		update_option($this->parent_slug . '_kf_auth', [
			'access_token'  => $data['access_token'],
			'refresh_token' => $data['refresh_token'],
			'timestamp'     => time(),
		]);
	}

	/**
	 * Register global notifications
	 *
	 * @param [type] $notifications
	 * @return void
	 */
	public function _register_global_notifications($notifications)
	{
		$whitelist = [
			'127.0.0.1',
			'::1',
		];
		if (!in_array($_SERVER['REMOTE_ADDR'], $whitelist)) {
			return $notifications;
		}

		$option = get_option('kaliforms_pro_license_status', false);
		if ($option === 'valid') {
			return $notifications;
		}

		$auth = $this->get_stored_auth();
		if (is_wp_error($auth) || empty($auth['access_token'])) {
			$notifications[] = new Notification(
				'plugin_login_needed',
				'info',
				esc_html__('Please authenticate and activate your license of Kali Forms Pro for this website.', 'kaliforms'),
				'redirect',
				admin_url('edit.php?post_type=kaliforms_forms&page=kaliforms-store-auth'),
				false
			);

			return $notifications;
		}

		$notifications[] = new Notification(
			'plugin_license_activation_needed',
			'info',
			esc_html__('Please activate your license of Kali Forms Pro for this website.', 'kaliforms'),
			'redirect',
			admin_url('edit.php?post_type=kaliforms_forms&page=kaliforms-store-auth'),
			false
		);

		return $notifications;
	}
}
