#include "pch.h"
#include "aLog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/async.h"

//app全局通用的logger实例
std::shared_ptr<spdlog::logger> alog;

static std::wstring _LogFilePath;
static std::wstring _LogFilePath2;

spdlog::sink_ptr pConsoleSink;
spdlog::sink_ptr pFileSink;
spdlog::sink_ptr pFileSink2;

// 用于console log
static FILE* _stream=nullptr;
static bool  _consoleAttached = false; // 附着到父进程的控制台
static bool  _consoleAllocated = false; // 我们新创建的控制台

static void _initConsoleLog()
{
	// 若已存在控制台，直接使用；否则尝试附着父进程控制台，失败再创建
	if (GetConsoleWindow()) {
		// 已有控制台（通常是控制台子系统）
	}
	else if (AttachConsole(ATTACH_PARENT_PROCESS)) {
		_consoleAttached = true;
	}
	else if (AllocConsole()) {
		_consoleAllocated = true;
	}
	// 若成功获得控制台，重定向 stdout 并设置 UTF-8
	if (GetConsoleWindow()) {
		//freopen_s(&_stream, "CONOUT$", "w", stdout);
		SetConsoleOutputCP(CP_UTF8);

		// 尝试启用虚拟终端处理（让 ANSI 颜色也能生效，兼容使用 ansicolor sink 的场景）
		HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
		if (hOut != INVALID_HANDLE_VALUE) {
			DWORD mode = 0;
			if (GetConsoleMode(hOut, &mode)) {
				// 添加虚拟终端 & 已处理输出标志（如果父控制台支持则颜色更稳定）
				SetConsoleMode(hOut, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
			}
		}

		pConsoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
		pConsoleSink->set_level(spdlog::level::debug);
	}
}

static void _deinitConsoleLog()
{
	pConsoleSink.reset();
	if (_stream) {
		fclose(_stream);
		_stream = nullptr;
	}

	// 只在我们附着或创建过控制台时释放
	if (_consoleAttached || _consoleAllocated) {
		FreeConsole();
		_consoleAttached = false;
		_consoleAllocated = false;
	}
}

void InitRollFileLog(std::shared_ptr<spdlog::logger>& log, const char * logname, int flag, const fs::path& logDir, const std::wstring& filename, int logfilesize_K, int logfilenum)
{
	spdlog::drop(logname); // 删除原来的logger

	std::time_t t = std::time(nullptr);

	// 创建异步logger, 默认必须有一个文件log

	auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}.log", filename, fmt::localtime(t));
	_LogFilePath = (logDir / name).wstring();
	log = spdlog::create_async_nb<spdlog::sinks::rotating_file_sink_mt>(logname, _LogFilePath, size_t(logfilesize_K) * 1024, logfilenum);


	pFileSink = log->sinks()[0]; 

	// 添加console log
	if (flag & INIT_CONSOLE_LOG) {
		_initConsoleLog();
		if(pConsoleSink) log->sinks().push_back(pConsoleSink);
	}
	
	pFileSink->set_level(spdlog::level::debug);

	if(flag & INIT_ERROR_FILE_LOG) {
		auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}_error.log", filename, fmt::localtime(t));
		_LogFilePath2 = (logDir / name).wstring();
		pFileSink2 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(_LogFilePath2, size_t(logfilesize_K) * 1024, logfilenum);

		pFileSink2->set_level(spdlog::level::warn);
		log->sinks().push_back(pFileSink2);
	}

	log->set_level(spdlog::level::debug);
	log->flush_on(spdlog::level::err);              //记录error立即flush一次
	spdlog::flush_every(std::chrono::seconds(5));   //5秒钟flush一次
}

void InitBasicFileLog(std::shared_ptr<spdlog::logger>& log, const char* logname, int flag, const fs::path& logDir, const std::wstring& filename)
{
	spdlog::drop(logname); // 删除原来的logger

	std::time_t t = std::time(nullptr);

	// 创建异步logger, 默认必须有一个文件log

	auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}.log", filename, fmt::localtime(t));
	_LogFilePath = (logDir / name).wstring();
	log = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>(logname, _LogFilePath);

	pFileSink = log->sinks()[0];

	// 添加console log
	if (flag & INIT_CONSOLE_LOG) {
		_initConsoleLog();
		log->sinks().push_back(pConsoleSink);
	}

	pFileSink->set_level(spdlog::level::debug);

	if (flag & INIT_ERROR_FILE_LOG) {
		auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}_error.log", filename, fmt::localtime(t));
		_LogFilePath2 = (logDir / name).wstring();
		pFileSink2 = std::make_shared<spdlog::sinks::basic_file_sink_mt>(_LogFilePath2);

		pFileSink2->set_level(spdlog::level::warn);
		log->sinks().push_back(pFileSink2);
	}

	log->set_level(spdlog::level::debug);
	log->flush_on(spdlog::level::err);              //记录error立即flush一次
	spdlog::flush_every(std::chrono::seconds(5));   //5秒钟flush一次
}

// ---- 这两段用于简单的程序，只开console log -----

// 仅开Console log
void aLogInitConsole()
{
	spdlog::drop(""); // 删除默认logger

	// 创建异步logger
	alog = spdlog::create_async_nb<spdlog::sinks::stdout_color_sink_mt>("");

	pConsoleSink = alog->sinks()[0];
	pConsoleSink->set_level(spdlog::level::debug);

	_initConsoleLog();

	alog->set_level(spdlog::level::debug);
	alog->flush_on(spdlog::level::err);              //记录error立即flush一次
	spdlog::flush_every(std::chrono::seconds(5));   //5秒钟flush一次

}

void LogDeinit(std::shared_ptr<spdlog::logger>& log, bool byelog)
{
	// 关闭前打印一条信息
	if(byelog) alog->info("Log正常关闭");
	alog->flush();
	Sleep(100); // 确保已经输出了
	alog->sinks().clear();

	if (pConsoleSink) {
		_deinitConsoleLog();
	}
	if (pFileSink) {
		pFileSink.reset();
	}
	if (pFileSink2) {
		pFileSink.reset();
	}

	spdlog::shutdown();
}

// ---- 这两段用于5C，运行过程中随时开启、关闭console log -----

// 如果没开启Console log，打开
void openConsoleLog()
{
	if (!pConsoleSink) {
		_initConsoleLog();
	}
	alog->sinks().push_back(pConsoleSink);

}

// 如果已经打开了Console Log，关闭掉
void closeConsoleLog()
{
	if (pConsoleSink) {//开启了console要关闭
		for (auto it = alog->sinks().begin(); it != alog->sinks().end(); it++) {
			if (pConsoleSink == *it) {
				alog->warn("已停止刷新Log到Console");
				alog->flush();
				Sleep(100); // 确保已经输出了
				alog->sinks().erase(it); // 假设没有别的线程在输出
				Sleep(100); // 确保已经输出了
				_deinitConsoleLog();
				break;
			}
		}
	}
}

