<?php

namespace Modules\Systeme\Controller;

use GuzzleHttp\Psr7\Response;
use Helpers\Outil\Roles;
use Skeleton\Controller\Controller;
use Helpers\Fichier\Fichier;
use Helpers\Session\ParseBase1;
use Helpers\Ariane\Ariane;

class LogSystemeController extends Controller
{
    public function indexAction(): string
    {
        $post         = $this->request->getParsedBody();
        $logDirectory = $this->getLogDirectory()->log;
        $trad         = $this->getTranslationService();
        date_default_timezone_set('Europe/Paris');
        Ariane::generate(0, $trad->t('Système'), $post);

        if ($_SESSION['Session_NumClient'] == 0) {
            $payload = [
                'user'=> $_SESSION['Session_Login'],
                'exp' => time()+60*60*1,
                'sessionId' => session_id(),
            ];
            
            $tokenSes = \Firebase\JWT\JWT::encode($payload, $this->JWTKEY, 'HS256');
        }
    

        // Vérifier l'espace libre sur le disque C
        $free_space = disk_free_space('C:/');
        $total_space = disk_total_space('C:/');
        
        $free_space_c = round($free_space / (1024 * 1024 * 1024), 2);
        $total_free_space_c = round($total_space / (1024 * 1024 * 1024), 2);
        $using_space_c = $total_free_space_c - $free_space_c;
        

        $errorLogPath       = $this->getErrorLogPath();
        $rootLogDirectory   = substr($logDirectory, 0, 3);
        $diskSpace          = disk_free_space($rootLogDirectory);
        $diskTotalSpace     = disk_total_space($rootLogDirectory);
        $diskSpaceFormatted = number_format($diskSpace / (1024 * 1024 * 1024), decimals: 2) ;
        $diskTotalFormatted = number_format($diskTotalSpace / (1024 * 1024 * 1024), 2) ;

  
        //disque E
        $diskOccupiedSpace     = $diskTotalSpace - $diskSpace;
        $diskOccupiedFormatted = number_format($diskOccupiedSpace / (1024 * 1024 * 1024), 2);
        $diskOccupiedPercent = ($diskOccupiedSpace / $diskTotalSpace) * 100;
        $login               = '';
                
        // if (isset($_SERVER['MODSECURITY'])) {
        //     echo "ModSecurity est activé.";
        // } else {
        //     echo "ModSecurity n'est pas activé.";
        // }

        $php_ini = php_ini_loaded_file();
        $fileNameLogin = 'PHP_SAML2_nameid.txt';
        $loginDirectory = $this->getLogDirectory()->tmp . $fileNameLogin;
        if (file_exists($loginDirectory)) {
            $login = $loginDirectory;
            $rootSaml = $this->router->generateUri('Systeme.GestionSystem.downloadLog', ['name' => basename($loginDirectory, ".txt")]);
        }

        $phpErrorLogData      = [];
        $generalLogFilesData  = [];
        $oxasasLogFilesData   = [];
        $oxabatchLogFilesData = [];
        $phpIniData           = [];
        $generalLogReqData    = [];


        $generalErrorLogFiles    = glob($this->getPhpIniDirectory() . '\PHP_error.log*');
        $generalOxasasLogFiles   = glob($logDirectory . '/*GENERALERRORLOG_Oxasas.log');
        $generalOxabatchLogFiles = glob($logDirectory . '/*GENERALERRORLOG_Oxabatch.log');
        $generalPhpIniFiles      = glob($this->getPhpIniDirectory() . '\php.ini');
        $generalLogRequete       = glob($logDirectory . '/*_req_SQLServer.log');
        
        $phpErrorLogData = $this->visuTabConstruct($generalErrorLogFiles, 'PHP Error Log');

        $modSecurity =  $this->visuTabConstruct($generalErrorLogFiles, 'ModSecurity');

        $generalErrorLogFiles = array_merge(
            /** @phpstan-ignore-next-line */
            glob($logDirectory . '*GENERALERRORLOG_OXAPROC.log'),
            /** @phpstan-ignore-next-line */
            glob($logDirectory . '*GENERALERRORLOG_Oxaproc.log')
        );
        // Below every table of error from their own use
        $generalLogFilesData  = $this->visuTabConstruct($generalErrorLogFiles, 'GENERALERRORLOG_OXAPROC');
        $oxasasLogFilesData   = $this->visuTabConstruct($generalOxasasLogFiles, 'GENERALERRORLOG_Oxasas');
        $oxabatchLogFilesData = $this->visuTabConstruct($generalOxabatchLogFiles, 'GENERALERRORLOG_Oxabatch');
        $generalLogReqData    = $this->visuTabConstruct($generalLogRequete, 'REQUETE_OXAPROC');

        $phpInidata           = $this->visuTabConstruct($generalPhpIniFiles, 'PHP_INI');

        $allValue =  array_merge($phpErrorLogData, $generalLogReqData, $generalLogFilesData, $oxasasLogFilesData, $oxabatchLogFilesData, $phpInidata);

        return $this->renderer->render('@Systeme/errorLog', [
            'menuActive'            => 'Systeme',
            'listeLog'              => $allValue,
            'collectionDiskRoot'     => $this->serverCheck(),
            'rootLogDirectory'      => $rootLogDirectory,
            'diskSpaceFormatted'    => $diskSpaceFormatted,
            'diskTotalFormatted'    => $diskTotalFormatted, // disque total :E
            'diskOccupiedFormatted' => $diskOccupiedFormatted,
            'diskOccupiedPercent'   => $diskOccupiedPercent,
            'loginSAML'             => $login,
            'free_space_c'          => $free_space_c,
            'total_free_space_c'    => $total_free_space_c,
            'using_space_c'         => $using_space_c,
            'downloadLoginSaml'     => $rootSaml ?? '',

            'tokenSession'          => $tokenSes??'',

            'activeTracingRequete'  => $_SESSION['activeTracingRequete'],
        ]);
    }

