//---------------------------------------------------------------------------
#include "logger.h"

#include "stdTools.h"
#include <cstring>
#include <iomanip>
#include <ctime>
#include <iostream>
#include <sstream>
#include <filesystem>
#include <sys/stat.h>

//---------------------------------------------------------------------------
Logger::Logger(std::string fileName){
	this->fileName = fileName;
	this->stop = false;
	std::string folder = Utility::BeforeLast(fileName,Utility::separator());
	if (!Utility::createFolder(folder)) {
		std::cerr << "Error create folder: " << folder << std::endl;
	}
	openLogFile();
	logThread = std::thread(&Logger::processQueue, this);
};
//---------------------------------------------------------------------------
Logger::~Logger() {
	{
		std::unique_lock<std::mutex> lock(queueMutex);
		stop = true;
	}
	queueCondition.notify_all();
	logThread.join();
};
//---------------------------------------------------------------------------
//Сервисная функция
std::string Logger::getCurrentDateTime() {
    std::time_t now = std::time(nullptr);
    std::tm* nowTm = std::localtime(&now);
    std::ostringstream timeStream;
    timeStream << std::put_time(nowTm, "%Y-%m-%dT%H:%M:%S");
    return timeStream.str();
}
//---------------------------------------------------------------------------
void Logger::log(std::string thread, std::string level, std::string data, bool cout)
{
	{
		std::unique_lock<std::mutex> lock(queueMutex);
		LogRec rec;
		rec.thread = thread;
		rec.level = level;
		rec.data = data;
		rec.cout = cout;
		logQueue.push(rec);
	}
	queueCondition.notify_one();
}
//---------------------------------------------------------------------------
void Logger::processQueue() {
	while (true) {
		{
			std::unique_lock<std::mutex> lock(queueMutex);
			// Ждем до 1 минуты или пока условие не выполнится
			queueCondition.wait_for(lock, std::chrono::minutes(1), [this] { return !logQueue.empty() || stop; });

			if (stop && logQueue.empty()){
				break;
			}

			if(!logQueue.empty()){
				LogRec rec = std::move(logQueue.front());
				logQueue.pop();
				writeLog(rec.thread,rec.level,rec.data,rec.cout);
			}

			//Всё что ниже для переименовывания старого файла
    	    if(!std::filesystem::exists(fileName)){
    	    	continue;
    	    }
		    // Получаем время создания файла (st_ctime)
            struct stat fileInfo;
            if (stat(fileName.c_str(), &fileInfo) != 0) {
                std::cerr << "Error getting file info: " << fileName << std::endl;
                continue;
            }
            std::time_t creationTime = fileInfo.st_ctime;
            std::tm* creation_tm = std::localtime(&creationTime);

		    // Получаем текущее время
		    auto now = std::chrono::system_clock::now();
		    std::time_t now_c = std::chrono::system_clock::to_time_t(now);
		    std::tm* now_tm = std::localtime(&now_c);

		    //Если даты не совпадают то переименовываю файл в с датой создания и переоткрываю новый файл
		    if(	(now_tm->tm_year != creation_tm->tm_year) ||
		        (now_tm->tm_mon != creation_tm->tm_mon) ||
		        (now_tm->tm_mday != creation_tm->tm_mday)){

	    	    if(file.is_open()) {
	    	    	file.close();
	    	    }

				char buffer[11]; // Длина строки "YYYY-MM-DD" + '\0'
				std::memset(buffer, 0, sizeof(buffer));
				std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", creation_tm);
	    	    std::ostringstream newFileName;
	    	    newFileName << Utility::BeforeLast(fileName,'.') << "_" << buffer << "." << Utility::AfterLast(fileName,'.');

	    	    std::string newName = newFileName.str();

				try {
					std::filesystem::rename(fileName, newName);
				} catch (const std::filesystem::filesystem_error& e) {
					std::cerr << "Error renaming file: " << e.what() << std::endl;
				}

	        	//Удаляю старые файлы
				std::string folder = Utility::BeforeLast(fileName,Utility::separator());
				Utility::deleteOldFiles(folder,10);
		    }
		}
	}
}
//---------------------------------------------------------------------------
void Logger::openLogFile() {
    file.open(fileName, std::ios::out | std::ios::app);
    if (!file.is_open()) {
        std::cerr << "Error open file: " << fileName << std::endl;
    }
}
//---------------------------------------------------------------------------
void Logger::writeLog(std::string thread, std::string level, std::string data, bool cout)
{
	if (!file.is_open()){
		openLogFile();
	}
	//Записываем лог
	if (file.is_open())
	{
		std::stringstream str(std::stringstream::out | std::stringstream::binary);
		std::string dateTime = getCurrentDateTime();
		thread = Utility::escape_json(thread);
		level = Utility::escape_json(level);
		data = Utility::escape_json(data);
		str << "{\"timestamp\":\"" << dateTime << "\", \"thread\":\"" <<thread<<"\", \"level\":\""<<level<<"\", \"message\":\"" << data <<"\"}" << std::endl;

		if (cout)
			std::cout << "[" << dateTime << "] " << data << std::endl; //Повтор лога в консоль

		file.write(str.str().c_str(), str.str().length());
		file.flush();
	}
}
//---------------------------------------------------------------------------
//std::string Logger::getCurrentDate() {
//    std::time_t now = std::time(nullptr);
//    std::tm* nowTm = std::localtime(&now);
//    std::ostringstream timeStream;
//    timeStream << std::put_time(nowTm, "%Y-%m-%d");
//    return timeStream.str();
//}
//---------------------------------------------------------------------------
