<?php

namespace auctionforge\inc;

use DateTime;

class Debug
{
    const LOGS_DIR = 'auctionforge-logs';
    const MAX_LOG_SIZE = 7 * 1024 * 1024;
    const LOG_RETENTION_DAYS = 90;

    public static function logData($data, $action = "log", $info = array())
    {
        if (!empty($info)) {
            $data = is_array($data) ? array_merge($data, $info) : array_merge([$data], $info);
        }
        self::putLogData('logs', $data, $action);
    }

    public static function devDump(...$data)
    {
        if (!empty($info)) {
            $data = is_array($data) ? array_merge($data, $info) : array_merge([$data], $info);
        }
        self::putLogData('dev', $data, "dev");
    }

    public static function webhookLog($data, $action = "webhook")
    {
        self::putLogData('webhook-logs', $data, $action);
    }

    private static function putLogData($logFile, $data, $action)
    {
        $logPath = self::getLogFilePath($logFile);
        self::ensureLogDirectoryExists();
        self::rotateLogIfNeeded($logPath);

        $logEntry = date("Y-m-d H:i:s")." : $action: ".var_export($data, true)."\r\n";
        file_put_contents($logPath, $logEntry, FILE_APPEND | LOCK_EX);
    }

    /*private static function putLogData($logFile, $data, $action) {
        $logPath = self::getLogFilePath($logFile);
        self::ensureLogDirectoryExists();
        self::rotateLogIfNeeded($logPath);

        $formattedData = self::formatLogData($data);

        $logEntry = sprintf(
            "[%s] %s\n%s\n%s\n\n",
            date("Y-m-d H:i:s"),
            $action,
            str_repeat('=', 50),
            $formattedData
        );

        file_put_contents($logPath, $logEntry, FILE_APPEND | LOCK_EX);
    }*/

    private static function formatLogData($data)
    {
        if (is_object($data)) {
            return method_exists($data, '__toString')
                ? (string) $data
                : json_encode($data, JSON_PRETTY_PRINT);
        }

        if (is_string($data) && self::isJson($data)) {
            return json_encode(json_decode($data), JSON_PRETTY_PRINT);
        }

        if (is_array($data)) {
            array_walk_recursive($data, function (&$item) {
                if (is_string($item) && mb_strlen($item) > 1000) {
                    $item = substr($item, 0, 1000).'... [TRUNCATED]';
                }
            });
        }

        return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    }

    private static function isJson($string)
    {
        json_decode($string);
        return json_last_error() === JSON_ERROR_NONE;
    }

    public static function errorLog($message, $type = "Notice", $action = "logs")
    {
        $logPath = self::getLogFilePath($action);
        self::ensureLogDirectoryExists();
        self::rotateLogIfNeeded($logPath);

        $logEntry = date("[Y-m-d H:i:s]")." PHP {$type}: $message\r\n";
        error_log($logEntry, 3, $logPath);
    }

    private static function ensureLogDirectoryExists()
    {
        $logDir = self::getLogsDirectory();
        if (!file_exists($logDir)) {
            wp_mkdir_p($logDir);

            self::createDirectoryProtection($logDir);
        }
    }

    private static function createDirectoryProtection($dir)
    {
        if (!file_exists($dir.'/index.html')) {
            file_put_contents($dir.'/index.html', '');
        }

        if (!file_exists($dir.'/.htaccess')) {
            file_put_contents($dir.'/.htaccess', "Options -Indexes\nDeny from all");
            //file_put_contents($dir . '/.user.ini', 'open_basedir = none');
        }

        if (!file_exists($dir.'/index.php')) {
            file_put_contents($dir.'/index.php', '<?php // Silence is golden');
        }
    }

    private static function rotateLogIfNeeded($logPath)
    {
        if (file_exists($logPath) && filesize($logPath) > self::MAX_LOG_SIZE) {
            $backupPath = $logPath.'.'.date('Y-m-d');
            rename($logPath, $backupPath);
        }

        self::cleanupOldLogs($logPath);
    }

    private static function cleanupOldLogs($currentLogPath)
    {
        $logDir = dirname($currentLogPath);
        $retentionTime = strtotime('-'.apply_filters('auctionforge_log_retention_days', self::LOG_RETENTION_DAYS).' days');

        foreach (glob($logDir.'/*.log.*') as $file) {
            if ($file === $currentLogPath) {
                continue;
            }

            $fileNameParts = explode('.', basename($file));
            $fileDate = end($fileNameParts);

            if (self::isValidDate($fileDate)) {
                $fileTimestamp = strtotime($fileDate);

                if ($fileTimestamp < $retentionTime) {
                    @unlink($file);
                }
            }
        }
    }

    private static function isValidDate($dateString)
    {
        $d = DateTime::createFromFormat('Y-m-d', $dateString);
        return $d && $d->format('Y-m-d') === $dateString;
    }

    private static function getLogsDirectory()
    {
        return WP_CONTENT_DIR.'/'.self::LOGS_DIR;
    }

    private static function getLogFilePath($logFile)
    {
        return self::getLogsDirectory().'/'.$logFile.'.log';
    }

    private static function getDumpFilePath($dumpFile)
    {
        return ABSPATH.'dump/'.$dumpFile.'.txt';
    }

    public static function dumpToFile(...$args)
    {
        if (is_array($args)) {
            $data = array_merge($args, array(__FILE__, __LINE__));
        }
        file_put_contents(ABSPATH.'dump/var_dump-'.date("Y-m-d-H-i-s").":".rand(1000, 9999).'.txt',
            var_export(
                $data
                , true));
    }

    public static function errorDump($message, $type = "Notice", $action = "log")
    {
        if (is_dir(ABSPATH.'dump/')) {
            error_log(date("[Y-m-d H:i:s]")." PHP {$type}: ".$message." "."\r\n", 3, self::getDumpFilePath($action));
        }
    }

    public static function memoryLog()
    {
        echo "Usege:".self::getNiceFileSize(memory_get_usage())." Peak: ".self::getNiceFileSize(memory_get_peak_usage())."\r\n";
    }

    public static function getNiceFileSize($bytes)
    {
        $unit = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB');
        if ($bytes == 0) {
            return '0 '.$unit[0];
        } else {
            return @round($bytes / pow(1024, ($i = floor(log($bytes, 1024)))), 2).' '.(isset($unit[$i]) ? $unit[$i] : 'B');
        }
    }
}