#include <stdio.h>
#include <sys/types.h>
#include <errno.h>
#include <miniunz.h>
#include <minizip.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>    
#include <sys/stat.h>
#include <signal.h>		 	
#include "wave_record_file_system.h"
#include "toolkit.h"
#include "wave_record_json_prase.h"
#include "linux_zip.h"
#include "bmser_log.h"
#include "wave_record_csv_storage.h"
#include "project_userdef.h"
#include "bmser_error_code.h"

#define SIGUSRSTOP							(50)

#define MAX_ZIP_NUM                         256   //一次性最多可以处理10个压缩处理
#define MAX_FILE_TYPE_LEN                   10
#define TAR_NAME_PREFIX                     "bak_"
#define USEDATA_DRS_FILE                    "/tmp/ems/bmser/drs.log"
static bool g_stop_tar = false;             //是否停止压缩,当收到掉电信号后停止压缩
static pthread_mutex_t g_tar_mutex = {0};   //压缩互斥锁


typedef struct
{
    uint8_t isNeedCompress;
    uint8_t format;
    char zipName[MAX_PATH_NAME_LEN];
    char fpath[MAX_PATH_NAME_LEN];
    char fileType[8];
    char baseFolder[32];
}LINUX_ZIP_INFO;

LINUX_ZIP_INFO  g_zipInfo[MAX_ZIP_NUM] = {0};
pthread_t    tid;


#define TAR_BAU_CSV_FILE_CMD_STR(id)        "nice -n 19 find -name \"*%s%d[A-Za-z_]*.*\" | grep \"%s\"| xargs tar zcf %s%s"
#define TAR_BCU_CSV_FILE_CMD_STR(id)        "nice -n 19 find -name \"*%s%d[A-Za-z_]*.*\" | grep \"%s\"| xargs tar zcf %s%s"
#define TAR_TYPE_CSV_FILE_CMD_STR(type)     "nice -n 19 find -name \"*%s*.*\"|grep \"%s\"| xargs tar zcf %s%s"
#define RM_BAU_CSV_FILE_CMD_STR             "nice -n 19 find %s/%s -name \"*%s%d[A-Za-z_]*.*\"|grep \"%s\" | xargs rm"
#define RM_BCU_CSV_FILE_CMD_STR             "nice -n 19 find %s/%s -name \"*%s%d[A-Za-z_]*.*\"|grep \"%s\" | xargs rm"
#define RM_TYPE_CSV_FILE_CMD_STR            "nice -n 19 find %s/%s -name \"*%s*.*\"|grep \"%s\"| xargs rm"
#define RM_BAK_CSV_FILE_CMD_STR             "nice -n 19 find %s/%s -mindepth 1 -type d|xargs rm -rf;nice -n 19 find %s/%s -name \"*.*\" | grep -vE \"%04d-%02d-%02d|%04d_%02d_%02d\" | xargs rm -rf;sync"

#define MAX_SAME_DATA_FILE_CNT              (30)
#define FIND_FILE_DATE_CMD_STR              "nice -n 19  find %s/%s -type f -name \"*.*\" | grep -vE \"%04d-%02d-%02d|%04d_%02d_%02d\" | sed -n '1p' | sed -nE 's/.*([0-9]{4}[-_][0-9]{2}[-_][0-9]{2}).*/\\1/p'"
#define FIND_DATA_FILE_CNT_CMD_STR          "nice -n 19 find %s/%s -name \"*%s*.*\"| grep \"%s\"| wc -l"

