#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#endif
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <libgen.h>
#include "convert_multi_to_zip64_flat_modular.h"

// 调试开关
#define DEBUG_ALL               0
#define DEBUG_COLLECT           0
#define DEBUG_ARGS              0
#define DEBUG_LOAD              0
#define DEBUG_SPLIT             0
#define DEBUG_PIGZ              0
#define DEBUG_7ZA               0
#define DEBUG_PARSE_SMALLS      0
#define DEBUG_PARSE_GZ          0
#define DEBUG_ZIP64             0
#define DEBUG_TIME              1

// 1. 路径和临时目录准备
// 修改为直接接收output_zip和parent_dir
void prepare_paths_and_tmpdir(const char *output_zip, const char *parent_dir, PathInfo *path_info) {
    char *target_dir = strdup(output_zip);
    char *target_dirname = dirname(target_dir);
    if (!realpath(target_dirname, path_info->abs_target_zip)) {
        fprintf(stderr, "[DEBUG] realpath target zip dir failed: %s\n", output_zip);
        free(target_dir);
        exit(1);
    }
    char *output_zip_copy = strdup(output_zip);
    snprintf(path_info->final_zip_path, sizeof(path_info->final_zip_path),
             "%s/%s", path_info->abs_target_zip, basename(output_zip_copy));
    free(output_zip_copy);
    free(target_dir);
    snprintf(path_info->tmpdir, sizeof(path_info->tmpdir), "%s.tmpdir", output_zip);
    mkdir(path_info->tmpdir, 0700);
    if (!realpath(path_info->tmpdir, path_info->abs_tmpdir)) {
        fprintf(stderr, "[DEBUG] realpath(tmpdir) failed: %s\n", path_info->tmpdir);
        exit(1);
    }
    strncpy(path_info->parent_dir, parent_dir, MAX_PATH-1);
    path_info->parent_dir_set = 1;
}

// 该函数用于向 flat_entries 数组中添加一个文件或目录的信息。
// 参数说明：
//   flat_entries    ：指向 FlatFileEntry* 的指针，表示文件/目录信息数组
//   flat_entry_count：指向当前已添加元素数量的指针
//   flat_entry_cap  ：指向当前数组容量的指针
//   abs_path        ：文件或目录的绝对路径
//   entry_name      ：在zip包中的相对路径（或条目名）
//   orig_size       ：原始文件大小（目录为0）
//   is_dir          ：是否为目录（1为目录，0为文件）
// 功能：
//   - 如果 flat_entries 数组容量不足，则自动扩容（初始128，之后每次翻倍）。
//   - 将文件/目录的相关信息写入 flat_entries 数组，并递增 flat_entry_count。
void add_flat_entry(FlatFileEntry **flat_entries, size_t *flat_entry_count, size_t *flat_entry_cap, const char *abs_path, const char *entry_name, uint64_t orig_size, int is_dir) {
    if (*flat_entry_count == *flat_entry_cap) {
        *flat_entry_cap = *flat_entry_cap ? *flat_entry_cap * 2 : 128;
        *flat_entries = realloc(*flat_entries, *flat_entry_cap * sizeof(FlatFileEntry));
    }
    strncpy((*flat_entries)[*flat_entry_count].abs_path, abs_path, MAX_PATH-1);
    strncpy((*flat_entries)[*flat_entry_count].entry_name, entry_name, MAX_PATH-1);
    (*flat_entries)[*flat_entry_count].orig_size = orig_size;
    (*flat_entries)[*flat_entry_count].is_dir = is_dir;
    (*flat_entry_count)++;
}

int is_tmpdir_path(const char *path) {
    const char *p = strstr(path, ".tmpdir");
    if (!p) return 0;
    if (p[strlen(".tmpdir")] == '\0' || p[strlen(".tmpdir")] == '/' )
        return 1;
    return 0;
}

void collect_files_flat(const char *input_path, const char *base_dir, const char *parent_dir, FlatFileEntry **flat_entries, size_t *flat_entry_count, size_t *flat_entry_cap) {
    if (is_tmpdir_path(input_path)) return;
    struct stat st;
    if (stat(input_path, &st) != 0) return;
    if (S_ISDIR(st.st_mode)) {
        char dir_entry[MAX_PATH];
        snprintf(dir_entry, sizeof(dir_entry), "%s/", base_dir);
        add_flat_entry(flat_entries, flat_entry_count, flat_entry_cap, input_path, dir_entry, 0, 1);
        DIR *dir = opendir(input_path);
        if (!dir) return;
        struct dirent *entry;
        while ((entry = readdir(dir)) != NULL) {
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
            char child_path[MAX_PATH];
            snprintf(child_path, MAX_PATH, "%s/%s", input_path, entry->d_name);
            if (parent_dir) {
                char new_base[MAX_PATH];
                snprintf(new_base, MAX_PATH, "%s/%s", base_dir, entry->d_name);
                collect_files_flat(child_path, new_base, parent_dir, flat_entries, flat_entry_count, flat_entry_cap);
            } else {
                collect_files_flat(child_path, entry->d_name, input_path, flat_entries, flat_entry_count, flat_entry_cap);
            }
        }
        closedir(dir);
    } else if (S_ISREG(st.st_mode)) {
        add_flat_entry(flat_entries, flat_entry_count, flat_entry_cap, input_path, base_dir, st.st_size, 0);
    }
}

