<?php

class debug
{
    private static $logs = [];
    private static $startTime;
    private static $closeTime;

    private static function typeFile(string $_string){
        switch ($_string) {
            case 'maintenance':
                return ".lock-maintenance";
                break;
            case 'debug':
                return ".active-debug";
                break;
            default:
                return ".active-debug-".$_string;
                break;
        }
    }
    
    public static function addFile(string $_string = NULL)
    {
        if($_string != NULL){
            $myfile = fopen(DOCUMENT_ROOT . self::typeFile($_string), "w");
            fclose($myfile);
        }
    }

    public static function removeFile(string $_string = NULL)
    {
        if($_string != NULL){
            unlink(DOCUMENT_ROOT . self::typeFile($_string));
        }
    }

    public static function isFile(string $_string = NULL)
    {
        return file_exists(DOCUMENT_ROOT . self::typeFile($_string)) ? TRUE : FALSE;
    }
    
    public static function includeDebug()
    {
        if (debug::isFile("debug")) {
            echo '<link rel="stylesheet" href="' . cache::getFileWithTime("css/debug.css") . '">';
        }
    }

    public static function dump($var, $label = 'Dump', $echo = true)
    {
        // Start output buffering
        ob_start();

        echo "<pre class='debug-dump'>";
        echo "<strong>" . $label . ":</strong> ";

        // Convert array or object to string
        if (is_array($var)) {
            print_r($var);
        } elseif (is_object($var)) {
            echo self::objectToString($var);
        } else {
            var_dump($var);
        }

        echo "</pre>";

        // Get the contents of the buffer
        $output = ob_get_clean();

        // If echo is true, print the output
        if ($echo) {
            echo $output;
        } else {
            return $output;
        }
    }

    public static function objectToString($object, $_tab = NULL) {
        ob_start();

        $tab = "&nbsp;&nbsp;&nbsp;&nbsp;" . $_tab;
        
        echo "<span class='debug-console-capsule'>Object (" . get_class($object) . ")\n</span>";
        echo $_tab . "<span class='debug-console-capsule'>{\n</span>";
        
        foreach (get_object_vars($object) as $property => $value) {
            echo $tab . "<span class='debug-console-capsule'>[<span class='debug-console-key'>$property</span>] => </span>";
            if (is_array($value)) {
                echo self::arrayToString($value, $tab);
            } elseif (is_object($value)) {
                echo self::objectToString($value, $tab);
            } else {
                echo "<span class='debug-console-value'>" . var_export($value, true) . "</span>\n";
            }
        }
        
        echo $_tab . "<span class='debug-console-capsule'>}\n</span>";
        
        return ob_get_clean();
    }



    public static function arrayToString($array, $_tab = NULL)
    {
        ob_start();

        $tab = "&nbsp;&nbsp;&nbsp;&nbsp;".$_tab;
        
        echo "<span class='debug-console-capsule'>Array\n</span>";
        echo $_tab . "<span class='debug-console-capsule'>(\n</span>";
        
        foreach ($array as $key => $value) {
            echo $tab . "<span class='debug-console-capsule'>[<span class='debug-console-key'>$key</span>] => </span>";
            if (is_array($value)) {
                echo self::arrayToString($value, $tab);
            } elseif (is_object($value)) {
                echo self::objectToString($value, $tab);
            } else {
                echo "<span class='debug-console-value'>" . var_export($value, true) . "</span>\n";
            }
        }
        
        echo $_tab . "<span class='debug-console-capsule'>)\n</span>";
        
        return ob_get_clean();
    }

    private static function variableToString($var, $label)
    {
        ob_start();
        echo "$label: ";
        if (is_array($var) || is_object($var)) {
            print_r($var);
        } else {
            var_dump($var);
        }
        return ob_get_clean();
    }

    public static function getTraces(){
        $return = "Trace : ";
        
        // Obtenir la trace d'exécution
        $backtrace = debug_backtrace();
        $nb = count($backtrace)-1;

        for ($i=$nb; $i > 0; $i--) { 
            $return .= ($i != 0) ? "[".$backtrace[$i]["function"]."] " : NULL;
            $return .= str_replace(DOCUMENT_ROOT, '', $backtrace[$i]["file"]).":".$backtrace[$i]["line"];
            $return .= ($i != 1) ? " >> " : NULL;
        }

        return $return;
    }

    public static function print_r(array $_array, int $_exit = NULL)
    {
        echo "<div>".debug::getTraces() . "</div>";
        echo "<pre>";
        print_r($_array);
        echo "</pre>";
        ($_exit != NULL) ? exit() : NULL;
    }

    public static function isHtml(string $_string) : bool 
    {
        $stripped_string = strip_tags($_string);
        return $_string !== $stripped_string;
    }