static int format_tar_cmd_string(const char *baseFolder, const char *tar_cmd, const char *tar_name, char *cmd_buf, int len)
{
    if (!tar_cmd || !tar_name || !baseFolder || !cmd_buf || len <= 0) {
        return -1;
    }

    int offset = 0;
    char cd_folder[128] = {0}, tar_folder[32] = {0};
    char file_path[256 + 128] = {0}, bak_file_path[512] = {0};

    snprintf(tar_folder, sizeof(tar_folder), "%s/%s", baseFolder, "tar");

    memset(cmd_buf, 0, len);
    memset(file_path, 0, sizeof(file_path));
    memset(bak_file_path, 0, sizeof(bak_file_path));
    //example: "/bmsLog/tar/bak/bak2023-12-12.tar.gz"
    snprintf(bak_file_path, sizeof(bak_file_path), "%s/%s/%s%s", baseFolder, BMS_LOG_TAR_FOLDER_NAME, TAR_NAME_PREFIX, tar_name);
    if (access(bak_file_path, F_OK) == F_OK) { //说明压缩过程中有断电
        offset += snprintf(cmd_buf + offset, len - offset, "rm %s;", bak_file_path);
        dy_syslog(LOG_DEBUG, "already exist bak tar file = %s, rm bak first.", bak_file_path);
    }

    #if 0
    snprintf(file_path, sizeof(file_path), "%s/%s", tar_folder, tar_name);
    snprintf(cd_folder, sizeof(cd_folder), "cd %s/%s", baseFolder, BMS_LOG_TAR_FOLDER_NAME);
    if (access(file_path, F_OK) == F_OK) {  //说明已经压缩,在rm老的文件夹时断电
        dy_syslog(LOG_DEBUG, "already exist tar file = %s.", file_path);
        offset += snprintf(cmd_buf + offset, len - offset, "%s;", cd_folder);
    } else {
        offset += snprintf(cmd_buf + offset, len - offset, "%s;%s", cd_folder, tar_cmd);
    }
    #endif
    //修改了逻辑,压缩包名称是在压缩完成后才确定的, 会带下标,而传入的tar_name是无下标的,因此只要有csv文件都进行压缩
    //进入tar目录下bak目录，目标csv文件会mv到这个目录
    snprintf(cd_folder, sizeof(cd_folder), "cd %s/%s", baseFolder, BMS_LOG_TAR_FOLDER_NAME);
    offset += snprintf(cmd_buf + offset, len - offset, "%s;%s", cd_folder, tar_cmd);

    return offset;
}

static int32_t handle_system_cmd(char *cmd_buf, const char *baseFolder, char *tar_name, char *c_date)
{
    int32_t i = 0, ret  = 0, status = 0;
    char tarName[512] = {0}, tarFolder[256] = {0};
    char sysCmd[1024 + 128] = {0};

    BMSER_CHECK_PARA_NULL_RETURN_VAL(cmd_buf, OPRT_PARA_NULL);
    BMSER_CHECK_PARA_NULL_RETURN_VAL(baseFolder, OPRT_PARA_NULL);
    BMSER_CHECK_PARA_NULL_RETURN_VAL(tar_name, OPRT_PARA_NULL);

    dy_syslog(LOG_DEBUG, "dev tar cmd %s.\n", cmd_buf); 
     // 记录当前时间并查看指定目录的空间占用情况并保存到文件
    //system("echo -n 'Current time: ' >> /tmp/directory_sizes.txt && date >> /tmp/directory_sizes.txt && du -sh /bmsLog/tar/bak /bmsLog/tar /bmsLog >> /tmp/directory_sizes.txt");
    status = system(cmd_buf);
    if ( WIFEXITED(status) && 0 == WEXITSTATUS(status)) { //WIFEXITED(status) 判断子进程是否是正常退出的，如果是则返回一个非零值, WEXITSTATUS(status)) 子进程的返回值
        ret = 0;
    } else {
        dy_syslog(LOG_ERR, "tar files fail!");
        ret = status;
        return ret;
    }

    //获取压缩名时间戳所在的目录
    //#define BMS_LOG_TAR_FILE_FOLDER             "tar"
    //tarFolder=/bmsLog/tar
    snprintf(tarFolder, sizeof(tarFolder), "%s/%s", baseFolder, BMS_LOG_TAR_FILE_FOLDER);
    if (access(tarFolder, 0) == -1) {
        snprintf(sysCmd, sizeof(sysCmd), "mkdir -p %s", tarFolder);
        if (0 != system(sysCmd)) {
            return -1;
        }
    }

    //压缩成功后,需要将压缩包名称去掉前缀
    snprintf(tarName, sizeof(tarName), "%s/%s%s", tarFolder, tar_name, BMS_TAR_FORMAT_NAME);
    if (access(tarName, F_OK) == F_OK) {
        for (i = 1; i <= MAX_SAME_DATA_FILE_CNT; i++) {
            memset(tarName, 0, sizeof(tarName));
            snprintf(tarName, sizeof(tarName), "%s/%s_%d%s", tarFolder, tar_name, i, BMS_TAR_FORMAT_NAME);
            if (access(tarName, F_OK) != F_OK) {
                break;
            }
        }
        
        //如果存在最大个数的tar包,则直接覆盖第一个
        if (i > MAX_SAME_DATA_FILE_CNT) {
            i = 1;
        }
    }

    //拼接mv命令修改压缩包文件名
    memset(sysCmd, 0, sizeof(sysCmd));
    if (0 == i) {
        snprintf(sysCmd, sizeof(sysCmd), "mv %s/%s/%s%s%s %s/%s%s", baseFolder, BMS_LOG_TAR_FOLDER_NAME, TAR_NAME_PREFIX, tar_name, BMS_TAR_FORMAT_NAME, \
        tarFolder, tar_name, BMS_TAR_FORMAT_NAME);
    } else {
        snprintf(sysCmd, sizeof(sysCmd), "mv %s/%s/%s%s%s %s/%s_%d%s", baseFolder, BMS_LOG_TAR_FOLDER_NAME, TAR_NAME_PREFIX, tar_name, BMS_TAR_FORMAT_NAME, \
        tarFolder, tar_name, i, BMS_TAR_FORMAT_NAME);
    }
    system(sysCmd);

#ifdef LOCAL_DEBUG
    memset(sysCmd, 0, sizeof(sysCmd));
    snprintf(sysCmd, sizeof(sysCmd), "echo \"tar cmd = %s, ret = %d, time = %ld.\" >> %s", cmd_buf, ret, time(NULL), USEDATA_DRS_FILE);
    system(sysCmd);
#endif

    return ret;
}