void collect_all_files(int argc, char *argv[], FlatFileEntry **flat_entries, size_t *flat_entry_count, PathInfo *path_info) {
    size_t flat_entry_cap = 0;
    for (int i = 2; i < argc; ++i) {
        char abs_path[MAX_PATH];
        if (!realpath(argv[i], abs_path)) {
            fprintf(stderr, "[DEBUG][COLLECT] realpath failed: %s\n", argv[i]);
            continue;
        }
        struct stat st;
        if (stat(abs_path, &st) != 0) {
            fprintf(stderr, "[DEBUG][COLLECT] stat failed: %s\n", abs_path);
            continue;
        }
        if (S_ISDIR(st.st_mode)) {
            const char *base = strrchr(abs_path, '/');
            base = base ? base + 1 : abs_path;
            if (!path_info->parent_dir_set) {
                strncpy(path_info->parent_dir, abs_path, MAX_PATH-1);
                char *slash = strrchr(path_info->parent_dir, '/');
                if (slash) *slash = '\0';
                path_info->parent_dir_set = 1;
            }
            if (DEBUG_ALL || DEBUG_COLLECT) printf("[DEBUG][COLLECT] 递归入口: abs_path=%s, base=%s\n", abs_path, base);
            collect_files_flat(abs_path, base, path_info->parent_dir, flat_entries, flat_entry_count, &flat_entry_cap);
        } else if (S_ISREG(st.st_mode)) {
            const char *base = strrchr(abs_path, '/');
            base = base ? base + 1 : abs_path;
            add_flat_entry(flat_entries, flat_entry_count, &flat_entry_cap, abs_path, base, st.st_size, 0);
        }
    }
    if (DEBUG_ALL || DEBUG_COLLECT) {
        printf("[DEBUG][COLLECT] collect files done, flat_entry_count=%zu\n", *flat_entry_count);
        for (size_t i = 0; i < *flat_entry_count; ++i) {
            printf("[DEBUG][COLLECT] flat_entries[%zu]: abs_path=%s, entry_name=%s, orig_size=%llu\n",
                i, (*flat_entries)[i].abs_path, (*flat_entries)[i].entry_name, (unsigned long long)(*flat_entries)[i].orig_size);
        }
    }
}

// 3. 分流
void split_files(FlatFileEntry *flat_entries, size_t flat_entry_count, FileSplitInfo *split_info) {
    split_info->big_count = 0;
    split_info->small_count = 0;
    split_info->empty_count = 0;
    for (size_t i = 0; i < flat_entry_count; ++i) {
        const char *p = flat_entries[i].abs_path;
        size_t len = strlen(p);
        uint64_t orig_size = flat_entries[i].orig_size;
        if (orig_size == 0) {
            split_info->emptyfiles[split_info->empty_count] = flat_entries[i].abs_path;
            split_info->emptyentry[split_info->empty_count++] = flat_entries[i].entry_name;
            continue;
        }
        if (orig_size > 500*1024*1024) {
            split_info->bigfiles[split_info->big_count] = flat_entries[i].abs_path;
            split_info->bigentry[split_info->big_count++] = flat_entries[i].entry_name;
        } else if (!(len > 3 && strcmp(p + len - 3, ".gz") == 0)) {
            split_info->smallfiles[split_info->small_count] = flat_entries[i].abs_path;
            split_info->smallentry[split_info->small_count++] = flat_entries[i].entry_name;
        }
    }
    if (DEBUG_ALL || DEBUG_SPLIT) {
        printf("[DEBUG][SPLIT] split done, big_count=%d, small_count=%d, empty_count=%d\n", split_info->big_count, split_info->small_count, split_info->empty_count);
    }
}

// 4. 批量压缩大文件
void compress_big_files(FileSplitInfo *split_info, PathInfo *path_info) {
    for (int i = 0; i < split_info->big_count; ++i) {
        char gz_file[MAX_PATH];
        snprintf(gz_file, sizeof(gz_file), "%s/%s.gz", path_info->abs_tmpdir, basename(split_info->bigentry[i]));
        char cmd[MAX_PATH*2];
        snprintf(cmd, sizeof(cmd), "pigz -k -f -c '%s' > '%s'", split_info->bigfiles[i], gz_file);
        if (DEBUG_ALL || DEBUG_PIGZ) {
            printf("[DEBUG][PIGZ] pigz input: %s, output: %s\n", split_info->bigfiles[i], gz_file);
            printf("[DEBUG][PIGZ] pigz cmd: %s\n", cmd);
        }
        int ret = system(cmd);
        if (ret != 0) {
            fprintf(stderr, "[DEBUG][PIGZ] pigz failed: %s\n", split_info->bigfiles[i]);
        }
    }
}

