#include "logger.h"
#include <QCoreApplication>
#include <QSettings>
#include <QFileInfo>
#include <QDir>
#include <QTextStream>

Logger& Logger::instance()
{
    //采用静态局部变量的方式，静态局部变量的初始化是在第一次访问时，以后的调用不会多次初始化，并且生命周期和程序一致
    static Logger instance;
    return instance;
}

Logger::Logger()
{
    initialize();
}

Logger::~Logger()
{
    shutdown();
}

void Logger::initialize()
{
    //默认配置
    m_logFilePath = "";
    m_logLevel = INFO;
    m_maxFileSize = 1024 *1024 * 10; //10MB
    m_maxBackupFiles = 5;
    m_outputToConsole = true;
    m_outputOtFile = true;
    //从配置文件中加载配置
    loadConfig();
    //创建log文件
    QString filePath = QCoreApplication::applicationDirPath() + "/log/app.log";
    setLogFile(filePath);
}

void Logger::loadConfig(/*const QString& configFilePath*/)
{
    QString settingFile = QCoreApplication::applicationDirPath() + "/config/log_config.ini";
    QFile file(settingFile);
    if(file.open(QIODevice::ReadWrite))
    {
        m_settings = new QSettings(settingFile, QSettings::IniFormat);

        QString strLevel = m_settings->value("Log/level").toString().toUpper();
        if(strLevel == "DEBUG")
            m_logLevel = DEBUG;
        else if(strLevel == "INFO")
            m_logLevel = INFO;
        else if(strLevel == "WARNING")
            m_logLevel = WARNING;
        else if(strLevel == "ERROR")
            m_logLevel = ERROR;
        else if(strLevel == "FATAL")
            m_logLevel = FATAL;

        m_maxFileSize = m_settings->value("Log/maxSize").toLongLong();
        m_maxBackupFiles = m_settings->value("Log/backups").toInt();
        QString strOutputToConsole = m_settings->value("Log/consoleOutput").toString();
        if(strOutputToConsole == "true")
            m_outputToConsole = true;
        else
            m_outputToConsole = false;
        QString strOutputToFile = m_settings->value("Log/fileOutput").toString();
        if(strOutputToFile == "true")
            m_outputOtFile = true;
        else
            m_outputOtFile = false;

    }
}

void Logger::setLogFile(const QString& filePath)
{
    //检查目录文件所在目录，如果不存在则创建目录
    QFileInfo fileInfo(filePath);
    QDir logDir = fileInfo.dir();
    if(!logDir.exists())
        logDir.mkpath(".");

    //更新log文件前要先关闭当前已打开的文件
    if(m_logFile.isOpen())
        m_logFile.close();

    m_logFilePath = filePath;
    m_logFile.setFileName(filePath);
}

void Logger::shutdown()
{
    if(m_logFile.isOpen())
        m_logFile.close();
}

void Logger::writeToFile(const QString& message)
{
    if(m_logFilePath.isEmpty())
        return;

    if(!m_logFile.isOpen())
    {
        if (!m_logFile.open(QIODevice::Append | QIODevice::Text))
        {
            qWarning() << "Failed to open log file:" << m_logFile.errorString();
            return;
        }
        //打开文件时先键入一个换行符
        QTextStream stream(&m_logFile);
        stream.setEncoding(QStringConverter::Utf8);//强制UTF-8编码
        stream  << Qt::endl;
        stream.flush(); //刷新输出缓冲区，确保数据立即写入文件
    }

    QTextStream stream(&m_logFile);
    stream << message << Qt::endl;
    stream.flush(); //刷新输出缓冲区，确保数据立即写入文件

    if(m_logFile.size() > m_maxFileSize)
        rollLogFiles();
}

void Logger::rollLogFiles()
{
    if(m_logFile.isOpen())
        m_logFile.close();

    //删除最旧的备份文件(备份文件以‘日志文件.数字’的格式命名，数字越大表示文件越旧)
    QFile::remove(QString("%1.%2").arg(m_logFilePath).arg(m_maxBackupFiles));
    //剩余文件依次更改名称
    for(int i = m_maxBackupFiles - 1; i > 0; i--)
        QFile::rename(QString("%1.%2").arg(m_logFilePath).arg(i), QString("%1.%2").arg(m_logFilePath).arg(i + 1));
    //将当前日志文件更改为'最新'的备份文件(编号为1)
    QFile::rename(m_logFilePath, QString("%1.1").arg(m_logFilePath));
    //更新当前配置文件(重新打开)
    m_logFile.setFileName(m_logFilePath);
    if (!m_logFile.open(QIODevice::Append | QIODevice::Text))
        qWarning() << "Failed to open new log file after rolling:" << m_logFile.errorString();
}

QString Logger::fromatLogMessage(LogLevel level, const QString& context, const QString& message)
{
    static const char* levelStrings[] = {"FATAL", "ERROR", "WARNING", "INFO", "DEBUG"};
    return QString("[%1] [%2] [%3] %4")
        .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")
             ,levelStrings[level]
             ,context
             ,message);
}

void Logger::log(LogLevel level, const QString& context, const QString& message)
{
    if(level > m_logLevel)
        return;

    QString formatMessage = fromatLogMessage(level, context, message);
    if(m_outputToConsole)
         QTextStream(stderr) << formatMessage << Qt::endl;
    if(m_outputOtFile)
        writeToFile(formatMessage);
}