static int handle_compress_tar_gz(const char *zipName, const char *baseFolder, const char *fpath)
{
    if (NULL == zipName || NULL == baseFolder || NULL == fpath) {
        return -1;
    }

    time_t timer = 0;
    struct tm tblock;
    int year = 0, mon = 0, day = 0, cnt = 0;
    char c_date[16] = {0};

    int ret = 0, len = 0, result = 0;
    int idx = 0, type = 0, rack_num = 0;
    FILE *fp = NULL, *fp_type = NULL;
    char result_buf[8] = {0}, cmd[256] = {0};
    char name[32] = {0};
    char cmd_buf[1024] = {0}, sysCmd[1024 + 128] = {0};
    char tar_pre_name[256] = {0}, tar_name[256 + 32] = {0}, tar_cmd[256 + 64] = {0}, rm_cmd[512] = {0};

    dy_syslog(LOG_DEBUG, "baseFolder = %s, path = %s.", baseFolder, fpath);

    rack_num = waveRecordJson_getBcuNum();
    dy_syslog(LOG_DEBUG, "get rack num = %d.", rack_num);


    //获取当天的时间戳
    timer = time(NULL);
    localtime_r(&timer, &tblock);
    year = tblock.tm_year + 1900;
    mon = tblock.tm_mon + 1;
    day = tblock.tm_mday;


    //找一个非当天的csv文件时间戳
    memset(sysCmd, 0, sizeof(sysCmd));
    snprintf(sysCmd, sizeof(sysCmd), FIND_FILE_DATE_CMD_STR, baseFolder, BMS_LOG_TAR_FOLDER_NAME, year, mon, day, year, mon, day);
    dy_syslog(LOG_DEBUG, "sysCmd = %s.", sysCmd);
    fp = popen(sysCmd, "r");
    if (NULL == fp) {
        return OPRT_OPEN_FILE_FAIL;
    }
    memset(c_date, 0, sizeof(c_date));
    fgets(c_date, sizeof(c_date), fp); //获取日期
    while (strlen(c_date) > 0 && cnt < MAX_SAME_DATA_FILE_CNT)
    {
        c_date[strlen(c_date) - 1] = '\0'; //去掉日期换行符
        dy_syslog(LOG_DEBUG, "parse tar file date = %s.", c_date);
        {
            //tar_pre_name:bank0_2023-12-29 modify -> 2023-12-29
            snprintf(tar_pre_name, sizeof(tar_pre_name), "%s", c_date);
            //tar_name:bank0_2023-12-29.tar.gz  modify -> 2023-12-29.tar.gz
            snprintf(tar_name, sizeof(tar_name), "%s%s", c_date, BMS_TAR_FORMAT_NAME);
            //#define TAR_BAU_CSV_FILE_CMD_STR(id)        "nice -n 19 find -name \"*%s%d[A-Za-z_]*.*\" | grep \"%s\"| xargs tar zcf %s%s"
            //找到所有的目标date的csv文件，并压缩为对应的bak$date.tar.gz
            snprintf(tar_cmd, sizeof(tar_cmd), "nice -n 19 find -name \"*.csv\" | grep \"%s\"| xargs tar zcf %s%s", c_date, TAR_NAME_PREFIX, tar_name);
        }
        //baseFolder = '/bmsLog'
        //执行上面拼接好的cmd命令
        len = format_tar_cmd_string(baseFolder, tar_cmd, tar_name, cmd_buf, sizeof(cmd_buf));
        if (len <= 0) {
            continue;
        }
        
        //判断压缩结果,只有压缩成功后,才将源文件删除
        result = handle_system_cmd(cmd_buf, baseFolder, tar_pre_name, c_date);
        if (0 == result) {
            //#define RM_BAU_CSV_FILE_CMD_STR             "nice -n 19 find %s/%s -name \"*%s%d[A-Za-z_]*.*\"|grep \"%s\" | xargs rm"
            snprintf(rm_cmd, sizeof(rm_cmd), "nice -n 19 find %s/%s -name \"*.csv\"|grep \"%s\" | xargs rm", baseFolder, BMS_LOG_TAR_FOLDER_NAME,c_date);
            system(rm_cmd);
        } else {
            ret |= result;
        }
        pclose(fp);

        fp = popen(sysCmd, "r");
        if (NULL == fp) {
            return OPRT_OPEN_FILE_FAIL;
        }
        memset(c_date, 0, sizeof(c_date));
        fgets(c_date, sizeof(c_date), fp); //获取日期
        cnt++;
    }
    pclose(fp);

    if (0 != ret) { //有压缩失败的场景则直接退出
        dy_syslog(LOG_ERR, "tar file exist fail, ret = %d.", ret);
        return ret;
    }
    
    //只删除bak目录中的目录文件和非当天的文件
    memset(rm_cmd, 0, sizeof(rm_cmd));
    //#define RM_BAK_CSV_FILE_CMD_STR "nice -n 19 find %s/%s -mindepth 1 -type d|xargs rm -rf;nice -n 19 find %s/%s -name \"*.*\" | grep -vE \"%04d-%02d-%02d|%04d_%02d_%02d\" | xargs rm -rf;sync"
    //删除bak目录中日期目录;
    //删除bak目录中分非当天csv文件
    snprintf(rm_cmd, sizeof(rm_cmd), RM_BAK_CSV_FILE_CMD_STR, baseFolder, BMS_LOG_TAR_FOLDER_NAME, baseFolder, BMS_LOG_TAR_FOLDER_NAME, year, mon, day, year, mon, day);
    ret = system(rm_cmd);
    dy_syslog(LOG_DEBUG, "rm cmd = %s.", rm_cmd);

#ifdef LOCAL_DEBUG
    memset(sysCmd, 0, sizeof(sysCmd));
    snprintf(sysCmd, sizeof(sysCmd), "echo \"rm cmd = %s, ret = %d, time = %ld.\" >> %s", rm_cmd, ret, time(NULL), USEDATA_DRS_FILE);
    dy_syslog(LOG_DEBUG, "sysCmd = %s.", sysCmd);
    system(sysCmd);
#endif

    return ret;
}

