<?php
/**
 * MainWP Database Updater WC.
 *
 * @package MainWP\Child
 */

namespace MainWP\Child;

/**
 * Class MainWP_Child_DB_Updater_WC.
 *
 * MainWP Database Updater extension handler.
 */
class MainWP_Child_DB_Updater_WC {

    /**
     * Public static variable to hold the single instance of the class.
     *
     * @var mixed Default null
     */
    public static $instance = null;

    /**
     * Public variable to hold the infomration if the WooCommerce plugin is installed on the child site.
     *
     * @var bool If WooCommerce intalled, return true, if not, return false.
     */
    public static $is_plugin_woocom_installed = false;

    /**
     * Method instance()
     *
     * Create a public static instance.
     *
     * @return mixed Class instance.
     */
    public static function instance() {
        if ( null === static::$instance ) {
            static::$instance = new self();
        }
        return static::$instance;
    }

    /**
     * Constructor.
     *
     * Run any time class is called.
     *
     * @return void
     */
    public function __construct() {
        require_once ABSPATH . 'wp-admin/includes/plugin.php'; // NOSONAR - WP compatible.

        if ( function_exists( 'WC' ) && is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
            $supported = true;
            if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '3.3', '<' ) ) {
                $supported = false;
            }
            if ( $supported ) {
                static::$is_plugin_woocom_installed = true;
            }
        }

        if ( static::$is_plugin_woocom_installed ) {
            add_filter( 'mainwp_child_db_updater_sync_data', array( $this, 'hook_db_updater_sync_data' ), 10, 1 );
        }
    }

    /**
     * Requires WC files.
     *
     * @return mixed Results.
     */
    public function requires_files() {
        if ( ! static::$is_plugin_woocom_installed ) {
            return;
        }
        if ( file_exists( WC_ABSPATH . 'includes/class-wc-install.php' ) ) {
            include_once WC_ABSPATH . 'includes/class-wc-install.php'; // NOSONAR -- WP compatible.
        }
        if ( file_exists( WC_ABSPATH . 'includes/wc-update-functions.php' ) ) {
            include_once WC_ABSPATH . 'includes/wc-update-functions.php'; // NOSONAR -- WP compatible.
        }
    }

    /**
     * Get db updater sync data.
     *
     * @param array $db_upgrades Input sync data.
     *
     * @return array $db_upgrades Return data array.
     * @throws MainWP_Exception Error message.
     */
    public function hook_db_updater_sync_data( $db_upgrades ) {
        if ( ! static::$is_plugin_woocom_installed ) {
            return $db_upgrades;
        }

        if ( ! is_array( $db_upgrades ) ) {
            $db_upgrades = array();
        }

        $this->requires_files();
        try {

            MainWP_Helper::instance()->check_classes_exists( array( '\WC_Install' ) );
            MainWP_Helper::instance()->check_methods( '\WC_Install', array( 'needs_db_update' ) );

            if ( \WC_Install::needs_db_update() ) {
                $next_scheduled_date = \WC()->queue()->get_next( 'woocommerce_run_update_callback', null, 'woocommerce-db-updates' );
                if ( ! $next_scheduled_date ) {
                    $current_db_version = get_option( 'woocommerce_db_version', null );
                    // need.
                    $db_upgrades['woocommerce/woocommerce.php'] = array(
                        'update'     => $this->get_needs_db_update(),
                        'Name'       => 'WooCommerce',
                        'db_version' => $current_db_version ? $current_db_version : '',
                    );
                }
            }
        } catch ( MainWP_Exception $e ) {
            // not exit here!
            error_log( $e->getMessage() ); //phpcs:ignore -- for debug.
        }
        return $db_upgrades;
    }



    /**
     * Is a DB update needed?
     *
     * @since  3.2.0
     * @return boolean
     */
    public static function get_needs_db_update() {
        $db_versions = array(
            'new_db_version' => '',
            'slug'           => 'woocommerce/woocommerce.php',
        );

        $updates         = \WC_Install::get_db_update_callbacks();
        $update_versions = array_keys( $updates );
        usort( $update_versions, 'version_compare' );

        if ( ! empty( $update_versions ) ) {
            $db_versions['new_db_version'] = end( $update_versions );
        }

        return $db_versions;
    }

    /**
     * Method update_db()
     *
     * Update WC DB.
     *
     * @return array Action result.
     */
    public function update_db() {
        if ( ! static::$is_plugin_woocom_installed ) {
            return false;
        }
        $success = false;
        try {
            MainWP_Helper::instance()->check_classes_exists( array( '\WC_Install' ) );
            MainWP_Helper::instance()->check_methods( '\WC_Install', array( 'needs_db_update' ) );
            $this->update_wc_db();
            $success = true;
        } catch ( MainWP_Exception $e ) {
            error_log( $e->getMessage() ); //phpcs:ignore -- for debug.
        }
        try {
            MainWP_Helper::instance()->check_classes_exists( array( '\WC_Admin_Notices' ) );
            MainWP_Helper::instance()->check_methods( '\WC_Admin_Notices', array( 'remove_notice' ) );
            static::hide_notice( 'update' );
        } catch ( MainWP_Exception $e ) {
            error_log( $e->getMessage() ); //phpcs:ignore -- for debug.
        }
        return $success;
    }

    /**
     * Push all needed DB updates to the queue for processing.
     */
    private static function update_wc_db() {
        MainWP_Helper::instance()->check_methods( '\WC_Install', array( 'get_db_update_callbacks' ) );
        $current_db_version = get_option( 'woocommerce_db_version' );
        $loop               = 0;
        foreach ( \WC_Install::get_db_update_callbacks() as $version => $update_callbacks ) {
            if ( version_compare( $current_db_version, $version, '<' ) ) {
                foreach ( $update_callbacks as $update_callback ) {
                    \WC()->queue()->schedule_single(
                        time() + $loop,
                        'woocommerce_run_update_callback',
                        array(
                            'update_callback' => $update_callback,
                        ),
                        'woocommerce-db-updates'
                    );
                    ++$loop;
                }
            }
        }

        // After the callbacks finish, update the db version to the current WC version.
        $current_wc_version = WC()->version;
        if ( version_compare( $current_db_version, $current_wc_version, '<' ) &&
            ! \WC()->queue()->get_next( 'woocommerce_update_db_to_current_version' ) ) {
            \WC()->queue()->schedule_single(
                time() + $loop,
                'woocommerce_update_db_to_current_version',
                array(
                    'version' => $current_wc_version,
                ),
                'woocommerce-db-updates'
            );
        }
    }

    /**
     * Hide a single notice.
     *
     * @param string $name Notice name.
     */
    private static function hide_notice( $name ) {
        \WC_Admin_Notices::remove_notice( $name );
        update_user_meta( get_current_user_id(), 'dismissed_' . $name . '_notice', true );
        do_action( 'woocommerce_hide_' . $name . '_notice' );
    }
}
