#include "business_log.h"
#include "pthread.h"
#include "string.h"
#include <stdlib.h>
#include "dy_utils/hash_intptr.h"
#include "../common.h"
#include <stdio.h>
#include <ctype.h>
#include "lnxall_list.h"
#include "lnxall_ubuslog.h"
static struct hash_intptr *business_log_hash;
static pthread_mutex_t business_log_lock = PTHREAD_MUTEX_INITIALIZER;

static int count_format(const char *fmt) {
    int count = 0;
    const char *p = fmt;
    
    while (*p != '\0') {
        if (*p == '%' && *(p+1) != '\0') {
            if (*(p+1) == '%') {
                p += 2;
                continue;
            }
            count++;
            p++;
            while (*p != '\0' && !isalpha(*p)) {
                p++;
            }
            if (*p != '\0') {
                p++;
            }
        } else {
            p++;
        }
    }
    
    return count;
}

/*
* @description: 记录业务日志(去重复)
* @param level 日志等级
* @param main_id 主ID
* @param line 代码行号
* @param obj_id 对象ID
* @param fmt 日志格式
* @description:使用注意事项：该函数用于记录业务日志,所以需确保同一个主ID+对象ID组合的日志起码调用两次。如（禁充、解除）,否则无法记录日志变更。
*/
void business_log(int level, int main_id, int line, const char *obj_id, const char *fmt, ...)
{
    va_list args;
    char log_content[2048] = {0};
    int key;
    BUSINESS_LOG_STATUS *old_status = NULL;
    BUSINESS_LOG_STATUS *new_status = NULL;
    int need_log = 0;
    
    va_start(args, fmt);
    vsnprintf(log_content, sizeof(log_content), fmt, args);
    va_end(args);
    
    const char *actual_obj_id = obj_id ? obj_id : "";
    
    // 生成key：只使用main_id和对象id标识的组合，确保同一对象的不同状态变化能被正确跟踪
    char key_base[256] = {0};
    if (obj_id == NULL || strlen(obj_id) == 0) {
        if(count_format(fmt) > 0)
            snprintf(key_base, sizeof(key_base), "%d_%d", main_id, line);
        else
            snprintf(key_base, sizeof(key_base), "%d", main_id);
    } else {
        snprintf(key_base, sizeof(key_base), "%d_%s", main_id, actual_obj_id);
    }
    
    unsigned int hash = 0;
    for (int i = 0; key_base[i] != '\0'; i++) {
        hash = hash * 31 + key_base[i];
    }
    key = hash;
    
    pthread_mutex_lock(&business_log_lock);

    if (hash_intptr_findptr(business_log_hash, &key, sizeof(int), (void **)&old_status) == 0) {
        // 已存在该日志状态，根据obj_id是否为空采用不同的去重策略
        if (obj_id == NULL || strlen(obj_id) == 0) {
            int has_args = (count_format(fmt) > 0);
            if (has_args) {
                // 有参数：比较日志内容
                if (old_status->content == NULL || strcmp(old_status->content, log_content) != 0) {
                    need_log = 1;
                }
            } else {
                // 无参数：直接判断line是否相同
                if (old_status->line != line) {
                    need_log = 1;
                }
            }
        } else {
            // obj_id不为空：直接比较日志内容
            if (old_status->content == NULL || strcmp(old_status->content, log_content) != 0) {
                need_log = 1;
            }
        }
    } else {
        need_log = 1;
    }
    
    if (need_log) {
        new_status = (BUSINESS_LOG_STATUS *)malloc(sizeof(BUSINESS_LOG_STATUS));
        if (new_status != NULL) {
            new_status->main_id = main_id;
            new_status->line = line;
            new_status->content = strdup(log_content);
            
            hash_intptr_addptr(&business_log_hash, &key, sizeof(int), new_status);
            lnxall_syslog_uid(level, BUSINESS_LOG_UID, "%sid[%d]:%s",log_level_string[level],main_id,log_content);
        }
        
        if (old_status != NULL) {
            if (old_status->content != NULL) {
                free(old_status->content);
            }
            free(old_status);
        }
    }
    pthread_mutex_unlock(&business_log_lock);
}