    /**
     * @param mixed $array
     * @param mixed $option
     * @return array<mixed>
     */
    public function visuTabConstruct($array, $option = null): array
    {
        $errorlog = [];
        if ($array !== false) {
            foreach ($array as $file) {
                // Dans le cas ou on veut la concatenation du chemin fichier  avec la date du jours , rajouter ceci au tableau
                // 'path' => $file. '_'. str_replace('/', '', date('Ymd')),
                $errorlog[$option][] = [
                    'path' => $file,
                    'name' => basename($file),
                    'size' => filesize($file),
                    'date' => date("d/m/Y H:i:s", (int)filemtime($file)),
                    'dataTime' => filemtime($file),
                    'downloadLink' => $this->router->generateUri('Systeme.GestionSystem.downloadLog', ['name' => basename($file, ".log")]),
                    'visualiser' => $this->router->generateUri('Systeme.GestionSystem.visualiserErrorLog', ['name' => explode('.', basename($file))[0] ])
                ];
            }
        }

        return $errorlog;
    }

    public function visualiserErrorLogAction(): string
    {
        $post         = $this->request->getParsedBody();
        $trad         = $this->getTranslationService();
        $modeVisu     = $this->request->getAttribute('name');
        $logDirectory = $this->getLogDirectory()->log;
        $errorLogPath = $this->getErrorLogPath();
        Ariane::generate(1, $trad->t('Visualiser'), $post);
        $titre = $trad->t('Visualisation des logs PHP');

        $error = null;
        if (!$errorLogPath) {
            throw new \Exception("Impossible de récupérer le chemin des fichiers de log.");
        }

        switch (trim($modeVisu)) {
            case 'PHP_error':
                $error   = glob($this->getPhpIniDirectory() . '\PHP_error.log*');
                break;
            case 'GENERALERRORLOG_Oxaproc':
                $error = array_merge(
                    /** @phpstan-ignore-next-line */
                    glob($logDirectory . '*GENERALERRORLOG_OXAPROC.log'),
                    /** @phpstan-ignore-next-line */
                    glob($logDirectory . '*GENERALERRORLOG_Oxaproc.log')
                );
                break;
            case 'GENERALERRORLOG_Oxasas':
                $error   = glob($logDirectory . '/*GENERALERRORLOG_Oxasas.log');
                break;
            case 'GENERALERRORLOG_Oxabatch':
                $error   = glob($logDirectory . '/*GENERALERRORLOG_Oxabatch.log');
                break;
            case 'php':
                $error   = glob($this->getPhpIniDirectory() . '\php.ini');
                break;
        }


        if ($error !== false) {
            foreach ($error as $file) {
                $fileContent = '';
                // Il faut traiter la date exact du fichier qu'on vas ouvrir ci-dessous
                $pointeur = fopen($file, "r");
                if ($pointeur) {
                    while (!feof($pointeur)) {
                        $fileContent .= fgets($pointeur);
                    }
                    fclose($pointeur);
                }
    
                $phpErrorLogData[] = [
                    'name' => basename($file),
                    'content' => $fileContent,
                ];
            }
        }
        return $this->renderer->render('@Systeme/errorLogVisualiser', [
            'phpErrorLogData' => $phpErrorLogData??[],
            'titre'           => $titre,
        ]);
    }
    
    
    public function downloadLogAction(): string
    {
        $name = $this->request->getAttribute('name');
        
        ($name != 'php.ini') ? $name .= ".log" : '';
        // Récupérer le chemin du fichier de log d'erreur
        $filePath = null;
        

        if (strpos($name, 'PHP_error') !== false || trim($name) == 'php.ini') {
            $errorLogPath = $this->getErrorLogPath();
            $filePath = ($errorLogPath != null) ? $this->getPhpIniDirectory() . '\\' . $name : null;
        } else {
            $logDirectory = $this->getLogDirectory()->log;
            $filePath = $logDirectory . '\\' . $name;
        }
        
        if (!file_exists($filePath)) {
            throw new \Exception("Le fichier de log n'existe pas ou le chemin est invalide.");
        }

        // Définir un nom pour le fichier téléchargé


        return Fichier::UploadClient($filePath, $name, true);
    }




