#include "myLog.h"
#include "myBase.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>

#define NONE                 "\033[0m"
#define BLACK                "\033[0;30m"
#define L_BLACK              "\033[1;30m"
#define RED                  "\033[0;31m"
#define L_RED                "\033[1;31m"
#define GREEN                "\033[0;32m"
#define L_GREEN              "\033[1;32m"
#define BROWN                "\033[0;33m"
#define YELLOW               "\033[1;33m"
#define BLUE                 "\033[0;34m"
#define L_BLUE               "\033[1;34m"
#define PURPLE               "\033[0;35m"
#define L_PURPLE             "\033[1;35m"
#define CYAN                 "\033[0;36m"
#define L_CYAN               "\033[1;36m"
#define GRAY                 "\033[0;37m"
#define WHITE                "\033[1;37m"

#define BOLD                 "\033[1m"
#define UNDERLINE            "\033[4m"
#define BLINK                "\033[5m"
#define REVERSE              "\033[7m"
#define HIDE                 "\033[8m"
#define CLEAR                "\033[2J"
#define CLRLINE              "\r\e[K" //or "\e[1K\r"

// 日志配置
#define LOG_FILE_PATH       "/mnt/RTU/release/exe/logs"
#define LOG_FILE_NAME       "app.log"
#define LOG_FILE_MAX_SIZE   (10 * 1024 * 1024)
#define LOG_FILE_MAX_COUNT  5

// 异步日志配置
#define LOG_QUEUE_SIZE      10000       // 日志队列大小
#define LOG_FLUSH_INTERVAL  100         // 刷新间隔（毫秒）
#define LOG_BATCH_SIZE      100         // 批量写入大小
#define LOG_BUFFER_SIZE     4096

// 日志消息结构
typedef struct log_message 
{
    uint32_t level;
    char timestamp[64];
    char file_info[128];
    char content[LOG_BUFFER_SIZE];
    size_t content_len;
    struct log_message* next;
} log_message_t;

// 日志队列
typedef struct 
{
    log_message_t* head;
    log_message_t* tail;
    int count;
    pthread_mutex_t mutex;
    pthread_cond_t not_empty;
    pthread_cond_t not_full;
} log_queue_t;

// 异步日志线程
typedef struct 
{
    log_queue_t queue;
    pthread_t thread_id;
    int running;
    FILE* log_fp;
    long log_file_size;
    int log_to_file;
    int log_to_console;
    pthread_mutex_t file_mutex;
} async_logger_t;

static async_logger_t logger = 
{
    .queue = 
	{
        .head = NULL,
        .tail = NULL,
        .count = 0,
        .mutex = PTHREAD_MUTEX_INITIALIZER,
        .not_empty = PTHREAD_COND_INITIALIZER,
        .not_full = PTHREAD_COND_INITIALIZER
    },
    .running = 0,
    .log_fp = NULL,
    .log_file_size = 0,
    .log_to_file = 0,
    .log_to_console = 1,
    .file_mutex = PTHREAD_MUTEX_INITIALIZER
};

// 预分配消息池，避免频繁malloc/free
static log_message_t* message_pool = NULL;
static pthread_mutex_t pool_mutex = PTHREAD_MUTEX_INITIALIZER;

static pthread_once_t log_once = PTHREAD_ONCE_INIT;

// 日志级别定义
static const char* log_level[LOG_LEVEL_MAX] = 
{
    "INFO",
    "ERROR",
};

static const char* code[LOG_LEVEL_MAX] = 
{
    WHITE,
    RED,
};

// 初始化消息池
static int init_message_pool(void) 
{
    pthread_mutex_lock(&pool_mutex);
    if (message_pool == NULL) 
	{
        message_pool = (log_message_t*)calloc(LOG_QUEUE_SIZE, sizeof(log_message_t));
        if (message_pool == NULL) 
		{
            pthread_mutex_unlock(&pool_mutex);
            return -1;
        }
        
        // 链接空闲列表
        for (int i = 0; i < LOG_QUEUE_SIZE - 1; i++) 
		{
            message_pool[i].next = &message_pool[i + 1];
        }
        message_pool[LOG_QUEUE_SIZE - 1].next = NULL;
    }
    pthread_mutex_unlock(&pool_mutex);
    return 0;
}