void * linuxZip_CompressThread(void* arg)
{
    while (1)
    {
        pthread_mutex_lock(&g_tar_mutex);
        for(int i = 0; i < MAX_ZIP_NUM; i++)
        {
            if (g_zipInfo[i].isNeedCompress == 1 && false == g_stop_tar)
            {
                handle_compress_tar_gz(g_zipInfo[i].zipName, (const char*)g_zipInfo[i].baseFolder, g_zipInfo[i].fpath);

                g_zipInfo[i].isNeedCompress = 0;
                g_zipInfo[i].format = 0;
                memset(g_zipInfo[i].baseFolder,0, sizeof(g_zipInfo[i].baseFolder));
                memset(g_zipInfo[i].zipName,0, MAX_PATH_NAME_LEN);
                memset(g_zipInfo[i].fpath, 0, MAX_PATH_NAME_LEN);
                wave_record_fs_calc_storage_size();
            }
        }
        pthread_mutex_unlock(&g_tar_mutex);
        sleep(1);
    }

    return 0;
}

int linuxZip_Compress(char* fpath,char* zipName,char *fileType)
{
    for (int i = 0; i < MAX_ZIP_NUM; i++)
    {
        if (g_zipInfo[i].isNeedCompress == 0)
        {
            g_zipInfo[i].isNeedCompress = 1;
            memcpy(g_zipInfo[i].zipName, zipName, strlen(zipName));
            memcpy(g_zipInfo[i].fpath, fpath, strlen(fpath));
            memcpy(g_zipInfo[i].fileType, fileType, MIN(MAX_FILE_TYPE_LEN,strlen(fileType)));
            return 0;
        }
    }

    return -1;
}

