#include "Logger.h"
#include <QDebug>
#include <QDir>
#include <QFileInfo>

// Initialize static members
QScopedPointer<Logger> Logger::m_instance; // Correct: Default constructs to a null pointer
QMutex Logger::m_instanceMutex;

Logger& Logger::getInstance(const QString &filePath)
{
    // Use a QMutexLocker to ensure thread-safe initialization of the singleton
    QMutexLocker locker(&m_instanceMutex);
    if (m_instance.isNull()) {
        if (filePath.isEmpty()) {
            qWarning() << "Logger: No file path provided for initial singleton creation. Logging might be disabled.";
            // Fallback to a default or disable logging, or throw an error.
            // For simplicity, we'll proceed but warn.
            m_instance.reset(new Logger("default.log")); // Provide a default if not given
        } else {
            m_instance.reset(new Logger(filePath));
        }
    }
    return *m_instance;
}

// Private constructor
Logger::Logger(const QString &filePath)
    : m_logFile(filePath),
    m_textStream(&m_logFile),
    m_maxFileSize(10 * 1024 * 1024), // Default to 10 MB
    m_maxBackupFiles(5)             // Default to 5 backup files
{
    QFileInfo fileInfo(filePath);
    QDir dir = fileInfo.absoluteDir();
    if (!dir.exists()) {
        dir.mkpath("."); // Create directory if it doesn't exist
    }

    if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
        qWarning() << "Logger: Could not open log file for writing:" << m_logFile.errorString();
    } else {
        info("Logger initialized."); // Log the initialization
    }
}

// Private destructor
Logger::~Logger()
{
    if (m_logFile.isOpen()) {
        info("Logger shutting down."); // Log shutdown
        m_logFile.close();
    }
}

void Logger::debug(const QString &message)
{
    writeLog(Debug, message);
}

void Logger::info(const QString &message)
{
    writeLog(Info, message);
}

void Logger::warn(const QString &message)
{
    writeLog(Warning, message);
}

void Logger::error(const QString &message)
{
    writeLog(Error, message);
}

void Logger::critical(const QString &message)
{
    writeLog(Critical, message);
}

void Logger::writeLog(LogLevel level, const QString &message)
{
    QMutexLocker locker(&m_mutex);

    if (!m_logFile.isOpen()) {
        qWarning() << "Logger: Log file is not open. Message not written:" << message;
        return;
    }

    if (m_logFile.size() > m_maxFileSize) {
        rotateLogFile();
    }

    QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    QString logLevelStr = logLevelToString(level);

    m_textStream << QString("[%1] [%2] %3\n").arg(timestamp).arg(logLevelStr).arg(message);
    m_textStream.flush();
}

void Logger::setMaxFileSize(qint64 bytes)
{
    m_maxFileSize = bytes;
}

void Logger::setMaxBackupFiles(int count)
{
    m_maxBackupFiles = count;
}

void Logger::rotateLogFile()
{
    m_logFile.close();

    QFileInfo fileInfo(m_logFile.fileName());
    QString baseName = fileInfo.baseName();
    QString suffix = fileInfo.suffix();
    QString absolutePath = fileInfo.absolutePath();

    for (int i = m_maxBackupFiles - 1; i >= 0; --i) {
        QString oldLogFileName = QString("%1/%2.%3.%4").arg(absolutePath).arg(baseName).arg(i).arg(suffix);
        QFile oldLogFile(oldLogFileName);
        if (oldLogFile.exists()) {
            if (i == m_maxBackupFiles - 1) {
                oldLogFile.remove();
            } else {
                QString newLogFileName = QString("%1/%2.%3.%4").arg(absolutePath).arg(baseName).arg(i + 1).arg(suffix);
                oldLogFile.rename(newLogFileName);
            }
        }
    }

    QString newCurrentLogFileName = QString("%1/%2.%3.%4").arg(absolutePath).arg(baseName).arg(0).arg(suffix);
    m_logFile.rename(newCurrentLogFileName);

    if (!m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
        qWarning() << "Logger: Could not reopen log file after rotation:" << m_logFile.errorString();
    }
}

QString Logger::logLevelToString(LogLevel level) const
{
    switch (level) {
    case Debug:
        return "DEBUG";
    case Info:
        return "INFO";
    case Warning:
        return "WARNING";
    case Error:
        return "ERROR";
    case Critical:
        return "CRITICAL";
    default:
        return "UNKNOWN";
    }
}