    public static function generateHtmlContent($htmlContent)
    {
        $id = md5(microtime());
        return <<<HTML
                    <!DOCTYPE html>
                    <html>
                    <head>
                        <title>Exécution de HTML</title>
                        <style>
                            .isolated-iframe {
                                width: 100%;
                                height: 300px;
                                border: none;
                            }
                        </style>
                    </head>
                    <body>
                        <iframe id="isolatedIframe-$id" class="isolated-iframe"></iframe>
                        <script>
                            var iframe = document.getElementById('isolatedIframe-$id');
                            var doc = iframe.document || iframe.contentDocument || iframe.contentWindow.document;
                            doc.open();
                            doc.write(`{$htmlContent}`);
                            doc.close();
                        </script>
                    </body>
                    </html>
                    HTML;
    }


    public static function log($_message, $_mark = NULL)
    {        
        $mark = "<div class='debug-head-console'>";
        $mark .= ($_mark != NULL) ? "<div style='font-weight: bold;'>". $_mark . "</div>" : NULL;
        $mark .= self::getTraces();
        $mark .= "</div>";
        if($_message != NULL) {
            if(is_array($_message)){
                self::$logs[] = ["data" => $mark ."<div class='debug-console'>" . self::arrayToString($_message) . "</div>", "nl2br" => TRUE];
            } elseif(is_object($_message)){
                self::$logs[] = ["data" => $mark ."<div class='debug-console'>" . self::objectToString($_message) . "</div>", "nl2br" => TRUE];
            } elseif(self::isHtml($_message)){
                self::$logs[] = ["data" => $mark ."<div class='debug-console'>" . self::generateHtmlContent($_message) . "</div>", "nl2br" => FALSE];
            } elseif($mark != NULL){
                self::$logs[] = ["data" => $mark ."<div class='debug-console' style='color:blue;'>" . $_message . "</div>", "nl2br" => TRUE];
            } else {
                self::$logs[] = ["data" => $_message, "nl2br" => TRUE];
            }
        }
    }

    public static function logSession($_message, $_mark = NULL)
    {        
        $mark = "<div class='debug-head-console'>";
        $mark .= ($_mark != NULL) ? "<div style='font-weight: bold;'>". $_mark . "</div>" : NULL;
        $mark .= self::getTraces();
        $mark .= "</div>";
        if($_message != NULL) {
            if(is_array($_message)){
                self::setSession(["data" => $mark ."<div class='debug-console'>" . self::arrayToString($_message) . "</div>", "nl2br" => TRUE]);
            } elseif(is_object($_message)){
                self::setSession(["data" => $mark ."<div class='debug-console'>" . self::objectToString($_message) . "</div>", "nl2br" => TRUE]);
            } elseif(self::isHtml($_message)){
                self::setSession(["data" => $mark ."<div class='debug-console'>" . self::generateHtmlContent($_message) . "</div>", "nl2br" => false]);
            } elseif($mark != NULL){
                self::setSession(["data" => $mark ."<div class='debug-console' style='color:blue;'>" . $_message . "</div>", "nl2br" => TRUE]);
            } else {
                self::setSession(["data" => $_message, "nl2br" => TRUE]);
            }
        }
    }

    public static function renderLogs()
    {
            echo "<div id='debugger-logs'>";

            echo "<div class='debug-renderLogs-header'>";
            echo "PHP <span style=\"font-weight: bold;\">". phpversion() . "</span> | MYSQL <span style=\"font-weight: bold;\">" . db::version() . "</span> | " . number_format(self::$closeTime, 4) . " secondes ";
            echo "</div>";
            echo "<div class=\"form-check form-switch\" style=\"margin-top: -30px;\">
                <div>
                    <input class=\"form-check-input\" type=\"checkbox\" id=\"checkIsSubmit\" " . core::checkboxSelecter(self::isFile("submit"), 0) . " >
                    <label class=\"form-check-label\" for=\"checkIsSubmit\">Intercepter les <span style=\"font-weight: bold;\">Submit</span></label>
                </div>
                <div>
                    <input class=\"form-check-input\" type=\"checkbox\" id=\"checkIsSql\" " . core::checkboxSelecter(self::isFile("sql"), 0) . " >
                    <label class=\"form-check-label\" for=\"checkIsSql\">Intercepter les <span style=\"font-weight: bold;\">requêtes SQL</span></label>
                </div>
                <div>
                    <input class=\"form-check-input\" type=\"checkbox\" id=\"checkIsEmail\" " . core::checkboxSelecter(self::isFile("email"), 0) . " >
                    <label class=\"form-check-label\" for=\"checkIsEmail\">Intercepter les <span style=\"font-weight: bold;\">Email</span></label>
                </div>
                <div>
                    <input class=\"form-check-input\" type=\"checkbox\" id=\"checkSendIsEmail\" " . core::checkboxSelecter(self::isFile("send-email"), 0) . " >
                    <label class=\"form-check-label\" for=\"checkSendIsEmail\">Afficher le mode debug lors de l'<span style=\"font-weight: bold;\">envoie d'email</span></label>
                </div>
            </div>";

            foreach (self::$logs as $log) {
                if($log != NULL){
                    echo "<div class='debug-renderLogs-print'>";
                        echo $log["nl2br"] == TRUE ? nl2br($log["data"]) : $log["data"];
                    echo "</div>";
                }
            }

            if(self::ifSession()){
                foreach (self::getSession() as $logSession) {
                    echo "<div class='debug-renderLogs-print'>";
                        echo $logSession["nl2br"] == TRUE ? nl2br($logSession["data"]) : $logSession["data"];
                    echo "</div>";
                }
            }

            echo "</div>";
            get::javascript("debug");
    }