// 从池中获取消息
static log_message_t* get_message_from_pool(void) 
{
    pthread_mutex_lock(&pool_mutex);
    log_message_t* msg = message_pool;
    if (msg != NULL) 
	{
        message_pool = msg->next;
        msg->next = NULL;
    }
    pthread_mutex_unlock(&pool_mutex);
    return msg;
}

// 归还消息到池中
static void return_message_to_pool(log_message_t* msg) 
{
    if (msg == NULL) 
	{	
		return;
	}
    
    pthread_mutex_lock(&pool_mutex);
    msg->next = message_pool;
    message_pool = msg;
    pthread_mutex_unlock(&pool_mutex);
}

// 入队日志消息
static int enqueue_log(log_message_t* msg) 
{
    pthread_mutex_lock(&logger.queue.mutex);
    
    // 等待队列非满
    while (logger.queue.count >= LOG_QUEUE_SIZE) 
	{
        pthread_cond_wait(&logger.queue.not_full, &logger.queue.mutex);
    }
    
    // 入队
    if (logger.queue.tail == NULL) 
	{
        logger.queue.head = msg;
        logger.queue.tail = msg;
    } 
	else 
	{
        logger.queue.tail->next = msg;
        logger.queue.tail = msg;
    }
    logger.queue.count++;
    
    // 通知消费者
    pthread_cond_signal(&logger.queue.not_empty);
    pthread_mutex_unlock(&logger.queue.mutex);
    
    return 0;
}

// 出队日志消息
static log_message_t* dequeue_log(void) 
{
    pthread_mutex_lock(&logger.queue.mutex);
    
    // 等待队列非空
    while (logger.queue.count == 0 && logger.running) 
	{
        pthread_cond_wait(&logger.queue.not_empty, &logger.queue.mutex);
    }
    
    if (logger.queue.count == 0) 
	{
        pthread_mutex_unlock(&logger.queue.mutex);
        return NULL;
    }
    
    log_message_t* msg = logger.queue.head;
    logger.queue.head = msg->next;
    if (logger.queue.head == NULL) 
	{
        logger.queue.tail = NULL;
    }
    logger.queue.count--;
    
    // 通知生产者
    pthread_cond_signal(&logger.queue.not_full);
    pthread_mutex_unlock(&logger.queue.mutex);
    
    return msg;
}

// 获取当前日志文件路径
static void get_log_file_path(char* path, size_t size, int index) 
{
    if (index == 0) 
	{
        snprintf(path, size, "%s/%s", LOG_FILE_PATH, LOG_FILE_NAME);
    } else 
	{
        snprintf(path, size, "%s/%s.%d", LOG_FILE_PATH, LOG_FILE_NAME, index);
    }
}

// 初始化日志目录
static int init_log_directory(void) 
{
    struct stat st = {0};
    if (stat(LOG_FILE_PATH, &st) == -1) 
	{
		LOG_E("Failed to stat log directory %s", LOG_FILE_PATH);
        if (mkdir(LOG_FILE_PATH, 0755) == -1) 
		{
			LOG_E("Failed to create log directory %s", LOG_FILE_PATH);
            return -1;
        }
    }

    LOG_I("Log directory %s create success", LOG_FILE_PATH);

    return 0;
}

// 轮转日志文件
static void rotate_log_files(void) 
{
    char old_path[256];
    char new_path[256];
    
    pthread_mutex_lock(&logger.file_mutex);
    
    if (logger.log_fp != NULL) 
	{
        fclose(logger.log_fp);
        logger.log_fp = NULL;
    }
    
    // 删除最旧的文件
    get_log_file_path(old_path, sizeof(old_path), LOG_FILE_MAX_COUNT);
    remove(old_path);
    
    // 轮转现有文件
    for (int i = LOG_FILE_MAX_COUNT - 1; i >= 1; i--) 
	{
        get_log_file_path(old_path, sizeof(old_path), i);
        get_log_file_path(new_path, sizeof(new_path), i + 1);
        rename(old_path, new_path);
    }
    
    // 重命名当前文件
    get_log_file_path(old_path, sizeof(old_path), 0);
    get_log_file_path(new_path, sizeof(new_path), 1);
    rename(old_path, new_path);
    
    logger.log_file_size = 0;
    pthread_mutex_unlock(&logger.file_mutex);
}