// 5. 生成 smallfile-list.txt
void generate_smallfile_list(FileSplitInfo *split_info, PathInfo *path_info) {
    char file_list_path[MAX_PATH];
    snprintf(file_list_path, sizeof(file_list_path), "%s/smallfile-list.txt", path_info->abs_tmpdir);
    if (DEBUG_ALL || DEBUG_COLLECT) printf("[DEBUG][COLLECT] file_list_path: %s\n", file_list_path);
    FILE *fl = fopen(file_list_path, "w");
    if (!fl) {
        fprintf(stderr, "[DEBUG][COLLECT] 打开文件失败: %s\n", file_list_path);
        exit(1);
    }
    int write_count = 0;
    for (int i = 0; i < split_info->small_count; ++i) {
        const char *entry = split_info->smallentry[i];
        const char *file_name = split_info->smallfiles[i];
        if (strstr(entry, ".tmpdir") != NULL) {
            if (DEBUG_ALL || DEBUG_COLLECT) {
                printf("[DEBUG][COLLECT] 跳过 .tmpdir 路径: %s\n", entry);
            }
            continue;
        }
        struct stat st;
        if (stat(file_name, &st) != 0 || !S_ISREG(st.st_mode)) {
            if (DEBUG_ALL || DEBUG_COLLECT) {
                printf("[DEBUG][COLLECT] 跳过不存在或非普通文件: %s\n", entry);
            }
            continue;
        }
	// 写入绝对路径
        // fprintf(fl, "%s\n", file_name);
	// 写入相对路径
        fprintf(fl, "%s\n", entry);
        write_count++;
        if (DEBUG_ALL || DEBUG_COLLECT) {
        //     printf("[DEBUG][COLLECT] 写入 smallfile-list.txt: %s\n", file_name);
            printf("[DEBUG][COLLECT] 写入 smallfile-list.txt: %s\n", entry);
        }
    }
    fclose(fl);
    if (DEBUG_ALL || DEBUG_COLLECT) {
        printf("[DEBUG][COLLECT] smallfile-list.txt 生成完成, 共写入 %d 个条目\n", write_count);
    }
}

// 6. 小文件批量压缩
void compress_small_files(PathInfo *path_info) {
    char file_list_path[MAX_PATH];
    snprintf(file_list_path, sizeof(file_list_path), "%s/smallfile-list.txt", path_info->abs_tmpdir);

    if (DEBUG_ALL || DEBUG_7ZA) {
	printf("[DEBUG][7ZA] 打印 smallfile-list.txt file list:\n");
	FILE *fl = fopen(file_list_path, "r");
	if (fl) {
		char line[MAX_PATH * 2];
		while (fgets(line, sizeof(line), fl)) {
			printf("[DEBUG][7ZA] %s", line);
		}
		fclose (fl);
	} else {
		printf("[DEBUG][7ZA] open failed file : %s\n", file_list_path);
	}
    }
    char smalls_zip[MAX_PATH];
    snprintf(smalls_zip, sizeof(smalls_zip), "%s/smalls.zip", path_info->abs_tmpdir);

    // 增加 parent_dir 及相关路径日志打印
    if (DEBUG_ALL || DEBUG_7ZA) {
        printf("[DEBUG][7ZA] parent_dir: %s\n", path_info->parent_dir);
        printf("[DEBUG][7ZA] abs_tmpdir: %s\n", path_info->abs_tmpdir);
        printf("[DEBUG][7ZA] file_list_path: %s\n", file_list_path);
        printf("[DEBUG][7ZA] smalls_zip: %s\n", smalls_zip);
        printf("[DEBUG][7ZA] parent_dir_set: %d\n", path_info->parent_dir_set);
    }

    char parent_dir_up[MAX_PATH];
    if (path_info->parent_dir_set) {
        strncpy(parent_dir_up, path_info->parent_dir, MAX_PATH-1);
        parent_dir_up[MAX_PATH-1] = '\0';
	if (DEBUG_ALL || DEBUG_7ZA) {
		printf("[DEBUG][7ZA] parent_dir_up: %s\n", parent_dir_up);
	}
        // char *slash = strrchr(parent_dir_up, '/');
        // if (slash && slash != parent_dir_up) {
        //     *slash = '\0';
        // } else {
        //     strcpy(parent_dir_up, ".");
        // }
        struct stat st;
        if (stat(parent_dir_up, &st) != 0 || !S_ISDIR(st.st_mode)) {
            fprintf(stderr, "[DEBUG] parent_dir上级目录不存在: %s\n", parent_dir_up);
            exit(1);
        }
	if (DEBUG_ALL || DEBUG_7ZA) {
		printf("[DEBUG][7ZA] chdir to parent_dir_up: %s\n", parent_dir_up);
	}
        if (chdir(parent_dir_up) != 0) {
            fprintf(stderr, "[DEBUG] chdir to parent_dir_up failed: %s\n", parent_dir_up);
            exit(1);
        }
    }
    char cmd[MAX_PATH*32];
    snprintf(cmd, sizeof(cmd), "7za a -tzip -mem=AES128 -bd -y -l -mx=1 -i@'%s' -- '%s' > /dev/null", file_list_path, smalls_zip);
//     snprintf(cmd, sizeof(cmd), "cd '%s' && 7za a -tzip -mem=AES128 -bd -y -l -mx=1 -i@'%s' -- '%s' > /dev/null", parent_dir_up, file_list_path, smalls_zip);
    if (DEBUG_ALL || DEBUG_7ZA) printf("[DEBUG][7ZA] 7za cmd: %s\n", cmd);
    int ret = system(cmd);
    if (ret != 0) {
        fprintf(stderr, "[DEBUG][7ZA] 7za failed\n");
    }
}

