#include "log_upper_data.h"
#include "modbus.h"
#include "../common.h"
#include <sys/syslog.h>

#define UD_LOG_LBUFF_SIZE 10
UA_NodeId UD_LOG_UA_NODE;
long ud_log_Level;

struct UD_log *ud_log_list_head;
pthread_rwlock_t ud_log_rwlock;

int UD_log_init()
{
    UD_LOG_UA_NODE.namespaceIndex = 0;
    UD_LOG_UA_NODE.identifierType = UA_NODEIDTYPE_NUMERIC;

    ud_log_list_head = (struct UD_log *)calloc(1, sizeof(struct UD_log));
    
    if(NULL == ud_log_list_head)
    {
        fprintf(stderr, "Error,malloc failed!\n");
        fflush(stderr);
        return 1;

    }

    INIT_LIST_HEAD(&ud_log_list_head->list);
    ud_log_list_head->file_name = NULL;

    if(pthread_rwlock_init(&ud_log_rwlock, NULL))
    {
        fprintf(stderr, "Error, ud_log_rwlock init err!!\n");
        fflush(stderr);
        return 1;
    }

    if(pthread_mutex_init(&ud_log_list_head->mutex, NULL))
    {
        fprintf(stderr, "Error, ud_log_list_head->mutex init err!!\n");
        fflush(stderr);
        return 1;
    }


    return 0;
}

int UD_log_check_null(struct UD_log *self)
{
    if(NULL== ud_log_list_head)
    {
        fprintf(stderr, "Error, ud_log_list_head is NULL!!\n");
        fflush(stderr);
        return 1;
    }
    if(NULL == self || NULL == self->file_name)
    {
        fprintf(stderr, "Error,self or file_name is NULL!!\n");
        fflush(stderr);
        return 1;
    }
    if( TRUE != self->en )
    {
        return 1;
    }

    return 0;
}

struct UD_log *UD_log_creat(const char *file_name, SET_EN_BACK set_en_back)
{
    if(NULL == file_name)
    {
        fprintf(stderr, "Error,file_name is NULL?\n");
        fflush(stderr);
        return NULL;
    }
    if(strlen(file_name) > UD_LOG_FILE_LEN)
    {
        fprintf(stderr, "Error,file_name > 20 size! you need to reset!\n");
        fflush(stderr);
        return NULL;
    }

    struct UD_log *tmp = (struct UD_log *)malloc(sizeof(struct UD_log));

    if(NULL == tmp)
    {
        fprintf(stderr, "Error,malloc failed!\n");
        fflush(stderr);
        return NULL;
    }
    
    tmp->file_name = file_name;
    tmp->en = 0;
    tmp->set_en_back = set_en_back;
    if(lbuff_init(&tmp->prt_buf, UD_LOG_LBUFF_SIZE))
    {
        free(tmp);
        return NULL;
    }


    if(pthread_mutex_init(&tmp->mutex, NULL))
    {
        lbuff_free(&tmp->prt_buf);
        free(tmp);
        return NULL;
    }

    list_add_tail(&tmp->list, &ud_log_list_head->list);

    return tmp;
}

int UD_log_update_en()
{
    if (!list_empty(&ud_log_list_head->list))
    {
        struct UD_log *pos = NULL;
        list_for_each_entry(pos, &ud_log_list_head->list, list)
        {
            if(NULL == pos || NULL == pos->file_name)
            {
                continue;
            }

            pthread_rwlock_rdlock(&ud_log_rwlock);
            pthread_mutex_lock(&pos->mutex);
                if(TRUE == pos->set_en_back(pos))
                {
                    pos->en = TRUE;
                }
                else 
                {
                    pos->en = FALSE;
                }
            pthread_mutex_unlock(&pos->mutex);
            pthread_rwlock_unlock(&ud_log_rwlock);
        
        }
        
    }
    
    return 0;
}

