<?php
/**
 * MainWP Logger
 *
 * For custom read/write logging file.
 *
 * @package     MainWP/Dashboard
 */

namespace MainWP\Dashboard;

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

    // phpcs:disable WordPress.WP.AlternativeFunctions -- for custom read/write logging file.

    const UPDATE_CHECK_LOG_PRIORITY    = 10;
    const EXECUTION_TIME_LOG_PRIORITY  = 15;
    const LOGS_AUTO_PURGE_LOG_PRIORITY = 16;
    const LOGS_REGULAR_SCHEDULE        = 18;
    const DEBUG_UPDATES_SCHEDULE       = 19;
    const COST_TRACKER_LOG_PRIORITY    = 20230112;
    const API_BACKUPS_LOG_PRIORITY     = 20240130;
    const CONNECT_LOG_PRIORITY         = 20241001;
    const UPTIME_CHECK_LOG_PRIORITY    = 20241017;
    const UPTIME_NOTICE_LOG_PRIORITY   = 202411106;
    const DISABLED                     = - 1;
    const LOG                          = 0;
    const WARNING                      = 1;
    const INFO                         = 2;
    const DEBUG                        = 3;

    const LOG_COLOR     = '#999999';
    const DEBUG_COLOR   = '#666666';
    const INFO_COLOR    = '#276f86';
    const WARNING_COLOR = '#9f3a38;';

    /**
     * Private variable to hold time start.
     *
     * @var int
     */
    private static $time_start = null;

    /**
     * Private varibale to hold the log file prefix.
     *
     * @var string Default 'mainwp'
     */
    private $logFileNamePrefix = 'mainwp';

    /**
     * Private varibale to hold the log file suffix.
     *
     * @var string Default '.log'
     */
    private $logFileNameSuffix = '.log';

    /**
     * Private varibale to hold the log file max size.
     *
     * @var int Default 0.5
     */
    private $logMaxMB = 0.5;

    /**
     * Private varibale to hold the log file date format.
     *
     * @var string Default 'Y-m-d H:i:s'
     */
    private $logDateFormat = 'Y-m-d H:i:s';

    /**
     * Private varibale to hold the log file output directory.
     *
     * @var mixed Default null
     */
    private $logDirectory = null;

    /**
     * Private varibale to hold the log file priotrity.
     *
     * @var string Disabled
     */
    private $logPriority = self::DISABLED;

    /**
     * Private varibale to hold the log Specific priotrity.
     *
     * @var string Disabled
     */
    private $logSpecific = 0;

    /**
     * Private varibale to hold the auto enable logging actions.
     *
     * @var array Auto enable logging.
     */
    private $autoEnableLoggingActions = array();


    /**
     * Private static varibale to hold the instance.
     *
     * @var mixed Default null
     */
    private static $instance = null;

    /**
     * Method instance()
     *
     * Returns new MainWP_Logger instance.
     *
     * @return self MainWP_Logger
     *
     * @uses \MainWP\Dashboard\MainWP_Logger
     */
    public static function instance() {
        if ( null === static::$instance ) {
            static::$instance = new self();
        }
        return static::$instance;
    }

    /**
     * MainWP_Logger constructor.
     *
     * Run each time the class is called.
     *
     * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
     */
    private function __construct() {

        add_action( 'init', array( $this, 'init' ) ); // Fix the issue where database tables do not exist.

        $enabled  = $this->get_log_status();
        $specific = $this->get_log_specific();

        $enabled  = apply_filters( 'mainwp_log_status', $enabled );
        $specific = apply_filters( 'mainwp_log_specific', $specific );

        $this->set_log_priority( $enabled, $specific );

        $this->autoEnableLoggingActions = array(
            static::CONNECT_LOG_PRIORITY,
        );
    }

    /**
     * Method init.
     */
    public function init() {
        $enabled = get_option( 'mainwp_actionlogs' );
        if ( false === $enabled && ! get_transient( 'mainwp_transient_action_logs' ) ) {
            $sites_count = MainWP_DB::instance()->get_websites_count();
            if ( empty( $sites_count ) ) {
                set_transient( 'mainwp_transient_action_logs', true, 2 * WEEK_IN_SECONDS );
            }
        }
    }

    /**
     * Method set_log_priority()
     *
     * Sets the log priority.
     *
     * @param mixed $logPriority Log priority value.
     * @param mixed $spec_log Specific log.
     */
    public function set_log_priority( $logPriority, $spec_log = 0 ) {
        $this->logPriority = (int) $logPriority;
        $this->logSpecific = (int) $spec_log; // 1 - specific log, 0 - not specific log.
    }


        /**
         * Method enable_log_priority()
         *
         * Sets the log priority.
         *
         * @param mixed $logPriority Log priority value.
         * @param mixed $spec_log Specific log.
         */
    public function enable_log_priority( $logPriority, $spec_log = 1 ) {
        $spec_log    = $spec_log ? 1 : 0;
        $logPriority = intval( $logPriority );
        MainWP_Utility::update_option( 'mainwp_specific_logs', $spec_log );
        MainWP_Utility::update_option( 'mainwp_actionlogs', $logPriority );
        MainWP_Utility::update_option( 'mainwp_actionlogs_enabled_timestamp', time() );
        $this->log_action( 'Action logs set to: ' . $this->get_log_text( $logPriority ), ( $spec_log ? $logPriority : static::LOG ), 2, true );
        $this->set_log_priority( $logPriority, $spec_log );
    }


    /**
     * Method get_log_status()
     *
     * Get log status.
     *
     * @return mixed $enabled log status.
     */
    public function get_log_status() {
        $enabled = get_option( 'mainwp_actionlogs' );
        if ( false === $enabled ) {
            if ( get_transient( 'mainwp_transient_action_logs' ) ) {
                $enabled = self::DEBUG;
            } else {
                $enabled = static::DISABLED;
            }
        }
        return $enabled;
    }


    /**
     * Method get_log_specific()
     *
     * Get log specific status.
     *
     * @return mixed $enabled log status.
     */
    public function get_log_specific() {
        return get_option( 'mainwp_specific_logs', 0 );
    }

    /**
     * Method get_log_type_info()
     *
     * Get log type info.
     *
     * @param int $type Log type value.
     * @param int $logcolor Log color value.
     *
     * @return int $currentColor log color code.
     */
    public function get_log_type_info( $type, $logcolor ) {
        $currentColor = '';
        $prefix       = '';
        if ( static::DEBUG === $type || static::DEBUG === $logcolor ) {
            $currentColor = static::DEBUG_COLOR;
            $prefix       = '[DEBUG]';
        } elseif ( static::INFO === $type || static::INFO === $logcolor ) {
            $currentColor = static::INFO_COLOR;
            $prefix       = '[INFO]';
        } elseif ( static::WARNING === $type || static::WARNING === $logcolor ) {
            $currentColor = static::WARNING_COLOR;
            $prefix       = '[WARNING]';
        } elseif ( static::LOG === $type || static::LOG === $logcolor ) {
            $currentColor = static::LOG_COLOR;
            $prefix       = '[LOG]';
        }
        return array(
            'log_color'  => $currentColor,
            'log_prefix' => $prefix,
        );
    }

    /**
     * Method debug()
     *
     * Grab debug.
     *
     * @param string $text Debug message text.
     *
     * @return string Log debug message.
     */
    public function debug( $text ) {
        return $this->log( $text, static::DEBUG );
    }

    /**
     * Method info()
     *
     * Grab info.
     *
     * @param string $text Info message text.
     *
     * @return string Log info message.
     */
    public function info( $text ) {
        return $this->log( $text, static::INFO );
    }

    /**
     * Method warning()
     *
     * Grab warning information.
     *
     * @param string $text Warning message text.
     *
     * @return string Log warning message.
     */
    public function warning( $text ) {
        return $this->log( $text, static::WARNING );
    }

    /**
     * Method actions()
     *
     * Grab actions information.
     *
     * @param string $text Warning message text.
     * @param int    $priority priority message.
     * @param int    $log_color Set color: 0 - LOG, 1 - WARNING, 2 - INFO, 3- DEBUG.
     * @param bool   $forced forced logging.
     *
     * @return string Log warning message.
     */
    public function log_action( $text, $priority, $log_color = 0, $forced = false ) {
        return $this->log( $text, $priority, $log_color, $forced );
    }


    /**
     * Method log_events().
     *
     * @param string $event_name Event name.
     * @param string $text Log update check.
     */
    public function log_events( $event_name, $text = '' ) {
        switch ( $event_name ) {
            case 'update-check':
                $this->log_action( '[Update Checks] :: ' . $text, static::UPDATE_CHECK_LOG_PRIORITY );
                break;
            case 'regular-schedule':
                $this->log_action( '[Regular Schedule] :: ' . $text, static::LOGS_REGULAR_SCHEDULE );
                break;
            case 'debug-updates-crons':
                $this->log_action( '[Debug updates crons] :: ' . $text, static::DEBUG_UPDATES_SCHEDULE );
                break;
            default:
                break;
        }
    }

    /**
     * Method log_update_check().
     *
     * @param string $text Log update check.
     */
    public function log_update_check( $text = '' ) {
        $this->log_action( $text, static::UPDATE_CHECK_LOG_PRIORITY );
    }

    /**
     * Method log_update_check().
     *
     * @param string $text Log update check.
     */
    public function log_uptime_check( $text = '' ) {
        $this->log_action( $text, static::UPTIME_CHECK_LOG_PRIORITY );
    }

    /**
     * Method log_uptime_notice().
     *
     * @param string $text Log update check.
     */
    public function log_uptime_notice( $text = '' ) {
        $this->log_action( $text, static::UPTIME_NOTICE_LOG_PRIORITY );
    }

    /**
     * Method debug_for_website()
     *
     * Grab website debug and info.
     *
     * @param object $website Child site object.
     * @param string $action Performed action.
     * @param string $message Debug message.
     *
     * @return mixed Website debug info.
     *
     * @uses  \MainWP\Dashboard\MainWP_Utility::get_nice_url()
     */
    public function debug_for_website( $website, $action, $message ) {
        if ( empty( $website ) ) {
            return $this->log( '[-] [-]  ::' . $action . ':: ' . $message, static::DEBUG );
        }

        return $this->log( '[' . $website->name . '] [' . MainWP_Utility::get_nice_url( $website->url ) . ']  ::' . $action . ':: ' . $message, static::DEBUG, 0, false, $website );
    }

    /**
     * Method info_for_website()
     *
     * Grab Website Info.
     *
     * @param object $website Child site object.
     * @param string $action Performed action.
     * @param string $message Info message.
     *
     * @return mixed Website Info.
     *
     * @uses  \MainWP\Dashboard\MainWP_Utility::get_nice_url()
     */
    public function info_for_website( $website, $action, $message ) {
        if ( empty( $website ) ) {
            return $this->log( '[-] [-]  ::' . $action . ':: ' . $message, static::INFO );
        }

        return $this->log( '[' . $website->name . '] [' . MainWP_Utility::get_nice_url( $website->url ) . ']  ::' . $action . ':: ' . $message, static::INFO );
    }

    /**
     * Method warning_for_website()
     *
     * Grab Website Warnings.
     *
     * @param object $website Child site object.
     * @param string $action Performed action.
     * @param string $message Warning message.
     * @param bool   $addStackTrace Add or Don't add stack trace.
     *
     * @return string Website warnings.
     */
    public function warning_for_website( $website, $action, $message, $addStackTrace = true ) {
        $stackTrace = '';
        if ( $addStackTrace ) {
            ob_start();
            // phpcs:ignore -- for debugging.
            debug_print_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS );
            $stackTrace = "\n" . ob_get_clean();
        }
        if ( empty( $website ) ) {
            return $this->log( '[-] [-]  :: ' . $action . ' :: ' . $message . $stackTrace, static::WARNING );
        }

        return $this->log( '[' . $website->name . '] [' . MainWP_Utility::get_nice_url( $website->url ) . ']  ::' . $action . ':: ' . $message . $stackTrace, static::WARNING );
    }

    /**
     * Method log_to_db()
     *
     * Log to database.
     *
     * @param string $text Log record text.
     * @param int    $priority Set priority.
     * @param int    $log_color Set color.
     * @param bool   $forced forced logging.
     * @param mixed  $website website object.
     *
     * @return bool true|false Default is False.
     */
    private function log_to_db( $text, $priority, $log_color = 0, $forced = false, $website = false ) {

        if ( static::DISABLED === $this->logPriority ) {
            return false;
        }

        $priority = (int) apply_filters( 'mainwp_log_to_db_priority', $priority, $website );

        $do_log = false;

        if ( 1 === $this->logSpecific ) { // 1 - specific log, 0 - not specific log.
            if ( $this->logPriority === $priority ) { // specific priority number saved setting.
                $do_log = true;
            }
        } elseif ( $this->logPriority >= $priority ) {
            $do_log = true;
        }

        $do_log = apply_filters( 'mainwp_log_do_to_db', $do_log, $website );

        if ( ! $forced && ! $do_log ) {
            return false;
        }

        $text = $this->prepare_log_info( $text );

        do_action( 'mainwp_before_log_data', $text, $priority, $log_color );

        if ( defined( 'DOING_CRON' ) && DOING_CRON && 'CRON' !== strtoupper( substr( $text, 0, 4 ) ) ) {
            $text = 'CRON :: ' . $text;
        }

        /**
         * Current user global.
         *
         * @global string
         */
        global $current_user;

        $user = '';
        if ( ! empty( $current_user ) && ! empty( $current_user->user_login ) ) {
            $user = $current_user->user_login;
        } elseif ( defined( 'WP_CLI' ) ) {
            $user = 'WP_CLI';
        } elseif ( defined( 'DOING_CRON' ) ) {
            $user = 'DOING_CRON';
        }

        $data = array();

        $data['log_content']   = $text;
        $data['log_user']      = $user;
        $data['log_type']      = $priority;
        $data['log_color']     = intval( $log_color );
        $data['log_timestamp'] = time();

        $data = apply_filters( 'mainwp_log_to_db_data', $data );

        MainWP_DB_Common::instance()->insert_action_log( $data );

        return true;
    }

    /**
     * Method log()
     *
     * Create Log File.
     *
     * @param string $text Log record text.
     * @param int    $priority Set priority.
     * @param int    $log_color Set color.
     * @param bool   $forced forced logging.
     * @param mixed  $website Site object.
     *
     * @return bool true|false Default is False.
     */
    private function log( $text, $priority,  $log_color = 0, $forced = false, $website = false ) { // phpcs:ignore -- NOSONAR - complex function.

        if ( in_array( $priority, $this->autoEnableLoggingActions ) && (int) $this->logPriority !== (int) $priority ) {
            $this->enable_log_priority( $priority, 1 );
        }

        if ( static::DISABLED === $this->logPriority ) {
            return false;
        }

        $log_to_db = apply_filters( 'mainwp_logger_to_db', true, $website );

        if ( $log_to_db ) {
            return $this->log_to_db( $text, $priority, $log_color, $forced, $website );
        }

        $text = $this->prepare_log_info( $text );

        $do_log = false;
        if ( 1 === $this->logSpecific ) { // 1 - specific log, 0 - not specific log.
            if ( $this->logPriority === $priority ) { // specific priority number saved setting.
                $do_log = true;
            }
        } elseif ( $this->logPriority >= $priority ) {
            $do_log = true;
        }

        if ( $do_log ) {
            $this->logCurrentFile = $this->get_log_file();
            $logCurrentHandle     = fopen( $this->logCurrentFile, 'a+' );

            if ( $logCurrentHandle ) {
                $time   = gmdate( $this->logDateFormat );
                $prefix = '[' . $this->get_log_text( $priority ) . ']';

                /**
                 * Current user global.
                 *
                 * @global string
                 */
                global $current_user;

                if ( ! empty( $current_user ) && ! empty( $current_user->user_login ) ) {
                    $prefix .= ' [administrator]';
                }

                fwrite( $logCurrentHandle, $time . ' ' . $prefix . ' ' . $text . "\n" );
                fclose( $logCurrentHandle );
            }

            if ( filesize( $this->logCurrentFile ) > ( $this->logMaxMB * 1048576 ) ) {
                $logCurrentHandle = fopen( $this->logCurrentFile, 'a+' );
                if ( $logCurrentHandle ) {
                    fseek( $logCurrentHandle, 0 );
                    $newLogFile   = $this->logCurrentFile . '.tmp';
                    $newLogHandle = false;
                    $chunkSize    = filesize( $this->logCurrentFile ) - ( $this->logMaxMB * 1048576 );
                    while ( is_resource( $logCurrentHandle ) && ! feof( $logCurrentHandle ) && ( $chunkSize > 0 ) ) {
                        $content = fread( $logCurrentHandle, $chunkSize );
                        if ( false === $content ) {
                            break;
                        }
                        $pos = strrpos( $content, "\n" );
                        if ( $newLogHandle ) {
                            fwrite( $newLogHandle, $content );
                        } elseif ( $pos ) {
                            if ( ! $newLogHandle ) {
                                $newLogHandle = fopen( $newLogFile, 'w+' );
                            }
                            fwrite( $newLogHandle, substr( $content, $pos + 1 ) );
                        }
                    }

                    if ( is_resource( $logCurrentHandle ) ) {
                        fclose( $logCurrentHandle );
                    }

                    if ( $newLogHandle ) {
                        fclose( $newLogHandle );
                        wp_delete_file( $this->logCurrentFile );
                        if ( file_exists( $newLogFile ) ) {
                            rename( $newLogFile, $this->logCurrentFile );
                        }
                    }
                }
            }

            return true;
        }

        return false;
    }


    /**
     * Method prepare_log_info()
     *
     * Prepare log data.
     *
     * @param mixed $data Log data.
     *
     * @return mixed $data filtered data.
     */
    public function prepare_log_info( $data ) {
        $patterns[0]    = '/user=([^\&]+)\&/';
        $replacement[0] = 'user=xxxxxx&';
        $patterns[1]    = '/alt_user=([^\&]+)\&/';
        $replacement[1] = 'alt_user=xxxxxx&';
        $patterns[2]    = '/\&server=([^\&]+)\&/';
        $replacement[2] = '&server=xxxxxx&';
        $data           = preg_replace( $patterns, $replacement, $data );
        return $data;
    }

    /**
     * Method prepend()
     *
     * Prepend content to log file.
     *
     * @param mixed $str Custom string.
     * @param mixed $filename Filename.
     */
    public function prepend( $str, $filename ) {
        $context = stream_context_create();
        $fp      = fopen( $filename, 'r', 1, $context );
        $tmpname = md5( $str ); // NOSONAR - safe for salt file name.
        file_put_contents( $tmpname, $str );
        file_put_contents( $tmpname, $fp, FILE_APPEND );
        fclose( $fp );
        wp_delete_file( $filename );
        rename( $tmpname, $filename );
    }

    /**
     * Method init_execution_time().
     *
     * @param string $time_index index for timer.
     *
     * Init execution time start value.
     */
    public function init_execution_time( $time_index = '' ) {
        if ( null === static::$time_start || ! is_array( static::$time_start ) ) {
            static::$time_start = array( 'start' => microtime( true ) );
            $this->log_action( 'execution time :: init :: [start]', static::EXECUTION_TIME_LOG_PRIORITY );
        }

        if ( ! empty( $time_index ) && is_string( $time_index ) && 'start' !== $time_index ) {
            static::$time_start[ $time_index ] = microtime( true );
            $this->log_action( 'execution time :: init :: [' . $time_index . ']', static::EXECUTION_TIME_LOG_PRIORITY );
        }
    }

    /**
     * Method log_execution_time().
     *
     * @param string $text Log record text.
     *
     * Log the execution time value.
     */
    public function log_execution_time( $text = '' ) {
        $exec_time = $this->get_execution_time();
        $this->log_action( 'execution time :: ' . ( ! empty( $text ) ? (string) $text : '<empty>' ) . ' :: [time=' . round( $exec_time, 4 ) . '](seconds)', static::EXECUTION_TIME_LOG_PRIORITY );
    }


    /**
     * Method get_execution_time().
     *
     * Get the execution time value.
     *
     * @param string $time_index Index for timer.
     *
     * @return int execution time.
     */
    private function get_execution_time( $time_index = '' ) {

        if ( empty( static::$time_start ) ) {
            return 0;
        }

        $start = 0;
        if ( ! empty( $time_index ) ) {
            $start = is_array( static::$time_start ) && isset( static::$time_start[ $time_index ] ) ? static::$time_start[ $time_index ] : 0;
        }

        if ( empty( $start ) ) {
            $start = is_array( static::$time_start ) && isset( static::$time_start['start'] ) ? static::$time_start['start'] : 0;
        }

        if ( empty( $start ) ) {
            return 0;
        }
        return microtime( true ) - $start; // seconds.
    }

    /**
     * Method get_log_file()
     *
     * Grab Log File.
     *
     * @return mixed Log File.
     */
    public function get_log_file() {
        if ( empty( $this->logDirectory ) ) {
            $this->logDirectory = MainWP_System_Utility::get_mainwp_dir();
            $this->logDirectory = $this->logDirectory[0];
        }
        return $this->logDirectory . $this->logFileNamePrefix . $this->logFileNameSuffix;
    }

    /**
     * Method get_log_text()
     *
     * Grab what type of log entry.
     *
     * @param mixed $priority Set priority.
     *
     * @return string LOG -OR- DISABLED|DEBUG|INFO|WARNING|INFO UPDATE
     */
    public function get_log_text( $priority ) {
        switch ( $priority ) {
            case static::DISABLED:
                return 'DISABLED';
            case static::DEBUG:
                return 'DEBUG';
            case static::INFO:
                return 'INFO';
            case static::WARNING:
                return 'WARNING';
            default:
                return 'SPEC LOG';
        }
    }

    /**
     * Method check_log_daily()
     *
     * Daily checks to clear the log file.
     */
    public function check_log_daily() {
        $status = (int) $this->get_log_status();
        if ( 0 >= $status ) {
            return;
        }

        $today_m_y = date_i18n( 'd/m/Y' ); //phpcs:ignore -- local time.
        // one time per day.
        if ( get_option( 'mainwp_logger_check_daily' ) !== $today_m_y ) {
            $num_days = apply_filters( 'mainwp_logger_keep_days', 7 );
            MainWP_DB_Common::instance()->delete_action_log( $num_days );
            MainWP_Utility::update_option( 'mainwp_logger_check_daily', $today_m_y );

            $enabled_time = get_option( 'mainwp_actionlogs_enabled_timestamp', false );
            if ( false === $enabled_time ) {
                MainWP_Utility::update_option( 'mainwp_actionlogs_enabled_timestamp', time() );
            } elseif ( $enabled_time + $num_days * DAY_IN_SECONDS < time() ) {
                MainWP_Utility::update_option( 'mainwp_actionlogs', static::DISABLED );
            }
        }
    }

    /**
     * Method clear_log_db()
     *
     * Clear the log file.
     */
    public function clear_log_db() {
        MainWP_DB_Common::instance()->delete_action_log();
    }

    /**
     * Method clear_log()
     *
     * Clear the log file.
     */
    public function clear_log() {
        $logFile = $this->get_log_file();
        wp_delete_file( $logFile );
        $fh = fopen( $logFile, 'w' );
        if ( false === $fh ) {
            return;
        }
        fclose( $fh );
    }

    /**
     * Method show_log_db()
     *
     * Grab log file and build output to screen.
     */
    public function show_log_db() { //phpcs:ignore -- NOSONAR - complexity.

        echo '<div class="ui hidden divider"></div>';
        echo '<div class="ui divided padded relaxed list" local-datetime="' . date( 'Y-m-d H:i:s' ) . '">'; // phpcs:ignore -- local time.

        $limit = 500;

        //phpcs:disable WordPress.Security.NonceVerification
        $paged = isset( $_GET['paged'] ) ? intval( $_GET['paged'] ) : 0; //phpcs:ignore -- NOSONAR -ok.

        if ( $paged <= 0 ) {
            $paged = 0;
        } else {
            --$paged;
        }

        $params = array();

        if ( isset( $_GET['hour'] ) && ! empty( $_GET['hour'] ) ) { // phpcs:ignore -- local time.
            $params['hour'] = intval( $_GET['hour'] ); // phpcs:ignore -- local time.
        } else {
            $params['hour'] = $limit;
        }

        $order = isset( $_GET['order'] ) ? sanitize_text_field( wp_unslash( $_GET['order'] ) ) : ''; //phpcs:ignore -- NOSONAR -ok.

        $total = MainWP_DB::instance()->get_var_field( MainWP_DB_Common::instance()->get_sql_log( $paged, $order, array( 'count' => true ) ) );

        $rows = MainWP_DB::instance()->query( MainWP_DB_Common::instance()->get_sql_log( $paged, $order, $params ) );

        $count = $rows ? MainWP_DB::num_rows( $rows ) : 0;

        $show_info = '';

        if ( isset( $_GET['hour'] ) ) {
            $show_info = $count . ' latest items from a total of ' . $total;
        } elseif ( isset( $_GET['paged'] ) ) { //phpcs:ignore -- NOSONAR -ok.
            $from      = $limit * $paged;
            $show_info = $count . ' items, from ' . $from . ' - ' . ( $from + $limit ) . ' of ' . $total . ' total.';
        }

        if ( ! empty( $show_info ) ) {
            echo '<p><strong>' . esc_html__( 'Showing ', 'mainwp' ) . ':</strong> ' . $show_info; //phpcs:ignore -- NOSONAR ok.
        }
        //phpcs:enable WordPress.Security.NonceVerification

        $start_wrapper = '<span class="ui mini label mainwp-action-log-show-more">Click to See Response</span><div class="mainwp-action-log-site-response" style="display: none;">';
        $end_wrapper   = '</div>';

        while ( $rows && ( $row  = MainWP_DB::fetch_object( $rows ) ) ) {
            $line = $row->log_content;
            if ( 120 * 1024 < strlen( $line ) ) {
                $line = '[Data row too long]';
            }

            $time = gmdate( $this->logDateFormat, MainWP_Utility::get_timestamp( $row->log_timestamp ) );

            $showInfo = $this->get_log_type_info( $row->log_type, $row->log_color );

            $currentColor = $showInfo['log_color'];

            $prefix = $time . ' ' . $showInfo['log_prefix'];

            $line = htmlentities( $line );

            if ( false !== strpos( $line, '[data-start]' ) ) {
                $line = str_replace( '[data-start]', $start_wrapper, $line );
                $line = str_replace( '[data-end]', $end_wrapper, $line );
            }

            echo '<div class="item" style="color:' . esc_html( $currentColor ) . '"><div class="mainwpactionlogsline">';

            echo $prefix . ' ' . $line; // phpcs:ignore WordPress.Security.EscapeOutput

            echo '</div></div>';
        }

        echo '</div></div>';

        echo '</div>';

        ?>
        <div class="ui large modal" id="mainwp-action-log-response-modal">
            <i class="close icon mainwp-reload"></i>
            <div class="header"><?php esc_html_e( 'Child Site Response', 'mainwp' ); ?></div>
            <div class="content">
                <div class="ui info message"><?php esc_html_e( 'To see the response in a more readable way, you can copy it and paste it into some HTML render tool, such as Codepen.io.', 'mainwp' ); ?>
                </div>
            </div>
            <div class="scrolling content content-response"></div>
            <div class="actions">
                <button class="ui green button mainwp-response-copy-button"><?php esc_html_e( 'Copy Response', 'mainwp' ); ?></button>
            </div>
        </div>
        <?php
    }

    /**
     * Method show_log_file()
     *
     * Grab log file and build output to screen.
     */
    public function show_log_file() { // phpcs:ignore -- NOSONAR - complex.
        $logFile = $this->get_log_file();

        if ( ! file_exists( $logFile ) ) {
            return;
        }

        $fh = fopen( $logFile, 'r' );
        if ( false === $fh ) {
            return;
        }

        $previousColor            = '';
        $fontOpen                 = false;
        $firstLinePassedProcessed = false;
        echo '<div class="ui hidden divider"></div>';
        echo '<div class="ui divided padded relaxed list">';
        while ( false !== ( $line = fgets( $fh ) ) ) {
            $currentColor = $previousColor;
            if ( stristr( $line, '[DEBUG]' ) ) {
                $currentColor    = static::DEBUG_COLOR;
                $firstLinePassed = true;
            } elseif ( stristr( $line, '[INFO]' ) ) {
                $currentColor    = static::INFO_COLOR;
                $firstLinePassed = true;
            } elseif ( stristr( $line, '[WARNING]' ) ) {
                $currentColor    = static::WARNING_COLOR;
                $firstLinePassed = true;
            } elseif ( stristr( $line, '[LOG]' ) ) {
                $currentColor    = static::LOG_COLOR;
                $firstLinePassed = true;
            } else {
                $firstLinePassed = false;
            }

            if ( $firstLinePassedProcessed && ! $firstLinePassed ) {
                echo ' <span class="ui mini label mainwp-action-log-show-more">Click to See Response</span></div><div class="mainwp-action-log-site-response" style="display: none;">';
            }

            $firstLinePassedProcessed = $firstLinePassed;

            if ( $currentColor !== $previousColor ) {
                if ( $fontOpen ) {
                    echo '</div></div>';
                }

                echo '<div class="item" style="color:' . esc_html( $currentColor ) . '"><div class="mainwpactionlogsline">';
                $fontOpen = true;
            }

            echo esc_html( htmlentities( $line ) );
        }

        if ( $fontOpen ) {
            echo '</div></div>';
        }

        echo '</div>';

        ?>
        <div class="ui large modal" id="mainwp-action-log-response-modal">
            <i class="close icon mainwp-reload"></i>
            <div class="header"><?php esc_html_e( 'Child Site Response', 'mainwp' ); ?></div>
            <div class="content">
                <div class="ui info message"><?php esc_html_e( 'To see the response in a more readable way, you can copy it and paste it into some HTML render tool, such as Codepen.io.', 'mainwp' ); ?>
                </div>
            </div>
            <div class="scrolling content content-response"></div>
            <div class="actions">
                <button class="ui green button mainwp-response-copy-button"><?php esc_html_e( 'Copy Response', 'mainwp' ); ?></button>
            </div>
        </div>
        <?php

        fclose( $fh );
    }
}