// 7. 解析 smalls.zip
void parse_smalls_zip(Entry **entries, int *entry_count, PathInfo *path_info) {
    char smalls_zip[MAX_PATH];
    snprintf(smalls_zip, sizeof(smalls_zip), "%s/smalls.zip", path_info->abs_tmpdir);
    FILE *f = fopen(smalls_zip, "rb");
    if (!f) {
        fprintf(stderr, "[DEBUG][PARSE_SMALLS] fopen smalls.zip fail\n");
        exit(1);
    }
    int cap = 128;
    *entries = calloc(cap, sizeof(Entry));
    *entry_count = 0;
    uint8_t sig[4];
    int idx = 0;
    while (fread(sig, 1, 4, f) == 4) {
        if (memcmp(sig, "PK\x03\x04", 4) != 0) break;
        uint8_t hdr[26];
        fread(hdr, 1, 26, f);
        int method = *(uint16_t*)(hdr+4);
        uint16_t name_len = *(uint16_t*)(hdr+22);
        uint16_t extra_len = *(uint16_t*)(hdr+24);
        char name[MAX_PATH];
        fread(name, 1, name_len, f); name[name_len] = 0;
        fseek(f, extra_len, SEEK_CUR);
        uint32_t crc32 = *(uint32_t*)(hdr+10);
        uint32_t csize = *(uint32_t*)(hdr+14);
        uint32_t usize = *(uint32_t*)(hdr+18);
        uint8_t *deflate_data = malloc(csize);
        if (!deflate_data) { fprintf(stderr, "[DEBUG][PARSE_SMALLS] malloc deflate_data fail\n"); exit(1); }
        fread(deflate_data, 1, csize, f);
        if (*entry_count == cap) {
            cap *= 2;
            *entries = realloc(*entries, cap * sizeof(Entry));
        }
        strcpy((*entries)[*entry_count].entry_name, name);
        (*entries)[*entry_count].deflate_data = deflate_data;
        (*entries)[*entry_count].dlen = csize;
        (*entries)[*entry_count].crc32 = crc32;
        (*entries)[*entry_count].orig_size = usize;
        (*entries)[*entry_count].use_zip64 = (usize >= 0xFFFFFFFF || csize >= 0xFFFFFFFF);
        (*entries)[*entry_count].method = method;
        (*entries)[*entry_count].is_dir = 0;
        if (DEBUG_ALL || DEBUG_PARSE_SMALLS) {
            printf("[DEBUG][PARSE_SMALLS] smalls.zip entry idx=%d, name=%s, csize=%u, usize=%u, crc32=%08x, method=%d\n", idx, name, csize, usize, crc32, method);
        }
        (*entry_count)++; idx++;
    }
    fclose(f);
    unlink(smalls_zip);
    if (DEBUG_ALL || DEBUG_PARSE_SMALLS) {
        printf("[DEBUG][PARSE_SMALLS] parse smalls.zip done, entry_count=%d\n", *entry_count);
    }
}

// 8. 解析大文件 .gz
void parse_gz_files(Entry **entries, int *entry_count, FileSplitInfo *split_info, PathInfo *path_info) {
    for (int i = 0; i < split_info->big_count; ++i) {
        char gz_file[MAX_PATH];
        snprintf(gz_file, sizeof(gz_file), "%s/%s.gz", path_info->abs_tmpdir, basename(split_info->bigfiles[i]));
        FILE *f = fopen(gz_file, "rb");
        if (!f) {
            fprintf(stderr, "[DEBUG][PARSE_GZ] fopen gz fail: %s\n", gz_file);
            exit(1);
        }
        uint8_t hdr[10];
        fread(hdr, 1, 10, f);
        int flg = hdr[3];
        if (flg & 4) { uint16_t xlen; fread(&xlen, 2, 1, f); fseek(f, xlen, SEEK_CUR); }
        if (flg & 8) while (fgetc(f) != 0);
        if (flg & 16) while (fgetc(f) != 0);
        if (flg & 2) fseek(f, 2, SEEK_CUR);
        long start = ftell(f);
        fseek(f, 0, SEEK_END);
        long end = ftell(f);
        long data_len = end - start - 8;
        if (data_len <= 0) {
            fprintf(stderr, "[DEBUG][PARSE_GZ] gz data_len<=0: %s\n", gz_file);
            fclose(f);
            exit(1);
        }
        Entry *new_entries = realloc(*entries, (*entry_count + 1) * sizeof(Entry));
        if (!new_entries) {
            fprintf(stderr, "[DEBUG][PARSE_GZ] realloc entries fail\n");
            fclose(f);
            exit(1);
        }
        *entries = new_entries;
        (*entries)[*entry_count].deflate_data = malloc(data_len);
        if (!(*entries)[*entry_count].deflate_data) {
            fprintf(stderr, "[DEBUG][PARSE_GZ] malloc gz deflate_data fail\n");
            fclose(f);
            exit(1);
        }
        fseek(f, start, SEEK_SET);
        fread((*entries)[*entry_count].deflate_data, 1, data_len, f);
        fseek(f, -8, SEEK_END);
        fread(&(*entries)[*entry_count].crc32, 4, 1, f);
        uint32_t gz_isize;
        fread(&gz_isize, 4, 1, f);
        struct stat st;
        if (stat(split_info->bigfiles[i], &st) != 0) {
            fprintf(stderr, "[DEBUG][PARSE_GZ] stat failed: %s\n", split_info->bigfiles[i]);
            fclose(f);
            exit(1);
        }
        (*entries)[*entry_count].orig_size = (uint64_t)st.st_size;
        (*entries)[*entry_count].dlen = data_len;
        strcpy((*entries)[*entry_count].entry_name, split_info->bigentry[i]);
        (*entries)[*entry_count].use_zip64 = ((*entries)[*entry_count].orig_size >= 0xFFFFFFFF || data_len >= 0xFFFFFFFF);
        (*entries)[*entry_count].method = 8;
        (*entries)[*entry_count].is_dir = 0;
        if (DEBUG_ALL || DEBUG_PARSE_GZ) {
            printf("[DEBUG][PARSE_GZ] gz entry[%d]: name=%s, dlen=%ld, orig_size=%llu\n", *entry_count, split_info->bigentry[i], data_len, (unsigned long long)(*entries)[*entry_count].orig_size);
        }
        (*entry_count)++;
        fclose(f);
        unlink(gz_file);
    }
    if (DEBUG_ALL || DEBUG_PARSE_GZ) {
        printf("[DEBUG][PARSE_GZ] parse gz done, entry_count=%d\n", *entry_count);
    }
}

