<?php

/**
 * Work with licenses
 */
class Wpil_License
{
    /**
     * Register services
     */
    public function register()
    {
        add_action('wp_ajax_wpil_license_activate', array(__CLASS__, 'ajax_wpil_license_activate'));
    }

    public static function init()
    {
        if (!empty($_GET['wpil_deactivate']))
        {
            update_option(WPIL_OPTION_LICENSE_STATUS, 'invalid');
            update_option(WPIL_OPTION_LICENSE_LAST_ERROR, $message='Deactivated manually');
        }

        include WP_INTERNAL_LINKING_PLUGIN_DIR . '/templates/wpil_license.php';
    }

    /**
     * Check if license is valid
     *
     * @return bool
     */
    public static function isValid()
    {
        if (get_option('wpil_2_license_status') == 'valid') {
            $prev = get_option('wpil_2_license_check_time');
            $delta = $prev ? time() - strtotime($prev) : 0;

            if (!$prev || $delta > (60*60*24*3) || !empty($_GET['wpil_check_license'])) {
                $license = self::getKey();
                self::check($license, true, self::is_local_url(self::clean_site_url(home_url())));
            }

            $status = get_option('wpil_2_license_status');

            if ($status !== false && $status == 'valid') {
                return true;
            }
        }

        return false;
    }

    /**
     * Get license key
     *
     * @param bool $key
     * @return bool|mixed|void
     */
    public static function getKey($key = false)
    {
        if (empty($key)) {
            if(defined('WPIL_PREMIUM_LICENSE_KEY') && !empty('WPIL_PREMIUM_LICENSE_KEY')){
                $key = WPIL_PREMIUM_LICENSE_KEY;
            }else{
                $key = get_option('wpil_2_license_key');
            }
        }

        if (stristr($key, '-')) {
            $ks = explode('-', $key);
            $key = $ks[1];
        }

        $key = preg_replace('/[^0-9a-z]/', '', $key);
        
        return $key;
    }

    /**
     * Check new license
     *
     * @param $license_key
     * @param $silent
     * @param $activate Should we make and activation call to the home site, or just checke the license?
     * @param bool $silent
     */
    public static function check($license_key, $silent = true, $activate = false)
    {
        $method = ($activate) ? 'activate_license': 'check_license';
        $base_url_path = 'admin.php?page=link_whisper_license';
        
        $license = self::getKey($license_key);
        $code = null;

        // if we're activating the license
        if($activate){
            // clear the item id
            delete_option('wpil_item_id');
            // pull the id directly
            $item_id = self::getItemId($license_key);
            // and update the item id in the options
            update_option('wpil_item_id', $item_id);
        }else{
            $item_id = self::getItemId($license_key);
        }

        if (function_exists('curl_version')) {
            self::curl_check_license($data, $code, $handle, $method, $license, $item_id);
            if(empty($data) || empty($code)){
                self::curl_check_license($data, $code, $handle, $method, $license, $item_id, true);
            }

            // if the curl request failed, try wp_remote_get
            if(empty($code) || $code !== 200){
                $params = [
                    'edd_action' => $method,
                    'license' => $license,
                    'item_id' => $item_id,
                    'url' => urlencode(trim(home_url())),
                ];
                $request = wp_remote_get(WPIL_STORE_URL . '/?' . http_build_query($params));
                $data = wp_remote_retrieve_body($request);
                $code = wp_remote_retrieve_response_code($request);
                if (!empty($data)) {
                    $code = 200;
                }
            }

        } else {
            //CURL is disabled
            $params = [
                'edd_action' => $method,
                'license' => $license,
                'item_id' => $item_id,
                'url' => urlencode(home_url()),
            ];

            $request = wp_remote_get(WPIL_STORE_URL . '/?' . http_build_query($params));
            $data = wp_remote_retrieve_body($request);
            $code = wp_remote_retrieve_response_code($request);
        }

        update_option(WPIL_OPTION_LICENSE_CHECK_TIME, date('c'));

        if(get_option(WPIL_OPTION_LICENSE_STATUS, '') === 'valid' && ($code > 499 && $code < 600 || empty($code) || $code < 200)){
            $redials = get_option('wpil_license_redial', 0);
            if($redials < 10){
                $redials += 1;
                update_option('wpil_license_redial', $redials);
                return;
            }
        }

        if (empty($data) || $code !== 200) {
            $error_message = !empty($handle) ? curl_error($handle) : '';

            if ($error_message) {
                $message = $error_message;
            } else {
                $message = (!empty($code)) ? "$code response code on activation, please try again or check code": __('No response was returned from the activation site, please contact support if this continues', 'wpil');
            }
        } else {
            $license_data = json_decode($data);

            if ($license_data->success === false) {
                $message = self::getMessage($license, $license_data);
            } else {
                update_option(WPIL_OPTION_LICENSE_STATUS, $license_data->license);
                update_option('wpil_license_redial', 0);

                if($license_data->license === 'site_inactive'){
                    update_option(WPIL_OPTION_LICENSE_KEY, '');
                    $base_url = admin_url('admin.php?page=link_whisper_license');
                    $message = __("Site has been disconnected from the previous Link Whisper Subscription.", 'wpil');
                    $redirect = add_query_arg(array('sl_activation' => 'false', 'message' => urlencode($message)), $base_url);
                    update_option(WPIL_OPTION_LICENSE_LAST_ERROR, $message);
                }else{
                    update_option(WPIL_OPTION_LICENSE_KEY, $license);
                    $base_url = admin_url('admin.php?page=link_whisper_settings&licensing');
                    $message = __("License key `%s` was activated", 'wpil');
                    $message = sprintf($message, $license);
                    $redirect = add_query_arg(array('sl_activation' => 'true', 'message' => urlencode($message)), $base_url);
                }

                if (!$silent) {
                    wp_redirect($redirect);
                    exit;
                } else {
                    return;
                }
            }
        }

        if (!empty($handle)) {
            curl_close($handle);
        }

        update_option(WPIL_OPTION_LICENSE_STATUS, 'invalid');
        update_option(WPIL_OPTION_LICENSE_LAST_ERROR, $message);

        if (!$silent) {
            $base_url = admin_url($base_url_path);
            $redirect = add_query_arg(array('sl_activation' => 'false', 'msg' => urlencode($message)), $base_url);
            wp_redirect($redirect);
            exit;
        }
    }