    public function serverCheck(): mixed
    {
        $server_check_version = '1.0.4';
        $start_time = microtime(true);
        $merge1 = [];
        
        $operating_system = PHP_OS_FAMILY;

        $phpload = round(memory_get_usage() / 1000000, 2);

        $returnCollection =[];

        array_push($returnCollection, [
            'phpVersion' => phpversion(),
            'phpLoad' => $phpload
        ]);

        if ($operating_system === 'Windows') {
            // Win CPU
            $command = 'powershell -Command "Get-WmiObject Win32_OperatingSystem | Select-Object TotalVisibleMemorySize,FreePhysicalMemory"';


            // Exécution de la commande PowerShell
            $output1 = shell_exec($command);

            // Analyser les résultats
            // preg_match('/TotalVisibleMemorySize=(\d+)/', $output, $totalMemoryMatch);
            // preg_match('/FreePhysicalMemory=(\d+)/', $output, $freeMemoryMatch);
            preg_match_all('/\d+/', (string)$output1, $totalMemoryMatch);

            $totalMemory = $totalMemoryMatch[0][0] ?? 0;
            $freeMemory = $totalMemoryMatch[0][1] ?? 0;
            
            
            // Convertir les valeurs de Ko en Mo
            $totalMemoryMB = $totalMemory != 0 ? round(((float)$totalMemory / 1024), 2):0;
            $freeMemoryMB = $freeMemory != 0 ? round(((float)$freeMemory / 1024), 2):0;
            

            // echo "Mémoire Totale: $totalMemoryMB MB\n";
            // echo "Mémoire Libre: $freeMemoryMB MB\n";
            
            $memoryUsagePercentage = ($freeMemoryMB / $totalMemoryMB) * 100;

            // Afficher le pourcentage
            // echo "Pourcentage de mémoire utilisée : " . round($memoryUsagePercentage, 2) . "%\n";

            $merge = array_merge(
                $returnCollection[0],
                [
                    'memoryTotal' => $totalMemory,
                    'freeMemory' => $freeMemory,
                    'memoryUsingPercentage' => round($memoryUsagePercentage, 2)
                ]
            );
            
            $command = 'wmic cpu get NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed, Name /value';
            $commandCache = 'wmic cpu get L2CacheSize, L3CacheSize /value';
            // Exécution de la commande
            $output2 = shell_exec($command);
            $outputCach = shell_exec($commandCache);

            // Appliquer des expressions régulières pour extraire les données
            preg_match('/L2CacheSize=(\d+)/', (string)$outputCach, $l2CacheMatch);
            preg_match('/L3CacheSize=(\d+)/', (string)$outputCach, $l3CacheMatch);
            
            preg_match('/NumberOfCores=(\d+)/', (string)$output2, $coresMatch);
            preg_match('/NumberOfLogicalProcessors=(\d+)/', (string)$output2, $logicalProcessorsMatch);
            preg_match('/MaxClockSpeed=(\d+)/', (string)$output2, $clockSpeedMatch);
            preg_match('/Name=(.+)/', (string)$output2, $nameMatch);


            // Vérifier si toutes les correspondances ont été trouvées
            if (isset($coresMatch[1], $logicalProcessorsMatch[1], $clockSpeedMatch[1], $nameMatch[1])) {
                $cores = $coresMatch[1];
                $logicalProcessors = $logicalProcessorsMatch[1];
                $clockSpeed = $clockSpeedMatch[1];
                $name = $nameMatch[1];

                $l2Cache = $l2CacheMatch[1] ?? '';
                // $l3Cache = $l3CacheMatch[1];
                

                // echo "Processeur : $name\n";
                // echo "Cœurs physiques : $cores\n";
                // echo "Processeurs logiques : $logicalProcessors\n";
                // echo "Fréquence maximale : $clockSpeed MHz\n";

                // echo "La mémoire cache :  $l2Cache . ko\n";
          
                $merge1 = array_merge(
                    $merge,
                    [
                            'processor' => $name,
                            'hearthPhysical' => $cores,
                            'logiqProcessor' => $memoryUsagePercentage,
                            'frequenceMax' => $clockSpeed,
                            'memoryCache' => $l2Cache
                    ]
                );
            }

            exec('powershell -Command "Get-WmiObject Win32_OperatingSystem | Select-Object FreePhysicalMemory, TotalVisibleMemorySize"', $output, $return_var);



            $all = explode(' ', $output[3]);
            $i= 0;

            $memoireLibre = '';
            
            $memoireTotal = '';

            foreach ($all as $v) {
                if ($v != null) {
                    ($i == 0) ? $memoireLibre = $v : $memoireTotal = $v;
                    $i++;
                }
            }

            // Convertir en Mo
            $memoryInMB = round((float)$memoireLibre / 1024, 2);
            // echo "Mémoire libre : " . $memoireLibre . " Mo";

            // Convertir en Go
            $memoryInGB = round((float)$memoryInMB / 1024, 2);
            // echo "Mémoire libre : " . $memoryInGB . " Go";

            $memoryTotalMB = round((float)$memoireTotal / 1024, 2);
            // echo "Mémoire total : " . $memoryTotalMB . " Mo";

            // Convertir en Go
            $memoryToalInGB = round($memoryTotalMB / 1024, 2);
            // echo "Mémoire total  : " . $memoryToalInGB . " Go";


            $usedMemoryGo = $memoryToalInGB - $memoryInGB;


            // $output = shell_exec('powershell -ExecutionPolicy Bypass -File "E:\\Oxalys\\Oxalys_Broker\\versions\\1200aa\\HAPlus\\oxaproc\src\Modules\\Systeme\\cpu_usage.ps1"');
            // echo "Utilisation du CPU : " . $output . "%";

            // FONCTIONNE !!!
            //  $output = shell_exec('powershell.exe -Command "Get-WmiObject Win32_Processor | Format-List *"');
            // // Parse the output into an array
            // $lines = explode("\n", $output);
            // A GARDER
            // PercentProcessorTime


            // Exécute la commande PowerShell pour obtenir le pourcentage d'utilisation du processeur
            $output = shell_exec('powershell.exe -Command "Get-WmiObject Win32_Processor | Format-List *"');

            // Parse the output to extract the relevant data
            preg_match('/\s+CounterSample\s+\((\d+\.\d+)\)/', (string)$output, $matches);


            $cpuInfo = shell_exec('wmic cpu get NumberOfCores,NumberOfLogicalProcessors');

            // Extraire les informations pertinentes
            preg_match('/(\d+)\s+(\d+)/', (string)$cpuInfo, $matches);
            $cores = $matches[1] ?? '';  // Cœurs physiques
            $threads = $matches[2] ?? ''; // Cœurs logiques (threads)


            if ($cores > 0) {
                $threadsPerCore = (float)$threads / (float)$cores;
            } else {
                $threadsPerCore = 0;
            }
            $merge2 = array_merge($merge1, [
                'threads_per_core' => $cores, // Chaque coeur peut exécuter xxx thread
                'total_threads' => $threadsPerCore,
                'memoireLibre' => $memoryInGB,
                'memoireTotal' => $memoryToalInGB,
                'memoireUtilise' => $usedMemoryGo
            ]);
        } else {
            // Linux CPU
            $load = sys_getloadavg();
            $cpuload = $load[0]??[];
            $cpu_count = shell_exec('nproc');
            // Linux MEM
            $free = shell_exec('free');
            $free = (string)trim((string)$free);
            $free_arr = explode("\n", $free);
            $mem = explode(" ", $free_arr[1]);
            $mem = array_filter($mem, function ($value) {
                /** @phpstan-ignore-next-line */
                return ($value !== null && $value !== false && $value !== '');
            }); // removes nulls from array
            $mem = array_merge($mem); // puts arrays back to [0],[1],[2] after
            $memtotal = round((float)$mem[1] / 1000000, 2);
            $memused = round((float)$mem[2] / 1000000, 2);
            $memfree = round((float)$mem[3] / 1000000, 2);
            $memshared = round((float)$mem[4] / 1000000, 2);
            $memcached = round((float)$mem[5] / 1000000, 2);
            $memavailable = round((float)$mem[6] / 1000000, 2);
            // Linux Connections
            $connections = `netstat -ntu | grep -E ':80 |443 ' | grep ESTABLISHED | grep -v LISTEN | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | grep -v 127.0.0.1 | wc -l`;
            $totalconnections = `netstat -ntu | grep -E ':80 |443 ' | grep -v LISTEN | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | grep -v 127.0.0.1 | wc -l`;
            
            $memusage = round(($memused/$memtotal)*100);
            // Créer un arbre pour le retour de la fonction avec la même forme de tableau du cas windows.
            return $returnCollection['serverCollection'] =
            [
                ''
            ];
        }
 

        $diskfree  = round(disk_free_space(".") / 1000000000);
        $disktotal = round(disk_total_space(".") / 1000000000);
        $diskused  = round($disktotal - $diskfree);
        $diskusage = round($diskused/$disktotal*100);
        

        $merge3 = array_merge($merge2, [
            'diskLibre'    => $diskfree,
            'diskTotal'    => $disktotal,
            'diskUtiliser' => $diskusage
        ]);
        
        // if ($memusage > 85 || $cpuload > 85 || $diskusage > 85) {
            //     $trafficlight = 'red';
            // } elseif ($memusage > 50 || $cpuload > 50 || $diskusage > 50) {
                //     $trafficlight = 'orange';
                // } else {
                    //     $trafficlight = '#2F2';
                    // }
                    
        $end_time = microtime(true);
        $time_taken = $end_time - $start_time;
        $total_time = round($time_taken, 4);

  
        return $merge3;
    }