    public static function init()
    {
        // Register shutdown function to render logs at the end of the script execution
        register_shutdown_function(function () {
            self::renderLogs();
        });
    }

    public static function startTimer()
    {
        self::$startTime = microtime(true);
    }

    public static function endTimer()
    {
        self::$closeTime = microtime(true) - self::$startTime;
    }

    public static function getBadge(string $_link,string $_label){
        return '<a href="'. $_link .'" target="_blank" class="badge debug-badge">'. $_label .'</a>';
    }

    public static function printEnvironnement(){
        echo (ENVIRONNEMENT != "PROD") ? " [" . ENVIRONNEMENT . "]" : NULL;
    }

    private static function buildBadge(array $_data){
        $color = empty($_data["color"]) ? "black" : $_data["color"];
        $backgroundColor = empty($_data["background-color"]) ? "orangered" : $_data["background-color"];
        $class = empty($_data["class"]) ? NULL : $_data["class"];
        $link = empty($_data["link"]) ? "#" : $_data["link"];
        $txt = empty($_data["txt"]) ? NULL : $_data["txt"];
        $icon = empty($_data["icon"]) ? NULL : "<i class=\"" . $_data["icon"] . "\"></i> ";
        return "<a href=\"" . $link . "\"><span class=\"badge " . $class . "\" style=\"background-color:" . $backgroundColor . "; color:" . $color . "; padding: 3px 5px 2px 5px; margin-right: 5px;\">" . $icon . $txt . "</span></a>";
    }

    public static function getBadges(){
        $return = "";
        if(debug::isFile("maintenance")){
            $return .= self::buildBadge([
                "icon" => "bi bi-exclamation-diamond-fill",
                "link" => "/parametres.html#parametres-debug", 
                "background-color" => "red",  
                "color" => "white", 
                "txt" => "MODE MAINTENANCE"
            ]);
        }
        if(debug::isFile("debug")){
            $return .= self::buildBadge([
                "icon" => "bi bi-bug-fill",
                "class" => "toggle-logs",
                "link" => "#", 
                "background-color" => "orangered",  
                "color" => "white", 
                "txt" => "MODE DEBUG"
            ]);
        } 
        if(self::isFile("sql")){
            $return .= self::buildBadge([
                "icon" => "bi bi-database-fill",
                "class" => "toggle-logs",
                "link" => "#", 
                "background-color" => "orange",  
                "color" => "black", 
                "txt" => "DEBUG SQL"
            ]);
        }
        if(self::isFile("email")){
            $return .= self::buildBadge([
                "icon" => "bi bi-envelope-fill",
                "class" => "toggle-logs",
                "link" => "#", 
                "background-color" => "orange",  
                "color" => "black", 
                "txt" => "DEBUG EMAIL"
            ]);
        }
        if(self::isFile("send-email")){
            $return .= self::buildBadge([
                "icon" => "bi bi-envelope-fill",
                "class" => "toggle-logs",
                "link" => "#", 
                "background-color" => "orange",  
                "color" => "black", 
                "txt" => "DEBUG SEND EMAIL"
            ]);
        }
        if(self::isFile("submit")){
            $return .= self::buildBadge([
                "icon" => "bi bi-send-fill",
                "class" => "toggle-logs",
                "link" => "#", 
                "background-color" => "orange",  
                "color" => "black", 
                "txt" => "DEBUG SUBMIT"
            ]);
        } 
        return $return;
    }

    public static function setSession($_data){
        $_SESSION["DEBUG"][] = $_data;
    }

    public static function getSession(){
        $return = $_SESSION["DEBUG"];
        self::resetSession();
        return $return;
    }

    public static function ifSession(){
        return empty($_SESSION["DEBUG"]) ? FALSE : TRUE;
    }

    public static function resetSession(){
        unset($_SESSION["DEBUG"]);
    }
}
