<?php
/**
 * Created by PhpStorm.
 * User: hjl
 * Date: 2023/6/21
 * Time: 07:25
 */

namespace support\log;

use Monolog\Handler\StreamHandler;
use Monolog\Logger;

class MonologExtendHandler extends StreamHandler
{
    protected int $maxFileSize;
    protected bool $mustRotate;
    protected string $runtimeLogPath;
    protected string|null $channelDirName;

    /**
     * @param string $channelDirName 日志通道路径
     * @param int $maxFileSize The maximal file size (default 10MB)
     * @param int $level The minimum logging level at which this handler will be triggered
     * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
     * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
     * @param bool $useLocking Try to lock log file before doing any writes
     *
     * @throws \Exception
     */
    public function __construct($channelDirName = null, $maxFileSize = 10485760, $level = Logger::DEBUG, bool $bubble = true, int $filePermission = null, bool $useLocking = false)
    {
        $this->runtimeLogPath = runtime_path() . '/logs/';
        $this->channelDirName = $channelDirName;
        $dateDir = date('Ym').'/';
        $filename = date('d') .'.log';
        $fullFilePath = empty($channelDirName) ? $this->runtimeLogPath . $dateDir .$filename : $this->runtimeLogPath . $this->channelDirName . '/' . $dateDir . $filename;
        $this->maxFileSize = (int)$maxFileSize;
        if ($maxFileSize <= 0) {
            throw new \Exception('Max file size must be higher than 0');
        }
        parent::__construct($fullFilePath, $level, $bubble, $filePermission, $useLocking);
    }

    /**
     * {@inheritdoc}
     */
    public function close(): void
    {
        parent::close();
        if ($this->mustRotate) {
            $this->rotate();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function reset()
    {
        parent::reset();
        if ($this->mustRotate) {
            $this->rotate();
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function write(array $record): void
    {
        $dateDir = date('Ym') . '/';
        $logBasePath = empty($this->channelDirName) ? $this->runtimeLogPath . $dateDir : $this->runtimeLogPath . $this->channelDirName . '/' . $dateDir;
        $fullLogFilename = $logBasePath . date('d').'.log';
        clearstatcache(true, $fullLogFilename);
        if (file_exists($fullLogFilename)) {
            $fileSize = filesize($fullLogFilename);
            if ($fileSize >= $this->maxFileSize) {
                $this->mustRotate = true;
                $this->close();
            }else{
                $this->stream = null;
                $this->url = $fullLogFilename;
            }
        }else{
            // 解决WebMan启动后删除日志文件无法写入的问题
            $this->mustRotate = true;
            $this->close();
        }
        parent::write($record);
    }

    /**
     * Rotates the files.
     */
    protected function rotate()
    {
        // skip GC of old logs if file size is unlimited
        if ($this->maxFileSize === 0) {
            return;
        }
        $dateDir = date('Ym') . '/';
        $logBasePath = empty($this->channelDirName) ? $this->runtimeLogPath . $dateDir : $this->runtimeLogPath . $this->channelDirName . '/' . $dateDir;
        $filename = date('d').'.log';
        $fullLogFilename = $logBasePath . $filename;
        // archive latest file
        clearstatcache(true, $fullLogFilename);
        if (file_exists($fullLogFilename)) {
            $target = $logBasePath.  date('Y-m') . '_' .  $filename;
            rename($fullLogFilename, $target);
        }else{
            if (!is_dir($logBasePath))
            {
                mkdir($logBasePath,0755,true);
            }
            $this->url = $fullLogFilename;
        }
        $this->mustRotate = false;
    }
}