// 打开日志文件
static FILE* open_log_file_internal(void) 
{
    if (init_log_directory() != 0) 
	{
		LOG_E("Failed to init log directory");
        return NULL;
    }
    
    char file_path[256];
    get_log_file_path(file_path, sizeof(file_path), 0);
    
    // 检查文件大小
    struct stat st;
    if (stat(file_path, &st) == 0) 
	{
        if (st.st_size > LOG_FILE_MAX_SIZE) 
		{
            rotate_log_files();
        } 
		else 
		{
            logger.log_file_size = st.st_size;
        }
    }
    
    FILE* fp = fopen(file_path, "a");
    if (fp != NULL) 
	{
        setlinebuf(fp);
    }
    
    return fp;
}

// 批量写入日志
static void write_log_batch_array(log_message_t* batch[], int count) 
{
    if (count == 0) return;
    
    // 控制台输出（带颜色）
    if (logger.log_to_console) 
    {
        for (int i = 0; i < count; i++) 
        {
            // 控制台输出也加上时间戳，使用消息中保存的时间
            printf("%s[%s] [%s%s%s] %s\n", 
                   code[batch[i]->level],
                   batch[i]->timestamp,                    
                   code[batch[i]->level], 
                   log_level[batch[i]->level], 
                   NONE, 
                   batch[i]->content);
        }
        
        fflush(stdout);
    }
    
    // 文件输出
    if (logger.log_to_file) 
    {
        pthread_mutex_lock(&logger.file_mutex);
        
        // 确保文件打开
        if (logger.log_fp == NULL) 
        {
            logger.log_fp = open_log_file_internal();
        }
        
        if (logger.log_fp != NULL) 
        {
            size_t total_len = 0;
            
            for (int i = 0; i < count; i++) 
            {
                fprintf(logger.log_fp, "[%s] [%s] %s\n", 
                        log_level[batch[i]->level], batch[i]->timestamp, batch[i]->content);
                total_len += strlen(batch[i]->content) + 64;
            }
            
            fflush(logger.log_fp);
            logger.log_file_size += total_len;
            
            // 检查是否需要轮转
            if (logger.log_file_size > LOG_FILE_MAX_SIZE) 
            {
                fclose(logger.log_fp);
                logger.log_fp = NULL;
                rotate_log_files();
                logger.log_fp = open_log_file_internal();
            }
        }
        
        pthread_mutex_unlock(&logger.file_mutex);
    }
}

// 日志处理线程
static void* log_worker_thread(void* arg) 
{
    (void)arg;

    while (logger.running) 
    {
        log_message_t* batch[LOG_BATCH_SIZE];
        int batch_count = 0;
        
        // 批量获取消息
        pthread_mutex_lock(&logger.queue.mutex);
        
        while (batch_count < LOG_BATCH_SIZE && logger.queue.count > 0) 
        {
            log_message_t* msg = logger.queue.head;
            logger.queue.head = msg->next;
            if (logger.queue.head == NULL) 
            {
                logger.queue.tail = NULL;
            }
            logger.queue.count--;
            batch[batch_count++] = msg;
        }
        
        pthread_cond_broadcast(&logger.queue.not_full);
        pthread_mutex_unlock(&logger.queue.mutex);
        
        // 处理消息
        if (batch_count > 0) 
        {
            // 批量写入
            write_log_batch_array(batch, batch_count);
            
            // 归还消息到池中
            for (int i = 0; i < batch_count; i++) 
            {
                return_message_to_pool(batch[i]);
            }
        } 
        else 
        {
            // 没有消息，休眠
            usleep(LOG_FLUSH_INTERVAL * 1000);
        }
    }
    
    return NULL;
}

