<?php
/**
 * Handle the add-on license and updates.
 *
 * @author Tijmen Smit
 * @since  2.1.0
 */

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

class WPSL_License_Manager {
    
    public $item_name;
    public $item_shortname;
    public $version;
    public $author;
    public $file;
    public $api_url = 'https://wpstorelocator.co/';
    
    /**
	 * Class constructor
	 *
	 * @param string  $item_name
	 * @param string  $version
	 * @param string  $author
	 * @param string  $file
	 */
    function __construct( $item_name, $version, $author, $file  ) {

        $this->item_name      = $item_name;
		$this->item_shortname = 'wpsl_' . preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->item_name ) ) );
		$this->version        = $version;
        $this->author         = $author;
		$this->file           = $file;
        
        $this->includes();

        add_action( 'admin_init',            array( $this, 'auto_updater' ), 0 );
        add_action( 'admin_init',            array( $this, 'license_actions' ) );
        add_filter( 'wpsl_license_settings', array( $this, 'add_license_field' ), 1 );
	}
    
   /**
	 * Include the updater class
	 *
     * @since 2.1.0
	 * @access  private
	 * @return  void
	 */
	private function includes() {
		if ( !class_exists( 'EDD_SL_Plugin_Updater' ) ) {
            require_once 'EDD_SL_Plugin_Updater.php';
        }
	}
    
    /**
     * Handle the add-on updates.
     * 
     * @since 2.1.0
     * @return void
     */
    public function auto_updater() {

        if ( $this->get_license_option( 'status' ) !== 'valid' ) {
			return;
		}

		$args = array(
			'version'   => $this->version,
			'license'   => $this->get_license_option( 'key' ),
			'author'    => $this->author,
            'item_name' => $this->item_name
		);

		// Setup the updater.
		$edd_updater = new EDD_SL_Plugin_Updater(
			$this->api_url,
			$this->file,
			$args
		);    
    }
    
    /**
     * Check which license actions to take.
     * 
     * @since  2.1.0
     * @return void
     */
    public function license_actions() {

    	if ( !isset( $_POST['wpsl_licenses'] ) ) {
            return;
        }

		if ( !isset( $_POST['wpsl_licenses'][ $this->item_shortname ] ) || empty( $_POST['wpsl_licenses'][ $this->item_shortname ] ) ) {
			return;
        }
        
        if ( !check_admin_referer( $this->item_shortname . '_license-nonce', $this->item_shortname . '_license-nonce' ) ) {
            return;
        }

        if ( !current_user_can( 'manage_wpsl_settings' ) ) {
            return;
        }
        
        if ( isset( $_POST[ $this->item_shortname . '_license_key_deactivate' ] ) ) {
            $this->deactivate_license();
        } else {
            $this->activate_license();
        }
    }

    /**
     * Try to activate the license key.
     * 
     * @since  2.1.0
     * @return void
     */
    public function activate_license() {
    
        // Stop if the current license is already active. 
        if ( $this->get_license_option( 'status' ) == 'valid' ) {
			return;
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verification is done in process_license_form() before this method is called
        $license = isset( $_POST['wpsl_licenses'][ $this->item_shortname ] ) ? sanitize_text_field( wp_unslash( $_POST['wpsl_licenses'][ $this->item_shortname ] ) ) : '';

		// data to send in our API request.
		$api_params = array(
			'edd_action' => 'activate_license',
			'license' 	 => $license,
			'item_name'  => urlencode( $this->item_name ),
			'url'        => home_url()
		);

        // Get the license data from the API.
		$license_data = $this->call_license_api( $api_params );

        if ( $license_data ) {
            update_option(
                $this->item_shortname . '_license_data',
                array(
                    'key'        => $license,
                    'expiration' => $license_data->expires,
                    'status'     => $license_data->license
                )
            );

            if ( $license_data->success ) {
                $this->set_license_notice( $this->item_name . ' license activated.', 'updated' );
            } else if ( !empty( $license_data->error ) ) {
                $this->handle_activation_errors( $license_data->error );
            }
        }
    }

    /**
     * Deactivate the license key.
     * 
     * @since  2.1.0
     * @return void
     */    
    public function deactivate_license() {

        // Data to send to the API
        $api_params = array(
            'edd_action' => 'deactivate_license',
            'license'    => $this->get_license_option( 'key' ),
            'item_name'  => urlencode( $this->item_name ),
            'url'        => home_url()
        );

        // Get the license data from the API.
		$license_data = $this->call_license_api( $api_params );
        
        if ( $license_data ) {
            if ( $license_data->license == 'deactivated' ) {
                delete_option( $this->item_shortname . '_license_data' );    
                
                $this->set_license_notice( $this->item_name . ' license deactivated.', 'updated' );
            } else {
                /* translators: %s: add-on name */
                $message = sprintf (__( 'The %s license failed to deactivate, please try again later or contact support!', 'wp-store-locator' ), $this->item_name );
                $this->set_license_notice( $message, 'error' );
            }
        }     
    }
    
    /**
     * Access the license API.
     * 
     * @since  2.1.0
     * @params array      $api_params   The used API parameters
     * @return void|array $license_data The returned license data on success
     */     
    public function call_license_api( $api_params ) {
        
        $response = wp_remote_post(
			$this->api_url,
			array(
				'timeout'   => 15,
				'sslverify' => false,
				'body'      => $api_params
			)
		);

		// Make sure the response came back okay.
		if ( is_wp_error( $response ) ) {
            $message = $response->get_error_message() . '. ' . __( 'Please try again later!', 'wp-store-locator' );
            $this->set_license_notice( $message, 'error' );
        } else {
            $license_data = json_decode( wp_remote_retrieve_body( $response ) );        

            return $license_data;
        }
    }    

    /**
     * Get a single license option.
     * 
     * @since 2.1.0
     * @param string        $option Name of the license option.
     * @return void|string          The value for the license option.
     */ 
    public function get_license_option( $option ) {
        
        $license_data = get_option( $this->item_shortname . '_license_data' ); 
        
        if ( isset( $license_data[ $option ] ) ) {
            return $license_data[ $option ];   
        }
    }

    /**
     * Set a notice holding license information.
     *
     * @since 2.1.0
     * @param string $message The license message to display.
     * @param string $type    Either updated or error.
     * @return void
     */
    public function set_license_notice( $message, $type ) {
        add_settings_error( $this->item_shortname . '-license', 'license-notice', $message, $type );
    }

    /**
     * Check the different license activation errors.
     * 
     * @since 2.1.0
     * @param string $activation_errors The activation errors returned by the license API.
     * @return void
     */     
    public function handle_activation_errors( $activation_errors ) {

        switch ( $activation_errors ) {
            case 'item_name_mismatch':
                /* translators: %s: add-on name */
                $error_msg = sprintf( __( 'The %s license key does not belong to this add-on.', 'wp-store-locator' ), $this->item_name );
                break;
            case 'no_activations_left':
                /* translators: %s: add-on name */
                $error_msg = sprintf( __( 'The %s license key does not have any activations left.', 'wp-store-locator' ), $this->item_name );
                break;
            case 'expired':
                /* translators: %s: add-on name */
                $error_msg = sprintf( __( 'The %s license key is expired. Please renew it.', 'wp-store-locator' ), $this->item_name );
                break;
            default:
                /* translators: %1$s: add-on name, %2$s: error code */
                $error_msg = sprintf( __( 'There was a problem activating the license key for the %1$s, please try again or contact support. Error code: %2$s', 'wp-store-locator' ), $this->item_name, $activation_errors );
                break;
        }

        $this->set_license_notice( $error_msg, 'error' );
    }
        
    /**
     * Add license fields to the settings.
     * 
     * @since  2.1.0
     * @param  array $settings The existing settings.
     * @return array
     */
	public function add_license_field( $settings ) {
        
		$license_setting = array(
			array(
                'name'       => $this->item_name,
				'short_name' => $this->item_shortname,
                'status'     => $this->get_license_option( 'status' ),
                'key'        => $this->get_license_option( 'key' ),
                'expiration' => $this->get_license_option( 'expiration' )
			)
		);

		return array_merge( $settings, $license_setting );
	}
}