int UD_log_sprintf(struct UD_log *self, const char *p, ...)
{
    va_list args;
    va_start(args, p);

    // 1. 快速路径：self 为空时直接输出到系统日志
    if (UD_log_check_null(self)) {
        char buf[10240];
        vsnprintf(buf, sizeof(buf), p, args);
        ems_syslog(LOG_DEBUG, "%s", buf);
        va_end(args);
        return 1;
    }

    // 2. 复制格式串（防止 p 被意外修改）
    char *p_copy = strdup(p);
    if (!p_copy) {
        va_end(args);
        return 2;
    }

    // 3. 准备参数副本用于探测长度，同时保留原始 args 供后续使用
    va_list args_try;
    va_copy(args_try, args);

    // 4. 栈上默认缓冲区
    char stack_buf[1024];
    char *buffer = stack_buf;
    int need_free = 0;   // 标记是否分配了堆内存

    // 5. 尝试用栈缓冲区格式化，同时获取所需长度（不含结尾 '\0'）
    int len = vsnprintf(stack_buf, sizeof(stack_buf), p_copy, args_try);
    va_end(args_try);

    if (len < 0) {
        // vsnprintf 输出错误（极少发生）
        free(p_copy);
        va_end(args);
        return 0;
    }

    if (len >= (int)sizeof(stack_buf)) {
        // 栈缓冲区不足，动态分配所需大小（+1 给 '\0'）
        buffer = (char *)malloc(len + 1);
        if (!buffer) {
            free(p_copy);
            va_end(args);
            return 3;
        }
        need_free = 1;
        // 使用原始 args 进行第二次格式化
        vsnprintf(buffer, len + 1, p_copy, args);
    }

    // 6. 加锁写入缓冲区
    pthread_rwlock_rdlock(&ud_log_rwlock);
    pthread_mutex_lock(&self->mutex);
    int ret = lbuff_sprintf(&self->prt_buf, "%s", buffer);
    pthread_mutex_unlock(&self->mutex);
    pthread_rwlock_unlock(&ud_log_rwlock);

    // 7. 清理资源
    if (need_free) {
        free(buffer);
    }
    free(p_copy);
    va_end(args);

    return ret;
}

int clear_UD_log(struct UD_log *self)
{

    if(UD_log_check_null(self))
    {
        return 1;
    }
    lbuff_setlen(&self->prt_buf, 1);
    pthread_rwlock_unlock(&ud_log_rwlock);

    return 0;
}

int fwrite_flush_UD_log(struct UD_log *self)
{
    pthread_rwlock_rdlock(&ud_log_rwlock);
    if(UD_log_check_null(self))
    {
        return 1;
    }
    char buf[1024];
    sprintf(buf, "/tmp/%s", self->file_name);
    FILE *fp = fopen(buf, "w");
    if (fwrite(self->prt_buf.bufptr, 1, self->prt_buf.curlen, fp) != (size_t)self->prt_buf.curlen) {
        perror("fwrite_flush_UD_log: Write error");
        lbuff_setlen(&self->prt_buf, 0);

        fclose(fp);
        return 2;
    }
    lbuff_setlen(&self->prt_buf, 0);
    fclose(fp);
    pthread_rwlock_unlock(&ud_log_rwlock);

    return 0;
}

int UD_log_free(struct UD_log *self)
{
    if(UD_log_check_null(self))
    {
        return 1;
    }
    pthread_rwlock_wrlock(&ud_log_rwlock);
    
    lbuff_free(&self->prt_buf);
    if (!list_empty(&ud_log_list_head->list))
    {
        struct UD_log *pos = NULL;
        list_for_each_entry(pos, &ud_log_list_head->list, list)
        {
            if (strcmp(pos->file_name, self->file_name))
            {
                list_del(&pos->list);
            }
        }
    }
    self->file_name = NULL;
    pthread_mutex_destroy(&self->mutex);
    
    free(self);

    pthread_rwlock_unlock(&ud_log_rwlock);
    return 0;
}

