<?php


/*
 * Screen site with Lighthouse CLI
 * Usage:
 * Make sure you have Lighthouse CLI installed
 * npm install -g lighthouse
 *
 * wp performance run
 * wp performance run http://site.se
 *
*/


class Performance extends WP_CLI_Command
{

    private $rootDir;
    private $screeningNum = 1; // Numbers of screenings each time
    private $url;
    private $active_plugins;
    private $tmp_folder = WEBIEN_PLUGIN_PATH."/src/Performance/tmp/";

    public function run($args, $assoc_args)
    {

        // Check for url, else use startpage from ENV
        $this->url = isset( $args[0] ) ? $args[0] : WP_HOME;

        $root_dir = dirname(WEBIEN_PLUGIN_PATH, 4);
        $this->rootDir = $root_dir;


        // First, check that we have whats needed in terms of software
        if(!$this->shell("wp core version")){
            die('WP CLI is not installed');
        }
        if(intval(substr($this->shell("node --version"),1,2)) < 12){
            die('NODE 12 or greater required.');
        }

        // First check what plugins we have active
        $this->active_plugins = get_option('active_plugins');


        // Reorder so that plugins that has other plugins dependent on them comes first.
        $prioritize = ["elementor/elementor.php","elementor-pro/elementor-pro.php","jet-engine/jet-engine.php","woocommerce/woocommerce.php"];
        foreach (array_reverse($prioritize) as $plugin){
            // Remove plugin from array than add it to beginning again
            if (($key = array_search($plugin, $this->active_plugins)) !== false) {
                unset($this->active_plugins[$key]);
                array_unshift($this->active_plugins, $plugin);
            }
        }



        // Now deactivate all plugins so we can start our screening from scratch
        deactivate_plugins( $this->active_plugins );

        array_unshift($this->active_plugins, 'Standard WP + MU plugins');

        foreach ($this->active_plugins as $i => $plugin) {
            $this->do_screening($i, $plugin);
        }

        // When screening is all done, lets build a report
        $url = $this->create_report();


        WP_CLI::success( 'Rapport ==> ' . $url );
    }


    public function do_screening($order, $plugin)
    {
        // Create temp folder
        $this->shell("mkdir -p ".$this->tmp_folder);


        // Reactivate plugin if not first run (clean wp)
        if($order !== 0) {
            activate_plugin($plugin, $redirect = '', $network = false, $silent = false);
        }
        // Start screening
        $count = 0;
        while($count < $this->screeningNum){
            $this->shell("lighthouse ".$this->url." --output json --output-path ".$this->tmp_folder.$order."_".$count.".json --preset=desktop --only-categories=performance");
            $count++;
        }

    }


    public function create_report()
    {
        $main_arr = [];
        $final_score = 0;

        // Get plugins data
        $plugins_data = get_plugins();

        // First, loop over each plugin
        $plugin = 0;
        while($plugin < count($this->active_plugins)){
            // Second, loop each screening of that plugin
            $screening = 0;
            $score = [];
            $response_time = [];
            $plugin_name = isset($plugins_data[$this->active_plugins[$plugin]]) ? $plugins_data[$this->active_plugins[$plugin]]['Name'] : $this->active_plugins[$plugin];
            while($screening < $this->screeningNum){
                $json = file_get_contents($this->tmp_folder.$plugin."_".$screening.".json");
                $json_a = json_decode($json,true);

                // Add metrics
                array_push($score, round(floatval($json_a['categories']['performance']['score'])*100, 1) );
                array_push($response_time, round(floatval($json_a['audits']['server-response-time']['numericValue'])/100, 2) );

                // If last
                if($screening == ($this->screeningNum-1)){
                    $final_score = $this->calculate_median($score);
                    $final_response = $this->calculate_median($response_time);

                    $main_arr['scores'][] = $final_score;
                    $main_arr['response_time'][] = $final_response;
                    $main_arr['labels'][] = $plugin_name;
                }

                $screening++;

            }
            $plugin++;
        }

        // Build report file from template
        ob_start();

        $labels = json_encode($main_arr['labels']);
        $response_times = json_encode($main_arr['response_time']);
        $scores = json_encode($main_arr['scores']);

        include(WEBIEN_PLUGIN_PATH.'/src/Performance/report.php');
        $html = ob_get_clean();
        $timestamp = time();
        $filepath = WEBIEN_PLUGIN_PATH ."/src/Performance/".$timestamp.".html";
        $file = fopen($filepath,"wb");
        fwrite($file,$html);
        fclose($file);

        // Remove temp files and move report to uploads
        $this->shell("rm -rf ".$this->tmp_folder);

        $uploads = wp_upload_dir();
        $destination = $uploads['path'].'/'.$timestamp.'.html';
        if(defined('S3_UPLOADS_BUCKET')){
            $this->shell("aws s3 mv ".$filepath." ".$destination);
        } else {
            $this->shell("mv ".$filepath." ".$destination);
        }


        return $uploads['url'].'/'.$timestamp.'.html';

    }


    private function shell(string $cmd) {
        //$this->log("Running command", ["cmd" => $cmd, "path" => $this->rootPath]);
        return shell_exec("cd $this->rootDir; " . $cmd);
    }


    private function calculate_median($arr)
    {
        $count = count($arr); //total numbers in array
        $middleval = floor(($count-1)/2); // find the middle value, or the lowest middle value
        if($count % 2) { // odd number, middle is the median
            $median = $arr[$middleval];
        } else { // even number, calculate avg of 2 medians
            $low = $arr[$middleval];
            $high = $arr[$middleval+1];
            $median = (($low+$high)/2);
        }
        return $median;
    }


}

WP_CLI::add_command('performance', 'Performance');