<?php
/**
 * MainWP Sync Handler
 *
 * Handle all syncing between MainWP & Child Site Network.
 *
 * @package     MainWP/Dashboard
 */

namespace MainWP\Dashboard;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Class MainWP_Sync
 *
 * @package MainWP\Dashboard
 */
class MainWP_Sync { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.

    /**
     * Clone websites setting.
     *
     * @var mixed Clone websites.
     */
    public static $clone_websites = null;

    /**
     * Clone enabled setting.
     *
     * @var mixed Clone enabled.
     */
    public static $clone_enabled = null;


    /**
     * Disallowed Clone sites setting.
     *
     * @var mixed Disallowed clone.
     */
    public static $disallowed_clone_sites = null;

    /**
     * Get the current stack action if the helper is available.
     *
     * Some execution paths can reach sync handlers before the stack helper
     * has been loaded, so telemetry must degrade safely instead of fatalling.
     *
     * @return string|null
     */
    protected static function get_current_stack_action() {
        return class_exists( __NAMESPACE__ . '\MainWP_Stack_Helper' ) ? MainWP_Stack_Helper::stack_current() : null;
    }

    /**
     * Push a stack action if the helper is available.
     *
     * @param string $action Stack action.
     * @return void
     */
    protected static function push_stack_action( $action ) {
        if ( class_exists( __NAMESPACE__ . '\MainWP_Stack_Helper' ) ) {
            MainWP_Stack_Helper::stack_push( $action );
        }
    }


    /**
     * Method sync_website()
     *
     * Sync Child Site.
     *
     * @param object $website object.
     * @param bool   $clear_session to run the ending session or not.
     *
     * @return bool sync result.
     */
    public static function sync_website( $website, $clear_session = true ) {
        if ( ! is_object( $website ) ) {
            return false;
        }
        MainWP_DB::instance()->update_website_sync_values( $website->id, array( 'dtsSyncStart' => time() ) );
        return static::sync_site( $website, false, true, $clear_session );
    }