// 格式化日志时间
static char* log_make_time(char* buf, const uint32_t bufLen) 
{
    if(buf != NULL) 
	{
        struct timeval tt;
        gettimeofday(&tt, NULL);
        struct tm* ptm = localtime(&tt.tv_sec);
        if(ptm != NULL) 
		{
            snprintf(buf, bufLen, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
                    ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday,
                    ptm->tm_hour, ptm->tm_min, ptm->tm_sec, 
                    (int)tt.tv_usec/1000);
        }
    }
    return buf;
}

// 格式化文件信息
static void format_file_info(char* buffer, size_t size, const char *file_name, const char *func, uint32_t line) 
{
    if((file_name != NULL) && (func != NULL)) 
	{
        char* p_ch = NULL;
        if ((p_ch = strrchr((char *)file_name, '/')) == NULL) 
		{
            if ((p_ch = strrchr((char *)file_name, '\\')) == NULL) 
			{
                p_ch = (char*)file_name;
            } 
			else 
			{
                p_ch++;
            }
        } 
		else 
		{
            p_ch++;
        }
        snprintf(buffer, size, "%s/%s:%d", p_ch, func, line);
    } 
	else 
	{
        snprintf(buffer, size, "unknown/unknown:0");
    }
}



static void log_global_init(void) 
{
    // 所有初始化代码移到这里
    init_message_pool();
    logger.running = 1;
    pthread_create(&logger.thread_id, NULL, log_worker_thread, NULL);
}

// 主日志函数（非阻塞）
void log_prt(const uint32_t level, const char *file, const char *func, uint32_t line, const char *fmt, ...) 
{
	pthread_once(&log_once, log_global_init);  // 自动初始化

    if((level >= LOG_LEVEL_MAX) || (fmt == NULL) || !logger.running) 
	{
        return;
    }

    // 获取消息对象
    log_message_t* msg = get_message_from_pool();
    if (msg == NULL) 
	{
        // 队列满了，丢弃日志
		// LOG_E("Failed to get message from pool");
        return;
    }
    
    msg->level = level;
    msg->next = NULL;
    
    // 获取时间
    log_make_time(msg->timestamp, sizeof(msg->timestamp));
    
    // 获取文件信息
    format_file_info(msg->file_info, sizeof(msg->file_info), file, func, line);
    
    // 格式化日志内容
    va_list args;
    va_start(args, fmt);
    
    int pos = snprintf(msg->content, sizeof(msg->content), 
                       "[%s] ", msg->file_info);
    
    if (pos < sizeof(msg->content)) 
	{
        pos += vsnprintf(msg->content + pos, sizeof(msg->content) - pos, fmt, args);
    }
    
    msg->content_len = strlen(msg->content);
    va_end(args);
    
    // 入队
    enqueue_log(msg);
}



// 设置文件日志开关
void log_set_file_enabled(int enabled) 
{
    logger.log_to_file = enabled;
}

// 设置控制台日志开关
void log_set_console_enabled(int enabled) {
    logger.log_to_console = enabled;
}

// 刷新日志（等待队列清空）
void log_flush(void) {
    // 等待队列清空
    while (1) 
	{
        pthread_mutex_lock(&logger.queue.mutex);
        int count = logger.queue.count;
        pthread_mutex_unlock(&logger.queue.mutex);
        
        if (count == 0) 
		{
			break;
		}

        usleep(10000);  // 10ms
    }
}

// 关闭日志系统
void log_cleanup(void) 
{
    if (!logger.running) 
	{
        return;
    }
    
    logger.running = 0;
    
    // 唤醒工作线程
    pthread_cond_signal(&logger.queue.not_empty);
    
    // 等待线程结束
    pthread_join(logger.thread_id, NULL);
    
    // 关闭文件
    pthread_mutex_lock(&logger.file_mutex);
    if (logger.log_fp != NULL) 
	{
        fclose(logger.log_fp);
        logger.log_fp = NULL;
    }
    pthread_mutex_unlock(&logger.file_mutex);
    
    // 释放消息池
    pthread_mutex_lock(&pool_mutex);
    if (message_pool != NULL) 
	{
        free(message_pool);
        message_pool = NULL;
    }
    pthread_mutex_unlock(&pool_mutex);
}