<?php

namespace xmvc;

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Processor\WebProcessor;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\RedisHandler;
use Monolog\Formatter\LineFormatter;
use Monolog\Level;
use Redis;

/**
 *  日志类
 *  - composer require monolog/monolog
 */
class Log
{
    private static $type = '';
    /**
     * 配置
     *
     * @param string $type 类型,如 system, database, 一个类型一个目录
     */
    public static function channel(string $type = 'error'): Logger
    {
        self::$type = trim($type);
        return self::getLoger();
    }

    /**
     * 获取 Monolog\Logger
     *
     * @param string $type 类型,如 system, database, 一个类型一个目录
     */
    public static function getLoger(): Logger
    {
        $type = self::$type ?: 'error';
        $guid = __CLASS__ . '_' . $type;
        if (isset(MVC::$objectList[$guid])) {
            return MVC::$objectList[$guid];
        } else {
            $cfg = cfg('log>' . $type);
            if (is_null($cfg)) {
                error('未配置的日志通道名称', null, [[__FILE__, __LINE__], DIR_MVC . '/Log.php']);
            }
            /** @var Logger $log */
            $log = MVC::createObject(Logger::class, [$type]);
            if (!is_dir(DIR_LOG)) {
                mkdir(DIR_LOG, 0777);
            }
            $logPath = DIR_LOG . '/' . $type;
            if (!is_dir($logPath)) {
                mkdir($logPath, 777);
            }
            $logFile = $logPath . "/" . $type . ".log";

            // 创建一个日志通道
            $log = new Logger($type);
            if ($cfg['dnsRedis'] != '') {
                // 取 Redis 配置
                $cfgRedis = cfg($cfg['dnsRedis']);

                // 创建一个 Redis 连接
                $redis = new Redis();
                $redis->connect($cfgRedis['host'], $cfgRedis['port']);
                if (isset($cfgRedis['password']) && $cfgRedis['password'] != '') {
                    $redis->auth($cfgRedis['password']);
                }

                // 创建一个 RedisHandler 将日志写入 Redis
                $redisHandler = new RedisHandler($redis, "monolog:{$type}", $cfg['level']);
                $redisHandler->setFormatter(new LineFormatter(null, null, true, true));

                // 将 RedisHandler 添加到日志通道
                $log->pushHandler($redisHandler);
            } else {
                //$log->pushHandler(new StreamHandler($logFile));
                // 创建一个每天旋转的日志处理器，保留7天的日志文件 例 error-2024-06-28.log
                $log->pushHandler(new RotatingFileHandler($logFile, $cfg['maxFiles'], $cfg['level'], true, 0775, true, 'Y-m-d', '{filename}-{date}'));
            }

            if ($cfg['webProcessor']) {
                $log->pushProcessor(new WebProcessor());
            }
            MVC::$objectList[$guid] = $log;
            return $log;
        }
    }

    /**
     * 格式化日志文本
     *
     * @param string $message
     * @return string
     */
    public static function formatMessage(string $message): string
    {
        $message = strtr($message, ['{' => '&#123', '}' => '&#125', '[' => '&#91', ']' => '&#93', "\r\n" => '<br>', "\n" => '<br>']);
        return $message;
    }

    /**
     * 调试信息 写入日志
     *
     * @param string $message 日志信息
     * @param array $contexts 上下文信息
     * @see xmvc\test\LogTest::sample()
     */
    public static function debug(string $message, array $contexts = [])
    {
        $message = self::formatMessage($message);
        self::getLoger()->debug($message, $contexts);
    }

    /**
     * 普通信息 写入日志
     *
     * @param string $message 日志信息
     * @param array $contexts 上下文信息
     * @see xmvc\test\LogTest::sample()
     */
    public static function info(string $message, array $contexts = [])
    {
        $message = self::formatMessage($message);
        self::getLoger()->info($message, $contexts);
    }

    /**
     * 警告信息 写入日志
     *
     * @param string $message 日志信息
     * @param array $contexts 上下文信息
     * @see xmvc\test\LogTest::sample()
     */
    public static function warning(string $message, array $contexts = [])
    {
        $message = self::formatMessage($message);
        self::getLoger()->warning($message, $contexts);
    }

    /**
     * 错误信息 写入日志
     *
     * @param string $message 日志信息
     * @param array $contexts 上下文信息
     * @see xmvc\test\LogTest::sample()
     */
    public static function error(string $message, array $contexts = [])
    {
        $message = self::formatMessage($message);
        self::getLoger()->error($message, $contexts);
    }

    /**
     * 关键信息 写入日志
     *
     * @param string $message 日志信息
     * @param array $contexts 上下文信息
     * @see xmvc\test\LogTest::sample()
     */
    public static function critical(string $message, array $contexts = [])
    {
        $message = self::formatMessage($message);
        self::getLoger()->critical($message, $contexts);
    }

    /**
     * 突发事件信息 写入日志
     *
     * @param string $message 日志信息
     * @param array $contexts 上下文信息
     * @see xmvc\test\LogTest::sample()
     */
    public static function emergency(string $message, array $contexts = [])
    {
        $message = self::formatMessage($message);
        self::getLoger()->emergency($message, $contexts);
    }
}