int linuxZip_Compress_ext(char*baseFolder, u_int8_t format, char* fpath, char* zipName, char *fileType)
{
    pthread_mutex_lock(&g_tar_mutex);
    for (int i = 0; i < MAX_ZIP_NUM; i++)
    {
        if (g_zipInfo[i].isNeedCompress == 0)
        {
            g_zipInfo[i].isNeedCompress = 1;
            g_zipInfo[i].format = format;
            memcpy(g_zipInfo[i].zipName, zipName, strlen(zipName));
            memcpy(g_zipInfo[i].fpath, fpath, strlen(fpath));
            memcpy(g_zipInfo[i].baseFolder, baseFolder, strlen(baseFolder));
            memcpy(g_zipInfo[i].fileType, fileType, MIN(MAX_FILE_TYPE_LEN,strlen(fileType)));
            pthread_mutex_unlock(&g_tar_mutex);
            return 0;
        }
    }
    pthread_mutex_unlock(&g_tar_mutex);

    return -1;
}

int linuxZip_Decompress(char* zipName)
{
    start_extract_zip(zipName, NULL, 1, "./");

    return 0;
}

void __handle_drs_stop_signal(int signal)
{
    dy_syslog(LOG_DEBUG, "recv stop drs signal.\n");
    g_stop_tar = true;
    system("killall tar");
    system("/etc/init.d/bmser_drs stop");
    dy_syslog(LOG_DEBUG, "handle drs stop signal finish.\n");
    return;
}

int wave_record_zip_init()
{
    int ret;
    char baseName[32] = {0}, tar_folder[128] = {0}, cmd[256] = {0};

    //创建tar包日志存放路径    
    waveRecordJson_getDir(baseName);
    if (access(baseName, F_OK) != F_OK) {
        printf("base folder is %s not exist.\n", baseName);
        return -1;
    }

    ret = pthread_mutex_init(&g_tar_mutex, NULL);
    if (0 != ret) {
        dy_syslog(LOG_ERR, "mutex init fail, ret = %d.", ret);
        return ret;
    }

    snprintf(tar_folder, sizeof(tar_folder), "%s/%s", baseName, BMS_LOG_TAR_FOLDER_NAME);
    if (access(tar_folder, 0) == -1) {
        snprintf(cmd, sizeof(cmd), "mkdir -p %s", tar_folder);
        if (0 != system(cmd)) {
            printf("creat tar file dir failed:%s.\n", tar_folder);
            return -1;
        }
    }

    //注册掉电处理信号
    signal(SIGUSRSTOP, __handle_drs_stop_signal);
    
    //创建一条线程 
    ret = pthread_create(&tid, NULL, linuxZip_CompressThread, NULL);
    if (ret != 0)
    {
        fprintf(stderr, "创建线程失败!\n");
        return -1;
    }

    return ret;
}

int linuxZip_Compress_Stop()
{
    g_stop_tar = true;
    system("killall tar");
    return 0;
}