// 新增：补充空文件Entry的函数实现
void append_empty_entries(Entry **entries, int *entry_count, FileSplitInfo *split_info) {
    for (int i = 0; i < split_info->empty_count; ++i) {
        Entry *new_entries = realloc(*entries, (*entry_count + 1) * sizeof(Entry));
        if (!new_entries) {
            fprintf(stderr, "[DEBUG][EMPTY] realloc entries fail\n");
            exit(1);
        }
        *entries = new_entries;
        strcpy((*entries)[*entry_count].entry_name, split_info->emptyentry[i]);
        (*entries)[*entry_count].deflate_data = NULL;
        (*entries)[*entry_count].dlen = 0;
        (*entries)[*entry_count].crc32 = 0;
        (*entries)[*entry_count].orig_size = 0;
        (*entries)[*entry_count].use_zip64 = 0;
        (*entries)[*entry_count].method = 0;
        (*entries)[*entry_count].is_dir = 0;
        (*entry_count)++;
    }
}

// 9. 拼装 zip64 包
void assemble_zip64(Entry *entries, int entry_count, PathInfo *path_info) {
    char tmp_zip[MAX_PATH];
    snprintf(tmp_zip, sizeof(tmp_zip), "%s/final.zip", path_info->abs_tmpdir);
    if (DEBUG_ALL || DEBUG_ZIP64) {
        printf("[DEBUG][ZIP64] 尝试创建输出zip文件: %s\n", tmp_zip);
    }
    FILE *zf = fopen(tmp_zip, "wb");
    if (!zf) {
        fprintf(stderr, "[DEBUG][ZIP64] fopen output zip fail: %s\n", tmp_zip);
        exit(1);
    }
    uint64_t offset = 0;
    for (int i = 0; i < entry_count; ++i) {
        entries[i].offset = offset;
        size_t name_len = strlen(entries[i].entry_name);
        if (DEBUG_ALL || DEBUG_ZIP64) {
            printf("[DEBUG][ZIP64] 处理Entry[%d]: name=%s, is_dir=%d, orig_size=%llu, dlen=%llu, method=%d, crc32=0x%08x, offset=%llu\n",
                i, entries[i].entry_name, entries[i].is_dir, (unsigned long long)entries[i].orig_size,
                (unsigned long long)entries[i].dlen, entries[i].method, entries[i].crc32, (unsigned long long)offset);
        }
        if (entries[i].is_dir) {
            // 目录local header
            uint8_t local_hdr[30] = {0};
            *(uint32_t*)local_hdr = 0x04034b50;
            *(uint16_t*)(local_hdr+4) = 20;
            *(uint16_t*)(local_hdr+6) = 0x800;
            *(uint16_t*)(local_hdr+8) = 0; // store
            *(uint16_t*)(local_hdr+26) = name_len;
            fwrite(local_hdr, 1, 30, zf);
            fwrite(entries[i].entry_name, 1, name_len, zf);
            if (DEBUG_ALL || DEBUG_ZIP64) {
                printf("[DEBUG][ZIP64] 写入目录local header: name=%s, header_size=%zu\n", entries[i].entry_name, 30 + name_len);
            }
            offset += 30 + name_len;
        } else if (entries[i].orig_size == 0) {
            // 空文件local header
            uint8_t local_hdr[30] = {0};
            *(uint32_t*)local_hdr = 0x04034b50;
            *(uint16_t*)(local_hdr+4) = 20;
            *(uint16_t*)(local_hdr+6) = 0x800;
            *(uint16_t*)(local_hdr+8) = 0; // store
            *(uint16_t*)(local_hdr+26) = name_len;
            fwrite(local_hdr, 1, 30, zf);
            fwrite(entries[i].entry_name, 1, name_len, zf);
            if (DEBUG_ALL || DEBUG_ZIP64) {
                printf("[DEBUG][ZIP64] 写入空文件local header: name=%s, header_size=%zu\n", entries[i].entry_name, 30 + name_len);
            }
            offset += 30 + name_len;
        } else {
            // 普通文件local header
            uint8_t local_hdr[30] = {0};
            int use_zip64 = (entries[i].orig_size >= 0xFFFFFFFF || entries[i].dlen >= 0xFFFFFFFF);
            *(uint32_t*)local_hdr = 0x04034b50;
            *(uint16_t*)(local_hdr+4) = use_zip64 ? 45 : 20;
            *(uint16_t*)(local_hdr+6) = 0x800;
            *(uint16_t*)(local_hdr+8) = entries[i].method;
            *(uint32_t*)(local_hdr+14) = entries[i].crc32;
            *(uint32_t*)(local_hdr+18) = use_zip64 ? 0xFFFFFFFF : (uint32_t)entries[i].dlen;
            *(uint32_t*)(local_hdr+22) = use_zip64 ? 0xFFFFFFFF : (uint32_t)entries[i].orig_size;
            *(uint16_t*)(local_hdr+26) = name_len;
            *(uint16_t*)(local_hdr+28) = use_zip64 ? 20 : 0;
            fwrite(local_hdr, 1, 30, zf);
            fwrite(entries[i].entry_name, 1, name_len, zf);
            if (use_zip64) {
                uint8_t extra[20];
                *(uint16_t*)extra = 0x0001;
                *(uint16_t*)(extra+2) = 16;
                *(uint64_t*)(extra+4) = entries[i].orig_size;
                *(uint64_t*)(extra+12) = entries[i].dlen;
                fwrite(extra, 1, 20, zf);
                if (DEBUG_ALL || DEBUG_ZIP64) {
                    printf("[DEBUG][ZIP64] 写入zip64扩展字段: name=%s, extra_size=20\n", entries[i].entry_name);
                }
            }
            fwrite(entries[i].deflate_data, 1, entries[i].dlen, zf);
            if (DEBUG_ALL || DEBUG_ZIP64) {
                printf("[DEBUG][ZIP64] 写入普通文件local header和数据: name=%s, header_size=%zu, data_size=%llu, use_zip64=%d\n",
                    entries[i].entry_name, 30 + name_len + (use_zip64 ? 20 : 0), (unsigned long long)entries[i].dlen, use_zip64);
            }
            offset += 30 + name_len + (use_zip64 ? 20 : 0) + entries[i].dlen;
        }
    }
    if (DEBUG_ALL || DEBUG_ZIP64) printf("[DEBUG][ZIP64] write local headers done, offset=%llu\n", (unsigned long long)offset);

    // central directory
    uint64_t cd_start = offset;
    uint64_t cd_size = 0;
    for (int i = 0; i < entry_count; ++i) {
        size_t name_len = strlen(entries[i].entry_name);
        uint8_t cd_hdr[46] = {0};
        int use_zip64 = (entries[i].orig_size >= 0xFFFFFFFF || entries[i].dlen >= 0xFFFFFFFF || entries[i].offset >= 0xFFFFFFFF);
        *(uint32_t*)cd_hdr = 0x02014b50;
        *(uint16_t*)(cd_hdr+4) = 0x2d;
        *(uint16_t*)(cd_hdr+6) = use_zip64 ? 45 : 20;
        *(uint16_t*)(cd_hdr+8) = 0x800;
        *(uint16_t*)(cd_hdr+10) = entries[i].method;
        *(uint32_t*)(cd_hdr+16) = entries[i].crc32;
        *(uint32_t*)(cd_hdr+20) = use_zip64 ? 0xFFFFFFFF : (uint32_t)entries[i].dlen;
        *(uint32_t*)(cd_hdr+24) = use_zip64 ? 0xFFFFFFFF : (uint32_t)entries[i].orig_size;
        *(uint16_t*)(cd_hdr+28) = name_len;
        *(uint16_t*)(cd_hdr+30) = use_zip64 ? 28 : 0;
        // 目录标志
        if (entries[i].is_dir) {
            *(uint32_t*)(cd_hdr+38) = 0x10;
        } else {
            *(uint32_t*)(cd_hdr+38) = 0x20;
        }
        *(uint32_t*)(cd_hdr+42) = use_zip64 ? 0xFFFFFFFF : (uint32_t)entries[i].offset;
        fwrite(cd_hdr, 1, 46, zf);
        fwrite(entries[i].entry_name, 1, name_len, zf);
        if (use_zip64) {
            uint8_t cd_extra[28];
            *(uint16_t*)cd_extra = 0x0001;
            *(uint16_t*)(cd_extra+2) = 24;
            *(uint64_t*)(cd_extra+4) = entries[i].orig_size;
            *(uint64_t*)(cd_extra+12) = entries[i].dlen;
            *(uint64_t*)(cd_extra+20) = entries[i].offset;
            fwrite(cd_extra, 1, 28, zf);
            if (DEBUG_ALL || DEBUG_ZIP64) {
                printf("[DEBUG][ZIP64] central dir写入zip64扩展字段: name=%s, extra_size=28\n", entries[i].entry_name);
            }
        }
        if (DEBUG_ALL || DEBUG_ZIP64) {
            printf("[DEBUG][ZIP64] central dir写入Entry[%d]: name=%s, use_zip64=%d, cd_hdr_size=%zu\n",
                i, entries[i].entry_name, use_zip64, 46 + name_len + (use_zip64 ? 28 : 0));
        }
        cd_size += 46 + name_len + (use_zip64 ? 28 : 0);
    }
    if (DEBUG_ALL || DEBUG_ZIP64) printf("[DEBUG][ZIP64] write central dir done, cd_start=%llu, cd_size=%llu\n", (unsigned long long)cd_start, (unsigned long long)cd_size);

    uint64_t cd_end = cd_start + cd_size;
    int need_zip64 = 0;
    for (int i = 0; i < entry_count; ++i) {
        if (entries[i].orig_size >= 0xFFFFFFFF || entries[i].dlen >= 0xFFFFFFFF || entries[i].offset >= 0xFFFFFFFF) {
            need_zip64 = 1;
            break;
        }
    }
    // 新增判断 central directory size/offset/entry count
    if (cd_size >= 0xFFFFFFFF || cd_start >= 0xFFFFFFFF || entry_count >= 0xFFFF) {
        need_zip64 = 1;
    }
    if (DEBUG_ALL || DEBUG_ZIP64) {
        printf("[DEBUG][ZIP64] 是否需要zip64结尾结构: %d\n", need_zip64);
    }
    if (need_zip64) {
        uint8_t zip64_eocd[56] = {0};
        *(uint32_t*)zip64_eocd = 0x06064b50;
        *(uint64_t*)(zip64_eocd+4) = 56-12;
        *(uint16_t*)(zip64_eocd+12) = 45;
        *(uint16_t*)(zip64_eocd+14) = 45;
        *(uint64_t*)(zip64_eocd+24) = entry_count;
        *(uint64_t*)(zip64_eocd+32) = entry_count;
        *(uint64_t*)(zip64_eocd+40) = cd_size;
        *(uint64_t*)(zip64_eocd+48) = cd_start;
        fwrite(zip64_eocd, 1, 56, zf);
        if (DEBUG_ALL || DEBUG_ZIP64) {
            printf("[DEBUG][ZIP64] 写入zip64 end of central directory, size=56\n");
        }
        uint8_t zip64_eocd_locator[20] = {0};
        *(uint32_t*)zip64_eocd_locator = 0x07064b50;
        *(uint64_t*)(zip64_eocd_locator+8) = cd_end;
        *(uint32_t*)(zip64_eocd_locator+16) = 1;
        fwrite(zip64_eocd_locator, 1, 20, zf);
        if (DEBUG_ALL || DEBUG_ZIP64) {
            printf("[DEBUG][ZIP64] 写入zip64 end of central directory locator, size=20\n");
        }
    }
    uint8_t end_hdr[22] = {0};
    *(uint32_t*)end_hdr = 0x06054b50;
    *(uint16_t*)(end_hdr+8) = need_zip64 ? 0xFFFF : entry_count;
    *(uint16_t*)(end_hdr+10) = need_zip64 ? 0xFFFF : entry_count;
    *(uint32_t*)(end_hdr+12) = need_zip64 ? 0xFFFFFFFF : (uint32_t)cd_size;
    *(uint32_t*)(end_hdr+16) = need_zip64 ? 0xFFFFFFFF : (uint32_t)cd_start;
    fwrite(end_hdr, 1, 22, zf);
    if (DEBUG_ALL || DEBUG_ZIP64) {
        printf("[DEBUG][ZIP64] 写入end of central directory, size=22\n");
        printf("[DEBUG][ZIP64] assemble_zip64 完成，最终zip文件: %s\n", tmp_zip);
    }
    fclose(zf);
}