    /**
     * Method sync_site()
     *
     * @param mixed $pWebsite         Null|userid.
     * @param bool  $pForceFetch      Check if a fourced Sync.
     * @param bool  $pAllowDisconnect Check if allowed to disconect.
     * @param bool  $clear_session to run the ending session or not.
     *
     * @return bool sync_information_array
     *
     * @uses \MainWP\Dashboard\MainWP_DB_Common::get_user_extension_by_user_id()
     * @uses \MainWP\Dashboard\MainWP_DB::query()
     * @uses \MainWP\Dashboard\MainWP_DB::update_website_option()
     * @uses \MainWP\Dashboard\MainWP_DB::fetch_object()
     * @uses \MainWP\Dashboard\MainWP_DB::free_result()
     * @uses \MainWP\Dashboard\MainWP_Exception
     * @uses \MainWP\Dashboard\MainWP_System_Utility::get_primary_backup()
     * @uses  \MainWP\Dashboard\MainWP_Utility::end_session()
     */
    public static function sync_site( &$pWebsite = null, $pForceFetch = false, $pAllowDisconnect = true, $clear_session = true ) { // phpcs:ignore -- NOSONAR - complexity method.

        // to support demo data.
        if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $pWebsite ) ) {
            return MainWP_Demo_Handle::get_instance()->handle_action_demo( $pWebsite, 'sync_site' );
        }

        if ( null === $pWebsite ) {
            return false;
        }
        $userExtension = MainWP_DB_Common::instance()->get_user_extension_by_user_id( $pWebsite->userid );
        if ( null === $userExtension ) {
            return false;
        }

        if ( $clear_session ) {
            MainWP_Utility::end_session();
        }

        $cur_id = MainWP_System_Utility::get_current_wpid();
        if ( empty( $cur_id ) ) {
            MainWP_System_Utility::set_current_wpid( $pWebsite->id );
        }

        MainWP_Logger::instance()->log_execution_sync( 'init', '', $pWebsite );
        $stats_track_id = MainWP_Execution_Helper::execute_call_track( 'start_point', $pWebsite );

        try {

            if ( null === static::$clone_enabled ) {

                /**
                 * Filter: mainwp_clone_enabled
                 *
                 * Filters whether the Clone feature is enabled or disabled.
                 *
                 * @since Unknown
                 */
                static::$clone_enabled  = apply_filters( 'mainwp_clone_enabled', false );
                static::$clone_websites = array();

                if ( static::$clone_enabled ) {

                    static::$disallowed_clone_sites = get_option( 'mainwp_clone_disallowedsites' );

                    if ( ! is_array( static::$disallowed_clone_sites ) ) {
                        static::$disallowed_clone_sites = array();
                    }

                    $wpsite_fields = array( 'id', 'name', 'url', 'adminname' );
                    $sync_fields   = array( 'extauth', 'totalsize' );
                    $websites      = MainWP_DB::instance()->query(
                        MainWP_DB::instance()->get_sql_websites_for_current_user_by_params(
                            array(
                                'select_wp_fields'   => $wpsite_fields,
                                'select_sync_fields' => $sync_fields,
                            )
                        )
                    );

                    if ( $websites ) {
                        while ( $websites && ( $website = MainWP_DB::fetch_object( $websites ) ) ) {
                            if ( in_array( $website->id, static::$disallowed_clone_sites ) ) {
                                continue;
                            }
                            if ( (int) $website->id === (int) $pWebsite->id ) {
                                continue;
                            }

                            static::$clone_websites[ $website->id ] = array(
                                'name'          => $website->name,
                                'url'           => $website->url,
                                'extauth'       => $website->extauth,
                                'size'          => $website->totalsize,
                                'connect_admin' => $website->adminname,
                            );
                        }
                        MainWP_DB::free_result( $websites );
                    }
                    $disallowed_current_site = in_array( $pWebsite->id, static::$disallowed_clone_sites ) ? true : false;
                }
            }

            $disallowed_current_site = static::$clone_enabled && is_array( static::$disallowed_clone_sites ) && in_array( $pWebsite->id, static::$disallowed_clone_sites ) ? true : false;

            $primaryBackup = MainWP_System_Utility::get_primary_backup();

            $othersData = apply_filters_deprecated( 'mainwp-sync-others-data', array( array(), $pWebsite ), '4.0.7.2', 'mainwp_sync_others_data' );  // @deprecated Use 'mainwp_sync_others_data' instead. NOSONAR - not IP.

            /**
             * Filter: mainwp_sync_others_data
             *
             * Filters additional data in the sync request. Allows extensions or 3rd party plugins to hook data to the sync request.
             *
             * @param object $pWebsite Object contaning child site data.
             *
             * @since Unknown
             *
             * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
             */
            $othersData = apply_filters( 'mainwp_sync_others_data', $othersData, $pWebsite );

            $saved_days_number = apply_filters( 'mainwp_site_actions_saved_days_number', 30 );

            $backup_method = '';
            if ( property_exists( $pWebsite, 'primary_backup_method' ) ) {
                if ( '' === $pWebsite->primary_backup_method || 'global' === $pWebsite->primary_backup_method ) {
                    $backup_method = $primaryBackup;
                } else {
                    $backup_method = $pWebsite->primary_backup_method;
                }
            }

            $postdata = array(
                'optimize'                        => 1 === (int) get_option( 'mainwp_optimize', 1 ) ? 1 : 0,
                'cloneSites'                      => ( ! static::$clone_enabled || $disallowed_current_site ) ? 0 : rawurlencode( wp_json_encode( static::$clone_websites ) ),
                'othersData'                      => wp_json_encode( $othersData ),
                'server'                          => get_admin_url(),
                'numberdaysOutdatePluginTheme'    => get_option( 'mainwp_numberdays_Outdate_Plugin_Theme', 365 ),
                'primaryBackup'                   => $backup_method, // if empty site backup method will not sync the backup info from child site.
                'siteId'                          => $pWebsite->id,
                'child_actions_saved_days_number' => intval( $saved_days_number ),
                'pingnonce'                       => MainWP_Utility::instance()->create_site_nonce( 'pingnonce', $pWebsite->id ),
            );

            $individual_settings_json = MainWP_DB::instance()->get_website_option( $pWebsite, 'password_policy_individual_settings' );
            $individual_settings      = array();

            if ( ! empty( $individual_settings_json ) ) {
                $individual_settings = json_decode( $individual_settings_json, true );
                if ( ! is_array( $individual_settings ) ) {
                    $individual_settings = array();
                }
            }

            if ( ! empty( $individual_settings['overwrite_enabled'] ) ) {
                $password_policy_settings = wp_parse_args(
                    $individual_settings,
                    array(
                        'max_age_days'     => 0,
                        'due_soon_message' => __( 'Your password is due to be changed soon. Please update it as soon as possible. This helps keep your account secure.', 'mainwp' ),
                        'overdue_message'  => __( 'Your password change is overdue. Please update your password now. This is required by your site\'s password policy.', 'mainwp' ),
                        'show_notices_to'  => 'edit_posts',
                    )
                );
            } else {
                $password_policy_defaults = array(
                    'max_age_days'     => 0,
                    'due_soon_message' => __( 'Your password is due to be changed soon. Please update it as soon as possible. This helps keep your account secure.', 'mainwp' ),
                    'overdue_message'  => __( 'Your password change is overdue. Please update your password now. This is required by your site\'s password policy.', 'mainwp' ),
                    'show_notices_to'  => 'edit_posts',
                );
                $password_policy_settings = wp_parse_args( get_option( 'mainwp_password_policy_settings', array() ), $password_policy_defaults );
            }

            $postdata['passwordPolicySettings'] = wp_json_encode( $password_policy_settings );

            $reg_verify = MainWP_DB::instance()->get_website_option( $pWebsite, 'register_verify_key', '' );
            if ( empty( $reg_verify ) ) {
                $postdata['sync_regverify'] = 1;
            }

            $postdata['params_logs'] = apply_filters( 'mainwp_module_logs_changes_logs_sync_params', '', $pWebsite->id, $postdata, $pWebsite );

            if ( class_exists( '\MainWP\Dashboard\Module\Log\Log_Manager' ) ) {
                $sync_last_created                      = \MainWP\Dashboard\Module\Log\Log_Manager::instance()->get_sync_actions_last_created( $pWebsite->id );
                $postdata['child_actions_last_created'] = (float) $sync_last_created;
            }

            $synclist             = MainWP_Settings::get_instance()->get_data_list_to_sync();
            $postdata['syncdata'] = wp_json_encode( $synclist );

            static::push_stack_action( 'sync_stats' );

            $information = MainWP_Connect::fetch_url_authed(
                $pWebsite,
                'stats',
                $postdata,
                true,
                $pForceFetch
            );

            $return = static::sync_information_array( $pWebsite, $information, '', false, false, $pAllowDisconnect );
            MainWP_Logger::instance()->log_execution_time( 'sync :: [siteid=' . $pWebsite->id . ']' );
            MainWP_Execution_Helper::execute_call_track( 'end_point', $pWebsite, array(), $stats_track_id, 'stats site' );
            return $return;
        } catch ( MainWP_Exception $e ) {
            MainWP_Execution_Helper::execute_call_track( 'end_point', $pWebsite, array(), $stats_track_id, 'stats site' );
            $sync_errors = '';

            if ( $e->getMessage() === 'HTTPERROR' ) {
                $sync_errors = esc_html__( 'HTTP error', 'mainwp' ) . ( ! empty( $e->get_message_extra() ) ? ' - ' . $e->get_message_extra() : '' );
            } elseif ( $e->getMessage() === 'NOMAINWP' ) {
                $sync_errors = MainWP_Error_Helper::get_error_not_detected_connect();
            }

            MainWP_Logger::instance()->log_execution_time( 'sync :: [siteid=' . $pWebsite->id . ']' );
            return static::sync_information_array( $pWebsite, $information, $sync_errors, false, true, $pAllowDisconnect );
        }
    }

    /**
     * Method sync_information_array()
     *
     * Grab all Child Site Information.
     *
     * @param object $pWebsite The website object.
     * @param array  $information Array contaning information returned from child site.
     * @param string $sync_errors Check for Sync Errors.
     * @param int    $check_result Check if offline.
     * @param bool   $error True|False.
     * @param bool   $pAllowDisconnect True|False.
     * @param array  $other Additional parameters.
     * @param array  $fetch_output Fetch output.
     *
     * @return bool true|false True on success, false on failure.
     *
     * @uses \MainWP\Dashboard\MainWP_DB::update_website_option()
     * @uses \MainWP\Dashboard\MainWP_DB::update_website_sync_values()
     * @uses \MainWP\Dashboard\MainWP_DB::update_website_values()
     * @uses \MainWP\Dashboard\MainWP_Logger::warning_for_website()
     * @uses \MainWP\Dashboard\MainWP_Monitoring_Handler::get_health_noticed_status_value()
     * @uses  \MainWP\Dashboard\MainWP_Utility::ctype_digit()
     * @uses  \MainWP\Dashboard\MainWP_Utility::get_site_health()
     */
    public static function sync_information_array( &$pWebsite, &$information, $sync_errors = '', $check_result = false, $error = false, $pAllowDisconnect = true, $other = array(), $fetch_output = array() ) { // phpcs:ignore -- NOSONAR -Current complexity is the only way to achieve desired results, pull request solutions appreciated.
        $emptyArray        = wp_json_encode( array() );
        $websiteValues     = array();
        $websiteSyncValues = array(
            'sync_errors' => $sync_errors,
            'version'     => 0,
        );

        $_error = $sync_errors;

        $done = false;

        $current_siteid = 0;
        if ( is_string( $pWebsite ) || is_int( $pWebsite ) ) {
            $current_siteid = intval( $pWebsite );
        } elseif ( is_object( $pWebsite ) && ( ! property_exists( $pWebsite, 'plugin_updates' ) || ! property_exists( $pWebsite, 'theme_updates' ) ) ) {
            $current_siteid = $pWebsite->id;
        }

        // to get full data.
        if ( $current_siteid ) {
            $pWebsite = MainWP_DB::instance()->get_website_by_id( $current_siteid );
        }

        /**
         * Filter: mainwp_before_save_sync_result
         *
         * Filters data returned from child site before saving to the database.
         *
         * @param object $pWebsite Object containing child site data.
         *
         * @since 3.4
         */
        $information = apply_filters( 'mainwp_before_save_sync_result', $information, $pWebsite );

        if ( ! empty( $information['regverify_info'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'register_verify_key', $information['regverify_info'] );
            $done = true;
        }

        if ( isset( $information['siteurl'] ) ) {
            $websiteValues['siteurl'] = $information['siteurl'];
            $done                     = true;
        }

        if ( isset( $information['version'] ) ) {
            $websiteSyncValues['version'] = $information['version'];
            $done                         = true;
        }

        $phpversion = '';
        $wpversion  = '';
        if ( isset( $information['site_info'] ) && ! empty( $information['site_info'] ) ) {
            if ( is_array( $information['site_info'] ) && isset( $information['site_info']['phpversion'] ) ) {
                $phpversion = $information['site_info']['phpversion'];
            }
            if ( is_array( $information['site_info'] ) && isset( $information['site_info']['ip'] ) ) {
                $websiteValues['ip'] = sanitize_text_field( wp_unslash( $information['site_info']['ip'] ) );
            }

            if ( is_array( $information['site_info'] ) && isset( $information['site_info']['wpversion'] ) ) {
                $wpversion = $information['site_info']['wpversion'];
            }

            MainWP_DB::instance()->update_website_option( $pWebsite, 'site_info', wp_json_encode( $information['site_info'] ) );
            $done = true;
        }

        if ( ! empty( $phpversion ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'phpversion', $phpversion );
        }
        if ( ! empty( $wpversion ) ) { // to support sorting by wpversion.
            $ver_num = MainWP_Utility::instance()->wp_versions_order_num( $wpversion );
            MainWP_DB::instance()->update_website_option( $pWebsite, 'wpversion_order_num', $ver_num );
        }

        if ( isset( $information['directories'] ) && is_array( $information['directories'] ) ) {
            $websiteValues['directories'] = wp_json_encode( $information['directories'] );
            $done                         = true;
        } elseif ( isset( $information['directories'] ) ) {
            $websiteValues['directories'] = $information['directories'];
            $done                         = true;
        }

        $had_pending_updates = null;

        $wp_updates_empty = true;
        if ( isset( $information['wp_updates'] ) && ! empty( $information['wp_updates'] ) ) {
            MainWP_DB::instance()->update_website_option(
                $pWebsite,
                'wp_upgrades',
                wp_json_encode(
                    array(
                        'current' => $information['wpversion'],
                        'new'     => $information['wp_updates'],
                    )
                )
            );
            $done                = true;
            $wp_updates_empty    = false;
            $had_pending_updates = true;
        }

        if ( isset( $information['plugin_updates'] ) ) {
            $update_values = array();
            if ( is_array( $information['plugin_updates'] ) ) {
                foreach ( $information['plugin_updates'] as $file => $update ) {
                    $update_values[ $file ] = $update;
                }
            }

            $had_pending_updates = ! empty( $update_values ) || (bool) $had_pending_updates;

            $websiteValues['plugin_upgrades'] = wp_json_encode( $update_values );
            $done                             = true;
        }

        if ( isset( $information['theme_updates'] ) ) {
            $update_values = array();
            if ( is_array( $information['theme_updates'] ) ) {
                foreach ( $information['theme_updates'] as $file => $update ) {
                    $update_values[ $file ] = $update;
                }
            }
            $had_pending_updates             = ! empty( $update_values ) || (bool) $had_pending_updates;
            $websiteValues['theme_upgrades'] = wp_json_encode( $update_values );
            $done                            = true;
        }

        if ( isset( $information['translation_updates'] ) ) {
            $had_pending_updates                   = ! empty( $information['translation_updates'] ) || (bool) $had_pending_updates;
            $websiteValues['translation_upgrades'] = wp_json_encode( $information['translation_updates'] );
            $done                                  = true;
        }

        if ( isset( $information['premium_updates'] ) ) {
            $had_pending_updates = ! empty( $information['premium_updates'] ) || (bool) $had_pending_updates;

            MainWP_DB::instance()->update_website_option( $pWebsite, 'premium_upgrades', wp_json_encode( $information['premium_updates'] ) );
            $done = true;
        }

        if ( isset( $information['securityStats'] ) ) {
            $total_securityIssues = 0;
            $securityStats        = $information['securityStats'];
            if ( is_array( $securityStats ) ) {
                /** This filter is documented in ../pages/page-mainwp-security-issues.php */
                $filterStats = apply_filters( 'mainwp_security_issues_stats', false, $securityStats, $pWebsite );
                if ( false !== $filterStats && is_array( $filterStats ) ) {
                    $securityStats = array_merge( $securityStats, $filterStats );
                }

                $tmp_issues           = array_filter(
                    $securityStats,
                    function ( $v ) {
                        return 'N' === $v;
                    },
                    ARRAY_FILTER_USE_BOTH
                );
                $total_securityIssues = count( $tmp_issues );
                $securityStats        = wp_json_encode( $securityStats );
            } else {
                $securityStats = $emptyArray;
            }
            $websiteValues['securityIssues'] = $total_securityIssues;
            MainWP_DB::instance()->update_website_option( $pWebsite, 'security_stats', $securityStats );
            $done = true;
        } elseif ( isset( $information['securityIssues'] ) && MainWP_Utility::ctype_digit( $information['securityIssues'] ) && $information['securityIssues'] >= 0 ) {
            $websiteValues['securityIssues'] = $information['securityIssues'];
            $done                            = true;
        }

        if ( isset( $information['recent_comments'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_comments', wp_json_encode( $information['recent_comments'] ) );
            $done = true;
        }

        if ( isset( $information['recent_posts'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_posts', wp_json_encode( $information['recent_posts'] ) );
            $done = true;
        }

        if ( isset( $information['recent_pages'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_pages', wp_json_encode( $information['recent_pages'] ) );
            $done = true;
        }

        if ( isset( $information['themes'] ) ) {
            $websiteValues['themes'] = wp_json_encode( $information['themes'] );
            $done                    = true;
        }

        $plugins_info = array();

        if ( isset( $information['plugins'] ) ) {
            $plugins_info             = $information['plugins'];
            $websiteValues['plugins'] = wp_json_encode( $plugins_info );
            $done                     = true;
        }

        if ( isset( $information['users'] ) ) {
            $websiteValues['users'] = wp_json_encode( $information['users'] );
            $done                   = true;
        }

        if ( isset( $information['categories_list'] ) ) {
            $websiteValues['categories'] = wp_json_encode( $information['categories_list'] );
            $done                        = true;
        } elseif ( isset( $information['categories'] ) ) { // support old child version.
            $websiteValues['categories'] = wp_json_encode( $information['categories'] );
            $done                        = true;
        }

        if ( isset( $information['totalsize'] ) ) {
            $websiteSyncValues['totalsize'] = $information['totalsize'];
            $done                           = true;
        }

        if ( isset( $information['dbsize'] ) ) {
            $websiteSyncValues['dbsize'] = $information['dbsize'];
            $done                        = true;
        }

        if ( isset( $information['dbsize_activitylogs'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'dbsize_activitylogs', $information['dbsize_activitylogs'] );
            $done = true;
        }

        if ( isset( $information['extauth'] ) ) {
            $websiteSyncValues['extauth'] = $information['extauth'];
            $done                         = true;
        }

        if ( isset( $information['wpe'] ) ) {
            $websiteValues['wpe'] = $information['wpe'];
            $done                 = true;
        }

        if ( isset( $information['wphost'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'wphost', $information['wphost'] );
        }

        if ( isset( $information['last_post_gmt'] ) ) {
            $websiteSyncValues['last_post_gmt'] = $information['last_post_gmt'];
            $done                               = true;
        }

        if ( isset( $information['health_site_status'] ) ) {
            $health_status                     = $information['health_site_status'];
            $hstatus                           = MainWP_Utility::get_site_health( $health_status );
            $custom_health_value               = $hstatus['val'] - $hstatus['critical'] * 100; // computes custom health value to support sorting by sites health and sites health threshold.
            $websiteSyncValues['health_value'] = $custom_health_value;
            $done                              = true;
            MainWP_DB::instance()->update_website_option( $pWebsite, 'health_site_status', wp_json_encode( $health_status ) );
            $new_noticed = MainWP_Monitoring_Handler::get_health_noticed_status_value( $pWebsite, $custom_health_value );
            if ( null !== $new_noticed ) {
                MainWP_DB::instance()->update_website_sync_values(
                    $pWebsite->id,
                    array(
                        'health_site_noticed' => $new_noticed,
                    )
                );
            }

            $hval          = $hstatus['val'];
            $critical      = $hstatus['critical'];
            $health_status = 0;
            if ( 80 <= $hval && empty( $critical ) ) {
                $health_status = 0; // Good.
            } else {
                $health_status = 1; // Should be improved'.
            }
            $websiteSyncValues['health_status'] = $health_status;
        }

        if ( isset( $information['mainwpdir'] ) ) {
            $websiteValues['mainwpdir'] = $information['mainwpdir'];
            $done                       = true;
        }

        if ( isset( $information['uniqueId'] ) ) {
            $websiteValues['uniqueId'] = $information['uniqueId'];
            $done                      = true;
        }

        if ( isset( $information['clone_adminname'] ) ) {
            $websiteValues['adminname'] = $information['clone_adminname'];
            $done                       = true;
        }

        if ( isset( $information['admin_nicename'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'admin_nicename', trim( $information['admin_nicename'] ) );
            $done = true;
        }

        if ( isset( $information['admin_useremail'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'admin_useremail', trim( $information['admin_useremail'] ) );
            $done = true;
        }

        if ( isset( $information['plugins_outdate_info'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'plugins_outdate_info', wp_json_encode( $information['plugins_outdate_info'] ) );
            $done = true;
        }

        if ( isset( $information['themes_outdate_info'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'themes_outdate_info', wp_json_encode( $information['themes_outdate_info'] ) );
            $done = true;
        }

        if ( isset( $information['password_policy_options'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'password_policy_options', wp_json_encode( $information['password_policy_options'] ) );
            $done = true;
        }

        if ( isset( $information['primaryLasttimeBackup'] ) ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, 'primary_lasttime_backup', $information['primaryLasttimeBackup'] );
            $done = true;
        }

        if ( isset( $information['child_site_actions_data'] ) ) {
            if ( is_array( $information['child_site_actions_data'] ) && isset( $information['child_site_actions_data']['connected_admin'] ) ) {
                unset( $information['child_site_actions_data']['connected_admin'] );
            }
            if ( class_exists( '\MainWP\Dashboard\Module\Log\Log_Manager' ) ) {
                \MainWP\Dashboard\Module\Log\Log_Manager::instance()->sync_log_site_actions( $pWebsite->id, $information['child_site_actions_data'], $pWebsite );
            }
            $done = true;
        }

        if ( ! empty( $information['changes_logs_data'] ) && class_exists( '\MainWP\Dashboard\Module\Log\Log_Changes_Logs_Helper' ) ) {
            \MainWP\Dashboard\Module\Log\Log_Changes_Logs_Helper::instance()->sync_changes_logs( $pWebsite->id, $information['changes_logs_data'], $pWebsite );
            $done = true;
        }

        if ( ! $done ) {
            if ( isset( $information['wpversion'] ) ) {
                $done = true;
            } elseif ( isset( $information['error'] ) ) {
                MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[' . esc_html( $information['error'] ) . ']' );
                $error                            = true;
                $done                             = true;
                $_error                           = esc_html__( 'ERROR: ', 'mainwp' ) . esc_html( $information['error'] );
                $websiteSyncValues['sync_errors'] = $_error;
            } elseif ( ! empty( $sync_errors ) ) {
                MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[' . $sync_errors . ']' );
                $_error = $sync_errors;
                $error  = true;
                if ( ! $pAllowDisconnect ) {
                    $sync_errors = '';
                }

                $websiteSyncValues['sync_errors'] = $sync_errors;
            } else {
                MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[Undefined error]' );
                $error = true;
                if ( $pAllowDisconnect ) {
                    $sync_errors                      = esc_html__( 'Undefined error! Please, reinstall the MainWP Child plugin on the child site.', 'mainwp' );
                    $websiteSyncValues['sync_errors'] = $sync_errors;
                    $_error                           = $sync_errors;
                }
            }
        }

        $sync_success = false;
        if ( $done ) {
            $sync_success                 = true;
            $websiteSyncValues['dtsSync'] = time();
            if ( $wp_updates_empty ) {
                MainWP_DB::instance()->update_website_option(
                    $pWebsite,
                    'wp_upgrades',
                    $emptyArray
                );
            }
        }
        MainWP_DB::instance()->update_website_sync_values( $pWebsite->id, $websiteSyncValues );
        MainWP_Logger::instance()->log_events( 'db-queries', sprintf( '[Update sync values=%s]', MainWP_DB::instance()->get_last_query() ) );

        if ( ! empty( $websiteValues ) ) {
            MainWP_DB::instance()->update_website_values( $pWebsite->id, $websiteValues );
            MainWP_Logger::instance()->log_events( 'db-queries', sprintf( '[Update site sync data=%s]', MainWP_DB::instance()->get_last_query() ) );
        }

        $error_occurred = $error;
        $msg_errors     = $_error;

        $error = apply_filters( 'mainwp_sync_site_after_sync_result', $error, $pWebsite, $information );

        if ( ! empty( $plugins_info ) && is_array( $plugins_info ) ) {
            foreach ( $plugins_info as $info ) {
                if ( ! empty( $info['icon'] ) ) {
                    $icon_slug = MainWP_Utility::get_dir_slug( $info['slug'] );
                    MainWP_System_Utility::save_cached_icons( $info['icon'], $icon_slug, 'plugin' );
                }
            }
        }

        // Sync action.
        if ( ! $error ) {

            do_action_deprecated( 'mainwp-site-synced', array( $pWebsite, $information ), '4.0.7.2', 'mainwp_site_synced' ); // @deprecated Use 'mainwp_site_synced' instead. NOSONAR - not IP.

            /**
             * Action: mainwp_site_synced
             *
             * Fires upon successful site synchronization.
             *
             * @param object $pWebsite    Object containing child site info.
             * @param array  $information Array containing information returned from child site.
             *
             * @since 3.4
             */
            do_action( 'mainwp_site_synced', $pWebsite, $information );
        }

        $telem_info = static::get_telem_sync_info( $sync_success );

        if ( isset( $information['version'] ) ) {
            $telem_info['child_plugin_version'] = $information['version'];
        }

        if ( isset( $had_pending_updates ) ) {
            $telem_info['site_had_pending_updates'] = $had_pending_updates ? true : false;
        }

        if ( $error_occurred && ! empty( $information['fetch_url_output'] ) && is_array( $information['fetch_url_output'] ) ) {
            $output                        = $information['fetch_url_output'];
            $telem_info['error_message']   = $msg_errors;
            $telem_info['error_category']  = ! empty( $output['error_category'] ) ? $output['error_category'] : 'unknown';
            $telem_info['error_code']      = ! empty( $output['error_code'] ) ? $output['error_code'] : 'undefined_error';
            $telem_info['connection_step'] = ! empty( $output['connection_step'] ) ? $output['connection_step'] : 'handshake';
            if ( ! empty( $output['http_status'] ) ) {
                $telem_info['http_status'] = $output['http_status'];
            }
        }

        /**
         * Action: mainwp_after_site_synced
         *
         * Fires upon site synchronization.
         *
         * @param object $pWebsite    Object containing child site info.
         * @param array  $information Array containing information returned from child site.
         * @param mixed  $error       Sync error result.
         * @param mixed  $sync_errors Sync error message if existed.
         * @param array  $other      Additional parameters.
         * @param array  $telem_info  Telemetry information.
         *
         * @since 6.0
         */
        do_action( 'mainwp_after_site_synced', $pWebsite, $information, $error, $sync_errors, $other, $telem_info );

        $post_data = array();

        /**
         * Action: mainwp_site_sync
         *
         * Fires upon successful site synchronization.
         *
         * @param object $pWebsite    Object containing child site info.
         * @param array  $information Array containing information returned from child site.
         * @param bool  $sync_success action success or failed.
         *  @param string  $_error Sync error message if existed.
         * @param array  $post_data Addition post data.
         *
         * @since 3.4
         */
        do_action( 'mainwp_site_sync', $pWebsite, $information, $sync_success, $_error, $post_data );

        return ! $error;
    }


    /**
     * Method get_telem_sync_info.
     *
     * @param  mixed $sync_done
     * @return void
     */
    public static function get_telem_sync_info( $sync_done ) {

        $is_bulk_sync = ! empty( $_POST['bulkSync'] ) ? true : false; // phpcs:ignore -- NOSONAR - superglobal usage is acceptable.

        $tp = 'post_add_site';

        if ( $is_bulk_sync ) {
            $tp = 'manual_bulk';
        } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
            $tp = 'auto_cron';
        } elseif ( isset( $_POST['bulkSync'] ) && ! $is_bulk_sync ) { //phpcs:ignore -- NOSONAR - superglobal usage is acceptable.
            $tp = 'manual_single';
        }

        $trigger = 'system';
        if ( 'manual_single' === $tp || 'manual_bulk' === $tp ) {
            $trigger = 'user_click';
        } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
            $trigger = 'cron';
        }

        $curr_stack       = static::get_current_stack_action();
        $prev_conn_status = in_array( $curr_stack, array( 'sync_before_reconnect', 'sync_reconnect' ) ) ? 'disconnected' : 'connected';
        $new_conn_status  = $sync_done ? 'disconnected' : 'connected';

        return array(
            'sync_type'                  => $tp,
            'trigger'                    => $trigger,
            'previous_connection_status' => $prev_conn_status,
            'new_connection_status'      => $new_conn_status,
            'connection_status_changed'  => $prev_conn_status === $new_conn_status ? false : true,
            'sync_duration_ms'           => MainWP_Execution_Helper::get_run_time( true ),
        );
    }

    /**
     * Method init empty sync values.
     *
     * @param object $pWebsite    Object containing child site info.
     *
     * @return void
     */
    public static function sync_init_empty_values( $pWebsite ) {

        $emptyArray = wp_json_encode( array() );

        $opts = array(
            'site_info',
            'wp_upgrades',
            'premium_upgrades',
            'recent_comments',
            'recent_posts',
            'recent_pages',
            'health_site_status',
            'plugins_outdate_info',
            'themes_outdate_info',
            'directories',
            'plugin_upgrades',
            'theme_upgrades',
            'translation_upgrades',
            'securityIssues',
            'themes',
            'plugins',
            'users',
            'categories',
            'password_policy_options',
        );

        foreach ( $opts as $opt ) {
            MainWP_DB::instance()->update_website_option( $pWebsite, $opt, $emptyArray );
        }
    }


    /**
     * Method get_wp_icon()
     *
     * Get site's icon.
     *
     * @param mixed $siteId site's id.
     *
     * @return array result error or success
     * @throws \MainWP_Exception Error message.
     *
     * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
     * @uses \MainWP\Dashboard\MainWP_Connect::get_file_content()
     * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
     * @uses \MainWP\Dashboard\MainWP_DB_Common::update_website_option()
     * @uses \MainWP\Dashboard\MainWP_Exception
     * @uses \MainWP\Dashboard\MainWP_Logger::debug()
     * @uses \MainWP\Dashboard\MainWP_System_Utility::can_edit_website()
     * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
     * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
     * @uses  \MainWP\Dashboard\MainWP_Utility::ctype_digit()
     */
    public static function get_wp_icon( $siteId = null ) { // phpcs:ignore -- NOSONAR - complex.
        if ( MainWP_Utility::ctype_digit( $siteId ) ) {
            $website = MainWP_DB::instance()->get_website_by_id( $siteId );
            if ( MainWP_System_Utility::can_edit_website( $website ) ) {
                $error = '';
                try {
                    $information = MainWP_Connect::fetch_url_authed( $website, 'get_site_icon' );
                } catch ( MainWP_Exception $e ) {
                    $error = $e->getMessage();
                }

                if ( ! empty( $error ) ) {
                    return array( 'error' => $error );
                } elseif ( isset( $information['faviIconUrl'] ) && ! empty( $information['faviIconUrl'] ) ) {
                    MainWP_Logger::instance()->debug( 'Downloading icon :: ' . esc_html( $information['faviIconUrl'] ) );
                    $content = MainWP_Connect::get_file_content( $information['faviIconUrl'] );
                    if ( ! empty( $content ) ) {

                        MainWP_System_Utility::get_wp_file_system();

                        /**
                         * WordPress files system object.
                         *
                         * @global object
                         */
                        global $wp_filesystem;

                        $dirs     = MainWP_System_Utility::get_mainwp_dir( 'icons', true );
                        $iconsDir = $dirs[0];
                        $filename = basename( $information['faviIconUrl'] );
                        $filename = strtok( $filename, '?' );
                        if ( $filename ) {
                            $filename = 'favi-' . $siteId . '-' . $filename;
                            $size     = false;
                            if ( MainWP_Utility::check_image_file_name( $filename ) ) {
                                $size     = $wp_filesystem->put_contents( $iconsDir . $filename, $content ); // phpcs:ignore --
                            }
                            if ( $size ) {
                                MainWP_Logger::instance()->debug( 'Icon size :: ' . $size );
                                MainWP_DB::instance()->update_website_option( $website, 'favi_icon', $filename );
                                return array( 'result' => 'success' );
                            } else {
                                return array( 'error' => 'Save icon file failed.' );
                            }
                        }
                        return array( 'undefined_error' => true );
                    } else {
                        return array( 'error' => esc_html__( 'Download icon file failed', 'mainwp' ) );
                    }
                } else {
                    return array( 'undefined_error' => true );
                }
            }
        }
        return array( 'result' => 'NOSITE' );
    }
}