    /**
     * @return Response
     */
    public function activeTracingRequeteAction()
    {
        if (Roles::GetALL() || $_SESSION["Session_Login"] == 'OXAUSER') {
            if (isset($_SESSION['activeTracingRequete'])) {
                unset($_SESSION['activeTracingRequete']);
            } else {
                $_SESSION['activeTracingRequete'] = true;
            }
        }

        return new Response(200, [], (string)json_encode([
            'activeTracingRequete' => $_SESSION['activeTracingRequete']??false
        ]));
    }

    /**
     * @return mixed
     */
    private function getLogDirectory(): mixed
    {
        return (new ParseBase1())->getRep();
    }

    /**
     * Summary of getErrorLogPath
     * @throws \Exception
     * @return string
     */
    private function getErrorLogPath(): string
    {
        $errorLogPath = ini_get('error_log');
        if (!$errorLogPath) {
            throw new \Exception("Le fichier de log n'existe pas ou le chemin est invalide.");
        }
        return $errorLogPath;
    }

    /**
     * Summary of getPhpIniDirectory
     * @return mixed|string
     */
    private function getPhpIniDirectory(): mixed
    {
        $pathInfo = pathinfo($this->getErrorLogPath());
        if (!isset($pathInfo['dirname'])) {
            throw new \Exception("Impossible de déterminer le dossier du fichier de log.");
        }
        return $pathInfo['dirname'];
    }
}