// 10. 移动最终 zip、清理临时目录
void finalize_and_cleanup(PathInfo *path_info) {
    char tmp_zip[MAX_PATH];
    snprintf(tmp_zip, sizeof(tmp_zip), "%s/final.zip", path_info->abs_tmpdir);
    if (rename(tmp_zip, path_info->final_zip_path) != 0) {
        fprintf(stderr, "[DEBUG] rename zip fail: %s -> %s\n", tmp_zip, path_info->final_zip_path);
        exit(1);
    }
    DIR *d = opendir(path_info->abs_tmpdir);
    if (d) {
        struct dirent *dp;
        char del_path[MAX_PATH*2];
        while ((dp = readdir(d)) != NULL) {
            if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue;
            snprintf(del_path, sizeof(del_path), "%s/%s", path_info->abs_tmpdir, dp->d_name);
            unlink(del_path);
        }
        closedir(d);
        rmdir(path_info->abs_tmpdir);
    }
    printf("[INFO] 完成: %s\n", path_info->final_zip_path);
}

// 新增：参数解析功能块
int parse_args(int argc, char *argv[], char **input_list_file, char **output_zip, char **parent_dir) {
    *input_list_file = NULL;
    *output_zip = NULL;
    *parent_dir = NULL;
    for (int i = 1; i < argc; ++i) {
        if (strncmp(argv[i], "-i@", 3) == 0) {
            *input_list_file = argv[i] + 3;
            if (DEBUG_ALL || DEBUG_ARGS) printf("[DEBUG][ARGS] 解析到输入文件列表: %s\n", *input_list_file);
        } else if (strcmp(argv[i], "-f") == 0 && i+1 < argc) {
            *output_zip = argv[++i];
            if (DEBUG_ALL || DEBUG_ARGS) printf("[DEBUG][ARGS] 解析到输出zip路径: %s\n", *output_zip);
        } else if (strcmp(argv[i], "-d") == 0 && i+1 < argc) {
            *parent_dir = argv[++i];
            if (DEBUG_ALL || DEBUG_ARGS) printf("[DEBUG][ARGS] 解析到原始数据目录: %s\n", *parent_dir);
        }
    }
    if (!*input_list_file || !*output_zip || !*parent_dir) {
        fprintf(stderr, "用法: %s -i@file_list.txt -f output.zip -d parent_dir\n", argv[0]);
        return 1;
    }
    if (DEBUG_ALL || DEBUG_ARGS) printf("[DEBUG][ARGS] 参数解析完成: -i@%s -f %s -d %s\n", *input_list_file, *output_zip, *parent_dir);
    return 0;
}