    /**
     * 
     **/
    private static function curl_check_license(&$data, &$code, &$handle, $method, $license, $item_id, $url_call = false){
        if(!empty($handle)){
            curl_close($handle);
        }

        $handle = curl_init();
        curl_setopt($handle, CURLOPT_HEADER, 0);
        curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1);

        if($url_call){
            curl_setopt($handle, CURLOPT_URL, WPIL_STORE_URL);
        }else{
            curl_setopt($handle, CURLOPT_URL, 'https://' . WPIL_STORE_IP);
            curl_setopt($handle, CURLOPT_HTTPHEADER, array(
                "Host: linkwhisper.com"
            ));
        }

        curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($handle, CURLOPT_USERAGENT, WPIL_DATA_USER_AGENT);
        curl_setopt($handle, CURLOPT_POST, 1);
        curl_setopt($handle, CURLOPT_POSTFIELDS, "edd_action={$method}&license={$license}&item_id={$item_id}&url=".urlencode(trim(home_url())));

        $data = curl_exec($handle);
        $code = curl_getinfo($handle, CURLINFO_HTTP_CODE);
    }

    /**
     * Check if a given site is licensed in the same plan as this site.
     *
     * @param string $site_url The url of the site we want to check.
     * @return bool
     */
    public static function check_site_license($site_url = '')
    {
        if(empty($site_url)){
            return false;
        }

        // if the site has been recently checked and does have a valid license
        if(self::check_cached_site_licenses($site_url)){
            // return true
            return true;
        }

        $license_key = self::getKey();
        $item_id = self::getItemId($license_key);
        $license = self::getKey($license_key);
        $code = null;

        if (function_exists('curl_version')) {
            //CURL is enabled
            self::curl_check_license($data, $code, $handle, 'check_license', $license, $item_id);
            if(empty($data) || empty($code)){
                self::curl_check_license($data, $code, $handle, 'check_license', $license, $item_id, true);
            }

            if (!empty($handle)) {
                curl_close($handle);
            }
        } else {
            //CURL is disabled
            $params = [
                'edd_action' => 'check_license',
                'license' => $license,
                'item_id' => $item_id,
                'url' => urlencode($site_url),
            ];
            $request = wp_remote_get(WPIL_STORE_URL . '/?' . http_build_query($params));
            $data = wp_remote_retrieve_body($request);
            $code = wp_remote_retrieve_response_code($request);
            if (!empty($data)) {
                $code = 200;
            }
        }

        if (empty($data) || $code !== 200) {
            return false;
        } else {
            $license_data = json_decode($data);

            if(isset($license_data->license) && 'valid' === $license_data->license){
                self::update_cached_site_list($site_url);
                return true;
            }
        }

        return false;
    }

    /**
     * Checks a site url against the cached list of known licensed urls.
     * Returns if the site is licensed and has been checked recently
     * 
     * @param string $site_url
     * @return bool
     **/
    public static function check_cached_site_licenses($site_url = ''){
        $site_urls = get_option('wpil_cached_valid_sites', array());

        if(empty($site_urls) || empty($site_url)){
            return false;
        }

        $time = time();
        foreach($site_urls as $url_data){
            if($site_url === $url_data['site_url'] && $time < $url_data['expiration']){
                return true;
            }
        }

        return false;
    }

    /**
     * Updates the cached site list with news of licensed sites.
     * 
     **/
    public static function update_cached_site_list($site_url = ''){
        if(empty($site_url)){
            return false;
        }

        $site_cache = get_option('wpil_cached_valid_sites', array());

        foreach($site_cache as $key => $site_data){
            if($site_data['site_url'] === $site_url){
                unset($site_cache[$key]);
            }
        }

        $site_cache[] = array('site_url' => $site_url, 'expiration' => (time() + (60*60*24*3)) );

        update_option('wpil_cached_valid_sites', $site_cache);
    }

    /**
     * Get current license ID
     *
     * @param string $license_key
     * @return false|string
     */
    public static function getItemId($license_key = '')
    {
        if ($license_key && stristr($license_key, '-')) {
            $ks = explode('-', $license_key);
            return $ks[0];
        }

        $item_id = get_option('wpil_item_id', false);
        if(empty($item_id)){
            $item_id = trim(file_get_contents(dirname(__DIR__) . '/../store-item-id.txt'));
        }

        return $item_id;
    }

    /**
     * Get license message
     *
     * @param $license
     * @param $license_data
     * @return string
     */
    public static function getMessage($license, $license_data)
    {
        switch ($license_data->error) {
            case 'expired' :
                $d = date_i18n(get_option('date_format'), strtotime($license_data->expires, current_time('timestamp')));
                $message = sprintf('Your license key %s expired on %s. Please renew your subscription to continue using Link Whisper.', $license, $d);
                break;

            case 'revoked' :
                $message = 'Your License Key `%s` has been disabled';
                break;

            case 'missing' :
                $message = 'Missing License `%s`';
                break;

            case 'invalid' :
            case 'site_inactive' :
                $message = 'The License Key `%s` is not active for this URL.';
                break;

            case 'item_name_mismatch' :
                $message = 'It appears this License Key (%s) is used for a different product. Please log into your linkwhisper.com user account to find your Link Whisper License Key.';
                break;

            case 'no_activations_left':
                $message = 'The License Key `%s` has reached its activation limit. Please upgrade your subscription to add more sites.';
                break;

            case 'invalid_item_id':
                $message = "The License Key `%s` isn't valid for the installed version of Link Whisper. Fairly often this is caused by a mistake in entering the License Key or after upgrading your Link Whisper subscription. If you've just upgraded your subscription, please delete Link Whisper from your site and download a fresh copy from linkwhisper.com. ";
                break;
    
            default :
                $message = "Error on activation: " . $license_data->error;
                break;
        }

        if (stristr($message, '%s')) {
            $message = sprintf($message, $license);
        }

        return $message;
    }

    /**
     * Activate license
     */
    public static function activate()
    {
        if (!isset($_POST['hidden_action']) || $_POST['hidden_action'] != 'activate_license' || !check_admin_referer('wpil_activate_license_nonce', 'wpil_activate_license_nonce')) {
            return;
        }

        $license = sanitize_text_field(trim($_POST['wpil_license_key']));

        self::check($license, false, true);
    }

    /**
     * Activate license via ajax call
     **/
    public static function ajax_wpil_license_activate(){
        
    }

    /**
     * 
     **/
    public static function get_subscription_version_message(){
        $item_id = self::getItemId();

        $message = __('The installed version of Link Whisper is for ', 'wpil');
        switch ($item_id) {
            case 1720130:
                $message .= __('an AppSumo Subscription', 'wpil');
                break;
            case 4888:
                $message .= __('a 10 Site Subscription', 'wpil');
                break;
            case 4886:
                $message .= __('a 3 Site Subscription', 'wpil');
                break;
            case 4872:
                $message .= __('a 1 Site Subscription', 'wpil');
                break;
            case 14:
                $message .= __('a 50 Site Subscription', 'wpil');
                break;
            case 5221018:
                $message .= __('a 1 Site Subscription (with free trial)', 'wpil');
                break;
            case 5221020:
                $message .= __('a 3 Site Subscription (with free trial)', 'wpil');
                break;
            case 5221022:
                $message .= __('a 10 Site Subscription (with free trial)', 'wpil');
                break;
            case 5221024:
                $message .= __('a 50 Site Subscription (with free trial)', 'wpil');
                break;
            default:
                $message = '';
                break;
        }

        return $message;
    }

        
    /**
     * Lowercases site URLs, strips HTTP protocols and strips www subdomains.
     * Borrowed from EDD and heavily modified
     * 
     * @param string $url
     *
     * @return string
     */
    private static function clean_site_url($url){
        $url = strtolower($url);
        // strip www subdomain
        $url = str_replace(array( '://www.', ':/www.' ), '://', $url);
        $url = str_replace(array( 'http://', 'https://', 'http:/', 'https:/' ), '', $url);
        $port = parse_url($url, PHP_URL_PORT);
        // strip port number
        $url = str_replace(':' . $port, '', $url);

        return $url;
    }

    /**
     * Check if a URL is considered a local one.
     * Borrowed from EDD and heavily modified
     *
     * @since  3.2.7
     *
     * @param string $url A URL that possibly represents a local environment.
     *
     * @return boolean If we're considering the URL local or not
     */
    private static function is_local_url($url = ''){
        $is_local_url = false;

        // Trim it up
        $url = strtolower(trim($url));

        // Need to get the host...so let's add the scheme so we can use parse_url
        if(false === strpos( $url, 'http://') && false === strpos($url, 'https://')){
            $url = 'http://' . $url;
        }

        $url_parts = parse_url($url);
        $host      = !empty($url_parts['host']) ? $url_parts['host'] : false;

        if (!empty($url) && !empty($host)){

            if(false !== ip2long($host)){
                if (!filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)){
                    $is_local_url = true;
                }
            }else if('localhost' === $host){
                $is_local_url = true;
            }

            if(!$is_local_url){
                $tlds_to_check = array(
                    '.dev', 
                    '.local', 
                    '.test',
                    '.sg-host.com',
                    '.go-vip.net',
                    '.go-vip.co',
                    '.docksal.site',
                    '.staging.onrocket.site',
                    '.azurewebsites.net',
                );

                foreach($tlds_to_check as $tld){
                    if(false !== strpos($host, $tld)){
                        $is_local_url = true;
                        continue;
                    }
                }
            }

            if(!$is_local_url && substr_count($host, '.') > 1){
                $subdomains_to_check = array(
                    'dev.',
                    '*.staging.',
                    '*.test.',
                    'staging-*.',
                    '*.wpengine.com',
                    'stage.',
                    'wp.',
                    '*staging*.wpengine.com', 
                    '*stage*.wpengine.com', 
                    'woocommerce-*.cloudwaysapps.com', 
                    'wordpress-*.cloudwaysapps.com',
                    'www-dev.',
                    'test.',
                    '*staging.',
                    '*.sg-host.com',
                    'stg.',
                    'webdev.'
                );

                foreach($subdomains_to_check as $subdomain){

                    $subdomain = str_replace('.', '(.)', $subdomain);
                    $subdomain = str_replace(array( '*', '(.)' ), '(.*)', $subdomain);

                    if(preg_match('/^(' . $subdomain . ')/', $host)){
                        $is_local_url = true;
                        break;
                    }
                }
            }
        }

        return $is_local_url;
    }
}
