<?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 . self::beta_suffix(), 'invalid');
            update_option(WPIL_OPTION_LICENSE_LAST_ERROR . self::beta_suffix(), $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' . self::beta_suffix()) == 'valid') {
            $prev = get_option('wpil_2_license_check_time' . self::beta_suffix());
            $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' . self::beta_suffix());

            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' . self::beta_suffix());
            }
        }

        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 $activate Should we utilize this call JUST to connect the user to our glorious AI system?
     * @param bool $silent
     */
    public static function check($license_key, $silent = true, $activate = false, $ai_connect = false)
    {
        $method = ($activate) ? 'activate_license': 'check_license';
        $base_url_path = 'admin.php?page=link_whisper_license';
        
        $license = self::getKey($license_key);
        $code = null;

        if($ai_connect && Wpil_Settings::has_ai_enabled()){
            return; // exist if we're all ready set!
        }

        // if we're activating the license
        if($activate){
            // clear the item id
            delete_option('wpil_item_id' . self::beta_suffix());
            // pull the id directly
            $item_id = self::getItemId($license_key);
            // and update the item id in the options
            update_option('wpil_item_id' . self::beta_suffix(), $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, true);
            if(empty($data) || empty($code)){
                self::curl_check_license($data, $code, $handle, $method, $license, $item_id);
            }

            // if the curl request failed, try wp_remote_get
            if(empty($code) || $code !== 200){
                $params = self::get_license_request_params($method, $license, $item_id, 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 = self::get_license_request_params($method, $license, $item_id, 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 . self::beta_suffix(), '') === 'valid' && ($code > 499 && $code < 600 || empty($code) || $code < 200)){
            $redials = get_option('wpil_license_redial' . self::beta_suffix(), 0);
            if($redials < 10){
                $redials += 1;
                update_option('wpil_license_redial' . self::beta_suffix(), $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 the response couldn't be processed but the license was good
            if(empty($license_data) && get_option(WPIL_OPTION_LICENSE_STATUS . self::beta_suffix(), '') === 'valid'){
                // check if we're under the redial limit
                $redials = get_option('wpil_license_redial' . self::beta_suffix(), 0);
                if($redials < 10){
                    // if we are, go around again and try later
                    $redials += 1;
                    update_option('wpil_license_redial' . self::beta_suffix(), $redials);
                    return;
                }
            }

            if ($license_data->success === false) {
                $message = self::getMessage($license, $license_data);
            } else {
                update_option(WPIL_OPTION_LICENSE_STATUS . self::beta_suffix(), $license_data->license);
                update_option('wpil_license_redial' . self::beta_suffix(), 0);
                self::store_renewal_date_from_license_data($license_data);
                if($license_data->license === 'site_inactive'){
                    update_option(WPIL_OPTION_LICENSE_KEY . self::beta_suffix(), '');
                    delete_option(self::get_renewal_option_name());
                    $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 . self::beta_suffix(), $message);
                }else{
                    update_option(WPIL_OPTION_LICENSE_KEY . self::beta_suffix(), $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);
                }

                self::store_credit_purchase_data_from_license_data($license_data);

                // if we're activating
                if($activate){
                    // try pushing a data update
                    Wpil_Telemetry::perform_cron_dashboard_update();
                }

                if( !Wpil_Settings::has_ai_enabled() && 
                    ($ai_connect ||
                    !Wpil_AI::has_ai_processed_data() && // and the user hasn't already processed with ai
                    !Wpil_Settings::get_linkwhisper_ai_deactivated()) && // and the user hasn't turned off LW AI!
                    isset($license_data->user_id, $license_data->access_token) && 
                    !empty($license_data->user_id) && 
                    !empty($license_data->access_token) &&
                    (bool) preg_match('/\Aai-[0-9a-f]{64}\z/i', $license_data->access_token) &&
                    (bool) preg_match('/\A[0-9a-f]{32}\z/i', $license_data->user_id)
                ){
                    // save the token to the options
                    update_option('wpil_ai_access_token', Wpil_Toolbox::encrypt($license_data->access_token));
                    // and the user id
                    update_option('wpil_ai_access_user_id', $license_data->user_id);
                    // and the user email
                    update_option('wpil_ai_access_user_email', sanitize_email($license_data->customer_email));
                    // track that the authentication happened
                    Wpil_Telemetry::log_event('linkwhisper_ai_auto_authenticated');
                    // set the provider to us
                    update_option('wpil_select_ai_provider', 'linkwhisper');
                    // and update the flag so we know it's live
                    update_option('wpil_ai_access_authorized', true);
                }

                if (!$silent) {
                    wp_redirect($redirect);
                    exit;
                } else {
                    return;
                }
            }
        }

        if (!empty($handle)) {
            curl_close($handle);
        }

        update_option(WPIL_OPTION_LICENSE_STATUS . self::beta_suffix(), 'invalid');
        update_option(WPIL_OPTION_LICENSE_LAST_ERROR . self::beta_suffix(), $message);
        delete_option(self::get_renewal_option_name());

        // if we're activating
        if($activate){
            // try pushing a data update
            Wpil_Telemetry::perform_cron_dashboard_update();
        }

        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_TIMEOUT, 30); // because some sites keep the connection open indefinitely and just timeout
        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, http_build_query(self::get_license_request_params($method, $license, $item_id, trim(home_url()))));

        $data = curl_exec($handle);
        if(empty(Wpil_Settings::get_linkwhisper_ai_user_email()) && !empty($data) && Wpil_Post::is_json($data)){
            $license_data = json_decode($data);
            if( !empty($license_data) && 
                isset($license_data->customer_email) && !empty($license_data->customer_email) && 
                isset($license_data->item_id) && !empty($license_data->item_id) && (int)$license_data->item_id === 4872 // only for single sites! Multi sites can be clients
            ){
                update_option('wpil_ai_access_user_email', $license_data->customer_email); // customer is the one that would be signing up for ai
            }
        }
        $code = curl_getinfo($handle, CURLINFO_HTTP_CODE);
    }

    private static function get_license_request_params($method, $license, $item_id, $site_url = ''){
        return array(
            'edd_action' => $method,
            'license' => $license,
            'item_id' => $item_id,
            'url' => trim($site_url),
        );
    }

    private static function store_credit_purchase_data_from_license_data($license_data = null){
        if(empty($license_data)){
            return;
        }

        $purchase_data = self::get_credit_purchase_data_from_license_response($license_data);
        if(empty($purchase_data) || !is_array($purchase_data)){
            return;
        }

        foreach($purchase_data as $purchase_time => $purchases){
            $purchase_time = is_numeric($purchase_time) ? (int) $purchase_time : time();
            if(is_object($purchases)){
                $purchases = (array) $purchases;
            }

            if(empty($purchases) || !is_array($purchases)){
                continue;
            }

            foreach($purchases as $purchase){
                if(is_object($purchase)){
                    $purchase = (array) $purchase;
                }

                if(empty($purchase) || !is_array($purchase)){
                    continue;
                }

                $purchase_id = isset($purchase['id']) ? (string) $purchase['id'] : '';
                $credits = isset($purchase['credits']) ? (float) $purchase['credits'] : 0;
                $purchase_type = isset($purchase['type']) ? (string) $purchase['type'] : '';

                if(empty($purchase_id) || $credits <= 0){
                    continue;
                }

                Wpil_AI::save_credit_deposit_notice($purchase_id, $credits, $purchase_type, $purchase_time);
            }
        }
    }

    private static function get_credit_purchase_data_from_license_response($license_data = null){
        if(empty($license_data)){
            return array();
        }

        $keys = array(
            'recent_credit_purchases',
            'credit_purchases',
            'credit_purchase_data',
            'ai_credit_purchases'
        );

        foreach($keys as $key){
            if(isset($license_data->$key) && !empty($license_data->$key)){
                if(is_string($license_data->$key) && Wpil_Post::is_json($license_data->$key)){
                    $decoded = json_decode($license_data->$key, true);
                    if(!empty($decoded) && is_array($decoded)){
                        return $decoded;
                    }
                }

                if(is_object($license_data->$key)){
                    return (array) $license_data->$key;
                }

                if(is_array($license_data->$key)){
                    return $license_data->$key;
                }
            }
        }

        return array();
    }

    /**
     * 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, true);
            if(empty($data) || empty($code)){
                self::curl_check_license($data, $code, $handle, 'check_license', $license, $item_id);
            }

            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 = (is_string($data)) ? json_decode($data): $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' . self::beta_suffix(), 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 (isset($license_data->error) && $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: " . (isset($license_data->error) && !empty($license_data->error)) ? $license_data->error: 'Unknown 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, true, true);

        $status = get_option(WPIL_OPTION_LICENSE_STATUS . self::beta_suffix());

        if($status === 'valid'){
            $message = __('License Activated', 'wpil');
        }else{
            $message = get_option(WPIL_OPTION_LICENSE_LAST_ERROR . self::beta_suffix());
        }

        // get the current licensing state
        if(empty($license) && empty($message) || ('invalid' === $status && 'Deactivated manually' === $message)){
            $licensing_state = 'not_activated';
        }elseif(!empty($license) && 'valid' === $status){
            $licensing_state = 'activated';
        }else{
            $licensing_state = 'error';
        }

        // create titles for the license statuses
        $status_titles   = array(
            'not_activated' => esc_html__('Not Activated', 'wpil'),
            'activated'     => esc_html__('License Active', 'wpil'),
            'error'         => esc_html__('License Error', 'wpil')
        );

        // create some helpful text to tell the user what's going on
        $status_messages = array(
            'not_activated' => (Wpil_License::is_beta() ? esc_html__('Please enter the supplied beta testing license key to activate Link Whisper.', 'wpil') : __('Activate to receive updates, support access, and full feature availability.', 'wpil')),
            'activated'     => (Wpil_License::is_beta() ? esc_html__('Thank You! The Link Whisper License Key has been confirmed and Link Whisper is now active!', 'wpil') : __('Congratulations! Your Link Whisper License Key has been confirmed and Link Whisper is now active!', 'wpil')),
            'error'         => esc_html($message)
        );

        if((defined('DOING_AJAX') && DOING_AJAX)){
            wp_send_json(array('status' => $status, 'message' => $message, 'title' => $status_titles[$licensing_state], 'message_text' => $status_messages[$licensing_state]));
        }
    }

    /**
     * Activate license via ajax call
     **/
    public static function ajax_wpil_license_activate(){
        self::activate();
    }

    /**
     * 
     **/
    public static function get_subscription_version_message(){
        $item_id = self::getItemId();

        if(self::is_beta()){
            return __('The installed version of Link Whisper is a Beta Testing Version.', 'wpil');
        }

        $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;
    }

    /**
     * Option name for persisted renewal date.
     *
     * @return string
     */
    public static function get_renewal_option_name(){
        return 'wpil_license_renewal_date' . self::beta_suffix();
    }

    /**
     * Gets the stored renewal date in Y-m-d H:i:s format.
     *
     * @return string
     */
    public static function get_renewal_date(){
        $date = get_option(self::get_renewal_option_name(), '');
        return is_string($date) ? trim($date) : '';
    }

    /**
     * Returns whole days until renewal date (0 if unknown/expired).
     *
     * @return int
     */
    public static function get_subscription_days_left(){
        $renewal = self::get_renewal_date();
        if(empty($renewal) || self::is_lifetime_membership()){
            return 0;
        }

        $renewal_ts = strtotime($renewal);
        if(empty($renewal_ts)){
            return 0;
        }

        $seconds_left = $renewal_ts - current_time('timestamp', true);
        if($seconds_left <= 0){
            return 0;
        }

        return (int) floor($seconds_left / DAY_IN_SECONDS);
    }

    /**
     * Checks if the stored membership is lifetime.
     *
     * @return bool
     */
    public static function is_lifetime_membership(){
        $renewal = strtolower(trim(self::get_renewal_date()));
        return (!empty($renewal) && false !== strpos($renewal, 'lifetime'));
    }

    /**
     * Saves renewal date from a license API response.
     *
     * @param object $license_data
     * @return void
     */
    private static function store_renewal_date_from_license_data($license_data){
        if(empty($license_data) || !is_object($license_data)){
            return;
        }

        if(!isset($license_data->expires) || !is_string($license_data->expires)){
            return;
        }

        $expires = trim($license_data->expires);
        if(empty($expires)){
            return;
        }

        if(false !== strpos(strtolower($expires), 'lifetime')){
            update_option(self::get_renewal_option_name(), 'lifetime', false);
            return;
        }

        // Check to make sure we have a valid date
        $expiry_time = strtotime($expires);
        if(empty($expiry_time)){
            return;
        }

        update_option(self::get_renewal_option_name(), gmdate('Y-m-d H:i:s', $expiry_time), false);
    }

        
    /**
     * Lowercases site URLs, strips HTTP protocols and strips www subdomains.
     * Borrowed from EDD and heavily modified
     * 
     * @param string $url
     *
     * @return string
     */
    public 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',
                    '.ddev.site'
                );

                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;
    }

    public static function is_beta(){
        return (defined('WPIL_VERSION_IS_BETA') && WPIL_VERSION_IS_BETA);
    }

    public static function beta_suffix(){
        return self::is_beta() ? '_beta': '';
    }
}