// 新增：读取文件列表功能块
void load_file_list(const char *input_list_file, const char *parent_dir, FlatFileEntry **flat_entries, size_t *flat_entry_count, size_t *flat_entry_cap) {
    if (DEBUG_ALL || DEBUG_LOAD) printf("[DEBUG][LOAD] 开始读取文件列表: %s, 基准目录: %s\n", input_list_file, parent_dir);
    FILE *fl = fopen(input_list_file, "r");
    if (!fl) {
        fprintf(stderr, "无法打开文件列表: %s\n", input_list_file);
        exit(1);
    }
    // 获取parent_dir最后一级目录名
    char parent_dir_copy[MAX_PATH];
    strncpy(parent_dir_copy, parent_dir, MAX_PATH-1);
    parent_dir_copy[MAX_PATH-1] = '\0';
    char *parent_last = basename(parent_dir_copy);
    char line[MAX_PATH];
    size_t line_num = 0;
    while (fgets(line, sizeof(line), fl)) {
        size_t len = strlen(line);
        if (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r')) line[len-1] = 0;
        // 去除前后双引号
        char *rel = line;
        if (rel[0] == '"') {
            rel++;
            char *endq = strchr(rel, '"');
            if (endq) *endq = 0;
        }
        char *clean_rel = rel;
        // parent_last 前缀跳过逻辑
        char *abs_entry = clean_rel;
        size_t parent_last_len = strlen(parent_last);
        if (strncmp(clean_rel, parent_last, parent_last_len) == 0 && clean_rel[parent_last_len] == '/') {
            abs_entry = clean_rel + parent_last_len + 1;
        }
        // 这段代码的作用是：根据文件列表中的相对路径，拼接出该文件在实际磁盘上的绝对路径（abs_path），
        // 然后通过stat函数检查该路径是否存在。如果不存在，则跳过该项（continue）。
        // 如果存在，则判断该路径是目录还是文件（is_dir），为后续加入flat_entries做准备。
        char abs_path[MAX_PATH];
        snprintf(abs_path, sizeof(abs_path), "%s/%s", parent_dir, abs_entry); // 拼接绝对路径
        struct stat st;
        if (stat(abs_path, &st) != 0) { // 检查文件或目录是否存在
            if (DEBUG_ALL || DEBUG_LOAD) printf("[DEBUG][LOAD] 跳过不存在: %s\n", abs_path);
            continue;
        }
        int is_dir = S_ISDIR(st.st_mode); // 判断是否为目录
        add_flat_entry(flat_entries, flat_entry_count, flat_entry_cap, abs_path, clean_rel, st.st_size, is_dir);
        if (DEBUG_ALL || DEBUG_LOAD) printf("[DEBUG][LOAD] 加入文件: %s (entry: %s, size: %llu, is_dir: %d)\n", abs_path, clean_rel, (unsigned long long)st.st_size, is_dir);
        line_num++;
    }
    fclose(fl);
    if (DEBUG_ALL || DEBUG_LOAD) printf("[DEBUG][LOAD] 文件列表读取完成，共%zu项\n", line_num);
}

int main(int argc, char *argv[]) {
    char *input_list_file = NULL;
    char *output_zip = NULL;
    char *parent_dir = NULL;

    struct timespec ts_start, ts_end;
    struct timespec ts_total_start, ts_total_end;
    double elapsed;
    double total_elapsed;

    // 统计总耗时开始
    clock_gettime(CLOCK_MONOTONIC, &ts_total_start);

    // 解析参数
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    if (parse_args(argc, argv, &input_list_file, &output_zip, &parent_dir)) {
        return 1;
    }
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] parse_args: %.3f 秒\n", elapsed);

    // 路径准备
    PathInfo path_info;
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    prepare_paths_and_tmpdir(output_zip, parent_dir, &path_info);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] prepare_paths_and_tmpdir: %.3f 秒\n", elapsed);

    // 读取文件列表
    FlatFileEntry *flat_entries = NULL;
    size_t flat_entry_count = 0, flat_entry_cap = 0;
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    load_file_list(input_list_file, parent_dir, &flat_entries, &flat_entry_count, &flat_entry_cap);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] load_file_list: %.3f 秒\n", elapsed);

    // 文件分组
    FileSplitInfo split_info;
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    split_files(flat_entries, flat_entry_count, &split_info);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] split_files: %.3f 秒\n", elapsed);

    // 压缩大文件
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    compress_big_files(&split_info, &path_info);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] compress_big_files: %.3f 秒\n", elapsed);

    // 生成小文件列表
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    generate_smallfile_list(&split_info, &path_info);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] generate_smallfile_list: %.3f 秒\n", elapsed);

    // 压缩小文件
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    compress_small_files(&path_info);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] compress_small_files: %.3f 秒\n", elapsed);

    // 解析小文件zip
    Entry *entries = NULL;
    int entry_count = 0;
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    parse_smalls_zip(&entries, &entry_count, &path_info);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] parse_smalls_zip: %.3f 秒\n", elapsed);

    // 解析大文件gz
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    parse_gz_files(&entries, &entry_count, &split_info, &path_info);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] parse_gz_files: %.3f 秒\n", elapsed);

    // 调用补充空文件Entry的函数
    append_empty_entries(&entries, &entry_count, &split_info);

    // 组装zip64
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    assemble_zip64(entries, entry_count, &path_info);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] assemble_zip64: %.3f 秒\n", elapsed);

    // 清理
    clock_gettime(CLOCK_MONOTONIC, &ts_start);
    finalize_and_cleanup(&path_info);
    clock_gettime(CLOCK_MONOTONIC, &ts_end);
    elapsed = (ts_end.tv_sec - ts_start.tv_sec) + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
    if (DEBUG_TIME)
    printf("[TIME] finalize_and_cleanup: %.3f 秒\n", elapsed);


    if (DEBUG_TIME) {
	// 统计总耗时结束
	clock_gettime(CLOCK_MONOTONIC, &ts_total_end);
	total_elapsed = (ts_total_end.tv_sec - ts_total_start.tv_sec) + (ts_total_end.tv_nsec - ts_total_start.tv_nsec) / 1e9;
	printf("[TIME] 总耗时: %.3f 秒\n", total_elapsed);
    }
    free(flat_entries);
    free(entries);
    return 0;
}
