<?php
/**
 * Class WCVendors_Pro_Admin_License_Update
 *
 * @since 1.9.0
 *
 * @package WCVendors
 */
class WCVendors_Pro_Admin_License_Update {
    /**
     * License option_key in the database
     *
     * @var string $option_key
     */
    private $option_key = 'wc-vendors-pro_license_manager';

    /**
     * License data from the database
     *
     * @var array $license_data
     */
    private $license_data;


    /**
     * License update endpoint
     *
     * @var string $license_update_url
     */
    private $license_update_url;

    /**
     * Plugin file
     *
     * @var string $plugin_file
     *
     * @since 1.9.0
     */
    private $plugin_file;

    /**
     * Update data option key
     *
     * @var string $update_data_key Update data option key.
     *
     * @since 1.9.4
     */
    private $update_data_key;

    /**
     * Instance of the class
     *
     * @since 1.9.0
     *
     * @var WCVendors_Pro_Admin_License_Update $instance
     */
    private static $instance = null;

    /**
     * Get the instance of the class
     *
     * @since 1.9.0
     *
     * @return WCVendors_Pro_Admin_License_Update
     */
    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }

        return self::$instance;
    }


    /**
     * Constructor method.
     * Initializes the class and adds necessary filters.
     *
     * @since 1.9.0
     */
    public function __construct() {
        $this->get_license_data();
        $this->plugin_file        = plugin_basename( WCV_PRO_PLUGIN_FILE );
        $this->license_update_url = WCV_LICENSE_SERVER . '/wp-json/slmw/v1/license/update';
        $this->update_data_key    = 'wcv_pro_update_data';

        add_filter( 'update_plugins_www.wcvendors.com', array( $this, 'maybe_update_plugin' ), 20, 3 );
        add_filter( 'plugins_api', array( $this, 'plugin_info' ), 10, 3 );
        add_action( 'upgrader_process_complete', array( $this, 'cleanup_after_update' ), 10, 2 );
    }

    /**
     * Retrieves the license data from the database.
     *
     * @since 1.9.0
     */
    public function get_license_data() {
        $default_license_data = array(
            'license_key'            => '',
            'license_email'          => '',
            'license_status'         => '',
            'license_expires'        => '',
            'max_activation'         => '',
            'max_staging_activation' => '',
            'current_version'        => '',
        );
        $this->license_data   = is_multisite() ? get_site_option( $this->option_key, array() ) : get_option( $this->option_key, array() );
        $this->license_data   = wp_parse_args( $this->license_data, $default_license_data );
    }

    /**
     * Retrieves a specific property from the license data.
     *
     * @since 1.9.0
     *
     * @param string $key The key of the property to retrieve.
     * @return mixed|null The value of the property if found, null otherwise.
     */
    public function get_license_data_prop( $key ) {
        return isset( $this->license_data[ $key ] ) ? $this->license_data[ $key ] : '';
    }

    /**
     * Checks for plugin updates.
     *
     * @since 1.9.0
     * @version 1.9.4 - Ensure plugin update come from our server
     *
     * @param bool   $update The plugin update data with the latest details.
     * @param array  $plugin_data Plugin headers.
     * @param string $plugin_file The plugin file.
     * @return bool Whether the plugin should be updated or not.
     */
    public function maybe_update_plugin( $update, $plugin_data, $plugin_file ) {

        if ( ! $this->is_license_valid() ) {
            $update = false;
        }

        if ( $plugin_file === $this->plugin_file ) {
            $this->ping_for_new_version();
            $update = $this->fetch_plugin_update_data();
        }

        return $update;
    }

    /**
     * Retrieves plugin information.
     *
     * @since 1.9.0
     * @since 2.0.2 - Suppress the WordPress.org plugin info API request by returning the local plugin details.
     *
     * @param false|object $res The default object.
     * @param string       $action The requested action.
     * @param object       $args The arguments for the plugin information request.
     * @return false|object The modified false object with custom plugin details.
     */
    public function plugin_info( $res, $action, $args ) {

        if ( 'plugin_information' !== $action || ! isset( $args->slug ) || 'wc-vendors-pro' !== $args->slug ) {
            return $res;
        }

        $software_update_data = is_multisite() ? get_site_option( $this->update_data_key ) : get_option( $this->update_data_key );
        $new_res              = new stdClass();

        if ( ! $software_update_data ) {
            $new_res->name    = 'WC Vendors Pro';
            $new_res->slug    = 'wc-vendors-pro';
            $new_res->version = WCV_PRO_VERSION;
            return $new_res;
        }

        $software_update_data = (object) $software_update_data;

        $new_res->name           = $software_update_data->name;
        $new_res->slug           = $software_update_data->slug;
        $new_res->version        = $software_update_data->version;
        $new_res->tested         = $software_update_data->tested;
        $new_res->requires       = $software_update_data->requires;
        $new_res->author         = $software_update_data->author;
        $new_res->author_profile = $software_update_data->author_profile;
        $new_res->download_link  = $software_update_data->download_link;
        $new_res->trunk          = $software_update_data->trunk;
        $new_res->last_updated   = $software_update_data->last_updated;
        $new_res->sections       = $software_update_data->sections;
        $new_res->banners        = $software_update_data->banners;
        $new_res->icons          = $software_update_data->icons;
        $new_res->version        = $software_update_data->version;
        $new_res->homepage       = $software_update_data->homepage;
        $new_res->package        = $software_update_data->download_link;
        return $new_res;
    }

    /**
     * Pings for a new version of the plugin.
     *
     * @since 1.9.0
     */
    public function ping_for_new_version() {
        $response        = json_decode( wp_remote_retrieve_body( wp_remote_get( WCVP_STATIC_PING_FILE ) ) );
        $current_version = $this->get_license_data_prop( 'current_version' );

        if ( empty( $current_version ) ) {
            $current_version = WCV_PRO_VERSION;
        }

        if ( is_object( $response ) && isset( $response->version ) && version_compare( $response->version, $current_version, '>' ) ) {

            if ( is_multisite() ) {
                delete_site_option( $this->update_data_key );
            } else {
                delete_option( $this->update_data_key );
            }
        }
    }

    /**
     * Fetch and format the plugin update data.
     *
     * @since 1.9.0
     * @return array|bool Update data array or false if update not available
     */
    public function fetch_plugin_update_data() {
        $software_update_data = is_multisite() ? get_site_option( $this->update_data_key ) : get_option( $this->update_data_key );

        if ( $software_update_data && isset( $software_update_data['version'] ) && version_compare( $software_update_data['version'], WCV_PRO_VERSION, '>' ) ) {
            return $software_update_data;
        }

        $response = wp_remote_get(
            $this->license_update_url,
            array(
                'timeout' => 30,
                'body'    => array(
                    'license_key'      => $this->get_license_data_prop( 'license_key' ),
                    'activation_email' => $this->get_license_data_prop( 'license_email' ),
                    'software_key'     => WCVP_SOFTWARE_KEY,
                    'site_url'         => home_url(),
                    'is_multisite'     => is_multisite() ? 1 : 0,
                ),
            )
        );

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

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

        if ( ! isset( $response->status ) || 'success' !== $response->status || empty( $response->software_update_data ) ) {
            return false;
        }

        $software_update_data = $response->software_update_data;

        if ( empty( $software_update_data->download_url ) || ! filter_var( $software_update_data->download_url, FILTER_VALIDATE_URL ) ) {
            return false;
        }

        $update_data = array(
            'name'           => 'WC Vendors Pro',
            'id'             => $software_update_data->download_id,
            'url'            => $software_update_data->home_page,
            'slug'           => 'wc-vendors-pro',
            'plugin'         => $this->plugin_file,
            'package'        => esc_url_raw( $software_update_data->download_url ),
            'requires'       => $software_update_data->requires,
            'tested'         => $software_update_data->tested_up_to,
            'version'        => $software_update_data->latest_version,
            'new_version'    => $software_update_data->latest_version,
            'author'         => $software_update_data->author,
            'author_profile' => $software_update_data->author_url,
            'homepage'       => $software_update_data->home_page,
            'download_link'  => esc_url_raw( $software_update_data->download_url ),
            'trunk'          => esc_url_raw( $software_update_data->download_url ),
            'last_updated'   => $software_update_data->last_updated,
            'sections'       => array(
                'description'  => $software_update_data->description,
                'changelog'    => $software_update_data->changelog,
                'installation' => $software_update_data->installation,
                'support'      => $software_update_data->support,
            ),
            'banners'        => array(
                'low'  => 'https://ps.w.org/wc-vendors/assets/banner-772x250.png',
                'high' => 'https://ps.w.org/wc-vendors/assets/banner-1544x500.png',
            ),
            'icons'          => array(
                '1x' => 'https://ps.w.org/wc-vendors/assets/icon-128x128.png',
                '2x' => 'https://ps.w.org/wc-vendors/assets/icon-256x256.png',
            ),
        );

        if ( is_multisite() ) {
            update_site_option( $this->update_data_key, $update_data );
        } else {
            update_option( $this->update_data_key, $update_data );
        }

        return $update_data;
    }

    /**
     * Checks if the license is valid.
     *
     * @since 1.9.0
     *
     * @return bool True if the license is valid, false otherwise.
     */
    public function is_license_valid() {
        $license_key    = $this->get_license_data_prop( 'license_key' );
        $license_email  = $this->get_license_data_prop( 'license_email' );
        $license_stauts = $this->get_license_data_prop( 'license_status' );

        if ( empty( $license_key ) || empty( $license_email ) ) {
            return false;
        }

        if ( 'active' !== $license_stauts ) {
            return false;
        }

        return true;
    }

    /**
     * Cleanup update data after plugin update is complete
     *
     * @since 1.9.4
     *
     * @param WP_Upgrader $upgrader WP_Upgrader instance.
     * @param array       $options  Array of bulk item update data.
     */
    public function cleanup_after_update( $upgrader, $options ) {
        if ( 'update' === $options['action'] && 'plugin' === $options['type'] && isset( $options['plugins'] ) && is_array( $options['plugins'] ) ) {
            foreach ( $options['plugins'] as $each_plugin ) {
                if ( $each_plugin === $this->plugin_file ) {
                    if ( is_multisite() ) {
                        delete_site_option( $this->update_data_key );
                    } else {
                        delete_option( $this->update_data_key );
                    }
                    break;
                }
            }
        }
    }
}
