<?php

namespace Sibs\Sibs\Utils;

use Sibs\Sibs\Model\SibsConstants;

class SibsLog
{
    /**
     * @var ?\Zend_Log
     */
    private static $_logger = null;

    /**
     * @var ?string
     */
    private static $logId = null;

    /**
     * @var ?string
     */
    private static $filename = null;

    /**
     * @var string
     */
    private static $ext = 'log';

    /**
     * @var int
     */
    private const LOG_UNCAPSULATE_DEPTH = 2;

    /**
     * @var int
     */
    private const LOG_CAPSULATE_DEPTH = 3;

    /**
     * @var string
     */
    public const LEVEL_DEBUG = \Zend_Log::DEBUG;         // 7

    /**
     * @var string
     */
    public const LEVEL_INFO = \Zend_Log::INFO;           // 6

    /**
     * @var string
     */
    public const LEVEL_NOTICE = \Zend_Log::NOTICE;       // 5

    /**
     * @var string
     */
    public const LEVEL_WARNING = \Zend_Log::WARN;        // 4

    /**
     * @var string
     */
    public const LEVEL_ERROR = \Zend_Log::ERR;           // 3

    /**
     * @var string
     */
    public const LEVEL_CRITICAL = \Zend_Log::CRIT;       // 2

    /**
     * @var string
     */
    public const LEVEL_ALERT = \Zend_Log::ALERT;         // 1

    /**
     * @var string
     */
    public const LEVEL_EMERGENCY = \Zend_Log::EMERG;     // 0

    /**
     * Constructor
     */
    private function __construct() {}

    /**
     * Clone
     */
    private function __clone() {}

    /**
     * Wakeup
     */
    public function __wakeup() {}

    /**
     * Get Logger Instance
     * @return \Zend_Log
     */
    public static function logger()
    {
        if (is_null(self::$_logger)) {
            self::$logId   = uniqid();
            $fileName      = self::getFileNameExt();
            $writer        = new \Zend_Log_Writer_Stream(BP . '/var/log/' . $fileName);
            self::$_logger = new \Zend_Log();
            self::$_logger->addWriter($writer);
        }

        return self::$_logger;
    }

    /**
     * Get File Name and Extension
     *
     * @param string
     * @return string
     */
    public static function getFileNameExt()
    {
        return self::getFileName() . "." . self::getFileExtension();
    }

    /**
     * Get File Name
     *
     * @param string
     * @return string
     */
    public static function setNameFile($filename)
    {
        self::$filename = $filename;
        return self::$filename;
    }

    /**
     * Get File Name
     *
     * @return string
     */
    public static function getFileName()
    {
        if (is_null(self::$filename)) {
            self::setNameFile(SibsConstants::SIBS_LOG);
        }

        return self::$filename . '_' . date('Y-m-d');
    }

    /**
     * Get File Extension
     *
     * @return string
     */
    public static function getFileExtension()
    {
        return self::$ext;
    }

    /**
     * Pretify Message to be Logged
     *
     * @param string $message
     * @return string
     */
    public static function prettify($message)
    {
        $objectMessage = SibsObjectify::json_mapper($message);
        return json_encode($objectMessage, JSON_PRETTY_PRINT);
    }

    /**
     * Get Message to Log Formated
     *
     * @param string $message
     * @param int $traceDepth
     * @return string
     */
    protected static function formatMessageToLog($message, $traceDepth = self::LOG_UNCAPSULATE_DEPTH)
    {
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $traceDepth + 1);
        // Get the call function where log is
        $traceLevel = $trace[$traceDepth];
        // Get the line where log is called
        $traceLineLevel = $trace[($traceDepth > 0) ? ($traceDepth - 1) : $traceDepth];

        return '[' . self::$logId . '] ' .
            (isset($traceLevel['class']) ? ($traceLevel['class'] . '::') : '') .
            (isset($traceLevel['function']) ? $traceLevel['function'] . '()' : '') .
            (isset($traceLineLevel['line']) ? (' (line: ' . $traceLineLevel['line'] . ')') : '') .
            ' ' . $message;
    }

    /**
     * Make custom log
     *
     * @param mixed $message
     * @param int $priority
     * @param array $extra
     * @param int $traceDepth
     * @return void
     */
    public static function log($message, $priority = self::LEVEL_DEBUG, $extra = [], $traceDepth = self::LOG_UNCAPSULATE_DEPTH)
    {
        $logger = self::logger();

        $prettyMessage = SibsObjectify::isArrayOrJson($message) ? self::prettify($message) : $message;
        $formatedMessage = self::formatMessageToLog($prettyMessage, $traceDepth);

        $logger->log($formatedMessage, $priority, $extra);
    }

    /**
     * Make debug log (1)
     *
     * @param mixed $message
     * @param array $extra
     * @return void
     */
    public static function debug($message, $extra = [])
    {
        self::log($message, self::LEVEL_DEBUG, $extra, self::LOG_CAPSULATE_DEPTH);
    }

    /**
     * Make info log (2)
     *
     * @param mixed $message
     * @param array $extra
     * @return void
     */
    public static function info($message, $extra = [])
    {
        self::log($message, self::LEVEL_INFO, $extra, self::LOG_CAPSULATE_DEPTH);
    }

    /**
     * Make notice log (3)
     *
     * @param mixed $message
     * @param array $extra
     * @return void
     */
    public static function notice($message, $extra = [])
    {
        self::log($message, self::LEVEL_NOTICE, $extra, self::LOG_CAPSULATE_DEPTH);
    }

    /**
     * Make warn log (4)
     *
     * @param mixed $message
     * @param array $extra
     * @return void
     */
    public static function warn($message, $extra = [])
    {
        self::log($message, self::LEVEL_WARNING, $extra, self::LOG_CAPSULATE_DEPTH);
    }

    /**
     * Make err log (5)
     *
     * @param mixed $message
     * @param array $extra
     * @return void
     */
    public static function err($message, $extra = [])
    {
        self::log($message, self::LEVEL_ERROR, $extra, self::LOG_CAPSULATE_DEPTH);
    }

    /**
     * Make crit log (6)
     *
     * @param mixed $message
     * @param array $extra
     * @return void
     */
    public static function crit($message, $extra = [])
    {
        self::log($message, self::LEVEL_CRITICAL, $extra, self::LOG_CAPSULATE_DEPTH);
    }

    /**
     * Make alert log (7)
     *
     * @param mixed $message
     * @param array $extra
     * @return void
     */
    public static function alert($message, $extra = [])
    {
        self::log($message, self::LEVEL_ALERT, $extra, self::LOG_CAPSULATE_DEPTH);
    }

    /**
     * Make emerg log (8)
     *
     * @param mixed $message
     * @param array $extra
     * @return void
     */
    public static function emerg($message, $extra = [])
    {
        self::log($message, self::LEVEL_EMERGENCY, $extra, self::LOG_CAPSULATE_DEPTH);
    }
}
