import json
import os
import shutil
import logging
import time
import sys
import re
import zipfile
import tkinter as tk
import subprocess
from tkinter import messagebox
from datetime import datetime
from pathlib import Path
import requests
from concurrent.futures import ThreadPoolExecutor
from tqdm import tqdm
import getpass

try:
    import msvcrt
    def get_key():
        return msvcrt.getch().decode('utf-8').lower()
except ImportError:
    import tty
    import termios
    def get_key():
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            return sys.stdin.read(1).lower()
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

GITEE_TOKEN = "10c5d89326d47f94585d346dd7e562f3"
# 没啥用，偷了也不会发生些啥

INTERNAL_VERSION = "7" 

# 配置日志格式
logging.basicConfig(
    level=logging.INFO,
    format='%(levelname)s: %(message)s',
    handlers=[logging.StreamHandler()]
)
logger = logging.getLogger(__name__)

# 路径判定
if getattr(sys, 'frozen', False):
    WORK_DIR = Path(sys.executable).resolve().parent
    EXE_PATH = Path(sys.executable).resolve()
    IS_EXE = True
else:
    WORK_DIR = Path(__file__).resolve().parent
    EXE_PATH = Path(__file__).resolve()
    IS_EXE = False

CONFIG_URL = "https://paratranz.cn/api/projects/16715/files/2813017/translation"
ASSET_URL = "https://cdn.modrinth.com/data/YzCQisiC/versions/wrVEHVV7/nlpbuilderasset2.zip"
LOCAL_CONFIG = WORK_DIR / "config.json"
MOD_CACHE_DIR = WORK_DIR / "file" / "mod"
MOD_CACHE_INFO = MOD_CACHE_DIR / "cache_info.txt"
HAS_ERROR = False 

def version_to_tuple(v_str):
    """版本号转元组对比逻辑"""
    try:
        return tuple(int(x) for x in re.findall(r'\d+', str(v_str)))
    except:
        return (0,)

def show_init_warning():
    """运行前的环境提醒"""
    if not (WORK_DIR / "file").exists() or not LOCAL_CONFIG.exists():
        root = tk.Tk()
        root.withdraw()
        msg = "脚本将在当前目录输出所有临时文件和最终资源包，注意存放位置。\n\n是否继续运行？"
        result = messagebox.askokcancel("环境提醒", msg)
        root.destroy()
        if not result:
            sys.exit(0)


def transform_config(raw_input):
    """处理远程配置，支持 assets 层级"""
    if isinstance(raw_input, dict):
        return raw_input

    config = {
        "config_version": "",
        "script_version": INTERNAL_VERSION, 
        "minecraft_path": "",
        "assets": {
            "config_url": CONFIG_URL,
            "asset_url": ASSET_URL,
            "latest_version": "0.0.0",
            "update_url": ""
        },
        "remote_files": [],
        "versions": []
    }
    files_map = {}
    for item in raw_input:
        key = item.get("key", "")
        val = item.get("translation") or item.get("original", "")
        
        if key.startswith("assets->"):
            sub_key = key.replace("assets->", "")
            if sub_key in config["assets"]:
                config["assets"][sub_key] = str(val).strip()
        elif "remote_files" in key:
            match = re.match(r'remote_files->(\d+)->(\w+)', key)
            if match:
                idx, field = match.groups()
                if idx not in files_map: files_map[idx] = {}
                files_map[idx][field] = str(val).strip()
        elif "versions" in key:
            config["versions"].append(str(val).replace("1.21", "1.15+"))
        elif key == "config_version":
            config["config_version"] = str(val).strip()
        elif key == "minecraft_path":
            config["minecraft_path"] = str(val)

    for i in sorted(files_map.keys(), key=int):
        config["remote_files"].append(files_map[i])
    return config

def load_config():
    """核心逻辑：先检查更新，再处理本地存储，返回 (config, config_updated)"""
    existing_mc_path = ""
    local_config_version = ""
    if LOCAL_CONFIG.exists():
        try:
            with open(LOCAL_CONFIG, 'r', encoding='utf-8-sig') as f:
                local_config = json.load(f)
                existing_mc_path = local_config.get("minecraft_path", "")
                local_config_version = local_config.get("config_version", "")
        except: pass

    logger.info("正在获取远程配置...")
    try:
        res = requests.get(CONFIG_URL, timeout=10)
        if res.status_code == 200:
            config_data = transform_config(res.json())
            remote_config_version = config_data.get("config_version", "")
            
            local_ver_tuple = version_to_tuple(local_config_version)
            remote_ver_tuple = version_to_tuple(remote_config_version)
            
            if local_ver_tuple > remote_ver_tuple:
                logger.info(f"[!] 本地配置版本较新 (本地:{local_config_version}, 云端:{remote_config_version})")
                with open(LOCAL_CONFIG, 'r', encoding='utf-8-sig') as f:
                    local_config = json.load(f)
                local_config["config_version"] = f"{local_config_version},{remote_config_version}"
                local_config["local_is_newer"] = True
                local_config["script_version"] = INTERNAL_VERSION
                return local_config, False
            
            config_updated = remote_ver_tuple > local_ver_tuple
            config_data["minecraft_path"] = existing_mc_path
            config_data["script_version"] = INTERNAL_VERSION
            with open(LOCAL_CONFIG, 'w', encoding='utf-8') as f:
                json.dump(config_data, f, ensure_ascii=False, indent=2)
            if config_updated:
                logger.info("[+] 配置版本已更新，将自动更新 mod 缓存")
            logger.info("[+] 配置加载完成")
            return config_data, config_updated
    except Exception as e:
        logger.warning(f"获取远程配置失败: {e}")

    if LOCAL_CONFIG.exists():
        with open(LOCAL_CONFIG, 'r', encoding='utf-8-sig') as f: return json.load(f), False
    return None, False

def upload_to_gitee(log_content, version):
    """同步日志到 Gitee 代码片段"""
    # 如果没填 Token 就跳过，不影响本地构建
    if not GITEE_TOKEN or "填入" in GITEE_TOKEN:
        return None
    
    builder = getpass.getuser() # 自动获取 Windows 用户名
    timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    title = f"[NLP构建日志] {version} - {builder} - {timestamp}"
    
    url = "https://gitee.com/api/v5/gists"
    payload = {
        "access_token": GITEE_TOKEN,
        "files": {f"build_{int(time.time())}.md": {"content": log_content}},
        "description": title,
        "public": "false" # 设为公开，方便你刷新页面直接看别人的
    }
    
    try:
        res = requests.post(url, json=payload, timeout=10)
        if res.status_code == 201:
            gist_url = res.json().get("html_url")
            logger.info(f"[+] 云端日志同步成功: {gist_url}")
            return gist_url
    except:
        logger.warning("[-] 云端同步失败，但不影响本地构建")
    return None

def ensure_assets(config):  # 1. 增加 config 参数
    """资源补全 (从 config 获取下载地址)"""
    asset_dir = WORK_DIR / "file"
    asset_zip = WORK_DIR / "nlpbuilderasset.zip"
    if asset_dir.exists(): return
    
    # 2. 从配置中提取 asset_url，如果提取不到则使用全局变量作为保底
    target_url = config.get("assets", {}).get("asset_url", ASSET_URL)
    
    logger.info(f"检测到缺失核心资源，正在从远程同步...")
    try:
        res = requests.get(target_url, stream=True, timeout=30) # 3. 使用 target_url
        if res.status_code == 200:
            total_size = int(res.headers.get('content-length', 0))
            block_size = 1024
            with open(asset_zip, "wb") as f, tqdm(
                desc="下载核心资源包",
                total=total_size,
                unit='iB',
                unit_scale=True,
                unit_divisor=1024,
            ) as bar:
                for data in res.iter_content(block_size):
                    size = f.write(data)
                    bar.update(size)
            # 以下是原有的解压逻辑
            temp = WORK_DIR / "_temp_extract"
            if temp.exists(): shutil.rmtree(temp)
            with zipfile.ZipFile(asset_zip, 'r') as z: z.extractall(temp)
            temp.rename(asset_dir)
            asset_zip.unlink()
            logger.info("[+] 核心资源补全成功")
    except Exception as e:
        logger.warning(f"资源同步失败: {e}")
        sys.exit(1)

def download_and_save_mod(file_info, force=False):
    target_file = MOD_CACHE_DIR / f"{file_info['name']}.json"
    if not force and target_file.exists(): return 
    try:
        res = requests.get(file_info['url'], timeout=15)
        if res.status_code == 200:
            MOD_CACHE_DIR.mkdir(parents=True, exist_ok=True)
            with open(target_file, 'w', encoding='utf-8') as f:
                json.dump(res.json(), f, ensure_ascii=False, indent=2)
    except: pass

def sync_all_mods(config, force=False):
    mods = [f for f in config.get('remote_files', []) if f.get('type') == 'mod']
    from concurrent.futures import as_completed
    with ThreadPoolExecutor(max_workers=5) as ex:
        futures = [ex.submit(download_and_save_mod, m, force) for m in mods]
        for _ in tqdm(as_completed(futures), total=len(futures), desc='进度', bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt}'):
            pass
    MOD_CACHE_DIR.mkdir(parents=True, exist_ok=True)
    cache_timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    config_version = config.get('config_version', 'unknown')
    with open(MOD_CACHE_INFO, 'w', encoding='utf-8') as f:
        f.write(f"Cache Time: {cache_timestamp}\n")
        f.write(f"Config Version: {config_version}\n")

def run_internal_compatible(source_content):
    diff_path = WORK_DIR / "id" / "diff.json"
    if not diff_path.exists(): return source_content
    try:
        with open(diff_path, 'r', encoding='utf-8-sig') as f: diff_data = json.load(f)
        relations = [] 
        for transition in diff_data.values():
            for new_key, info in transition.items():
                old_key = info.get('old_key')
                if not old_key: continue
                found = [i for i, s in enumerate(relations) if old_key in s or new_key in s]
                if not found: relations.append({old_key, new_key})
                else:
                    new_set = {old_key, new_key}
                    for i in sorted(found, reverse=True): new_set.update(relations.pop(i))
                    relations.append(new_set)
        compat = source_content.copy()
        for group in relations:
            match_key = next((k for k in group if k in source_content), None)
            if match_key:
                val = source_content[match_key]
                for k in group:
                    if k not in compat: compat[k] = val
        return compat
    except: return source_content

def is_extra_content(file_info):
    return str(file_info.get('is_extra', 'false')).lower() == 'true'

def download_file(file_info):
    """下载单个文件 (增加进度条)"""
    logger.info(f"正在下载 {file_info['name']}...")
    try:
        res = requests.get(file_info['url'], stream=True, timeout=15)  # 启用流式传输
        if res.status_code == 200:
            # 获取文件总大小
            total_size = int(res.headers.get('content-length', 0))
            data_chunks = []
            block_size = 1024
            with tqdm(
                desc=file_info['name'][:20].ljust(20),  # 截取名称并用进度条描述
                total=total_size,
                unit='iB',
                unit_scale=True,
                unit_divisor=1024,
                leave=False,  # 下载完成后清除此进度条
            ) as bar:
                for chunk in res.iter_content(block_size):
                    if chunk:
                        data_chunks.append(chunk)
                        bar.update(len(chunk))
            # 拼接数据并解析为JSON
            file_data = b''.join(data_chunks)
            return str(file_info['id']), json.loads(file_data.decode('utf-8'))
    except Exception as e:
        logger.error(f"下载 {file_info['name']} 时出错: {e}")
    global HAS_ERROR
    HAS_ERROR = True
    return str(file_info['id']), None

def build_resource_pack(version, file_data_map, config, mode_name, selected_files, release_mode=False, include_mods=True):
    display_ver = version.replace("1.21", "1.15+")
    pack_name = f"nlp for {display_ver}"
    pack_dir = WORK_DIR / pack_name
    if pack_dir.exists(): shutil.rmtree(pack_dir)
    pack_dir.mkdir(parents=True, exist_ok=True)
    
    rs_source = WORK_DIR / "file" / "rs"
    if rs_source.exists():
        for item in rs_source.iterdir():
            if item.name == "pack.mcmeta":
                continue
            target = pack_dir / item.name
            if item.is_dir():
                shutil.copytree(item, target, dirs_exist_ok=True)
            else:
                target.parent.mkdir(parents=True, exist_ok=True)
                shutil.copy2(item, target)
    
    mcmeta_source = WORK_DIR / "file" / f"{version}.mcmeta"
    if mcmeta_source.exists():
        shutil.copy2(mcmeta_source, pack_dir / "pack.mcmeta")
    else:
        logger.warning(f"警告：未找到版本 {version} 对应的 mcmeta 文件，使用默认配置")
    
    if include_mods:
        for mod_f in [f for f in config.get('remote_files', []) if f.get('type') == 'mod']:
            local_json = MOD_CACHE_DIR / f"{mod_f['name']}.json"
            if local_json.exists():
                target = pack_dir / mod_f['path']
                target.parent.mkdir(parents=True, exist_ok=True)
                try:
                    with open(local_json, 'r', encoding='utf-8-sig') as f:
                        raw_data = json.load(f)
                    mod_data = {}
                    for item in raw_data:
                        if isinstance(item, dict):
                            key = item.get('key', '')
                            trans = item.get('translation', '')
                            orig = item.get('original', '')
                            val = trans or orig
                            if release_mode and (not trans or trans == orig):
                                continue
                            if key:
                                mod_data[key] = val
                    with open(target, 'w', encoding='utf-8') as f:
                        json.dump(mod_data, f, ensure_ascii=False, indent=2)
                except:
                    shutil.copy2(local_json, target)
    
    # 【新增】检查是否勾选了minecraft，并复制sounds、texts、textures文件夹
    # 判断逻辑：检查selected_files中是否存在id为"2569365"的文件（根据代码，此为Minecraft本体文件）
    is_minecraft_selected = any(str(f.get('id')) == "2569365" for f in selected_files)
    if is_minecraft_selected:
        file_assets_dir = WORK_DIR / "file"
        target_assets_dir = pack_dir / "assets" / "minecraft"
        folders_to_copy = ["sounds", "texts", "textures"]
        for folder in folders_to_copy:
            source_folder = file_assets_dir / folder
            if source_folder.exists():
                target_folder = target_assets_dir / folder
                shutil.copytree(source_folder, target_folder, dirs_exist_ok=True)
                logger.info(f"✓ 已复制 {folder} 文件夹到 assets/minecraft")
            else:
                logger.warning(f"警告：源文件夹 {folder} 不存在，跳过复制。")

    processed = {}
    config_map = {str(f['id']): f for f in config['remote_files']}
    sorted_fids = sorted(file_data_map.keys(), key=lambda x: 1 if config_map.get(x, {}).get('type') == 'append' else 0)
    
    for fid in sorted_fids:
        raw_data, f_conf = file_data_map[fid], config_map[fid]
        path = f_conf['path']
        formatted_data = {}
        for item in raw_data:
            if isinstance(item, dict):
                key = item.get('key', '')
                trans = item.get('translation', '')
                orig = item.get('original', '')
                if release_mode and (not trans or trans == orig):
                    continue
                if key:
                    formatted_data[key] = trans or orig
        if fid == "2569365":
            formatted_data = run_internal_compatible(formatted_data)
        if f_conf['type'] == 'base': processed[path] = formatted_data.copy()
        elif f_conf['type'] == 'append':
            if path not in processed: processed[path] = {}
            processed[path].update(formatted_data)

    for rel_path, content in processed.items():
        if "minecraft/lang/zh_cn.json" in rel_path:
            patch_ver = version.replace("1.15+", "1.21")
            patch = WORK_DIR / "file" / f"for{patch_ver}.json"
            if patch.exists():
                with open(patch, 'r', encoding='utf-8-sig') as f: content.update(json.load(f))
        if release_mode:
            content = {k: v for k, v in content.items() if v}
        full_path = pack_dir / rel_path
        full_path.parent.mkdir(parents=True, exist_ok=True)
        with open(full_path, 'w', encoding='utf-8') as f:
            json.dump(content, f, ensure_ascii=False, indent=2)

    # 1. 构造日志内容
    # 注意：这里在开头加了 ```markdown，结尾加了 ```，确保在 Gitee 上直接以代码块显示
    log_content = f"Timestamp: {int(time.time())}\n"
    log_content += f"Build Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
    log_content += f"Build Mode: {mode_name}\n"
    log_content += f"Release Mode: {'Yes' if release_mode else 'No'}\n"
    log_content += f"Include Mods: {'Yes' if include_mods else 'No'}\n"
    log_content += f"Builder: {getpass.getuser()}\n"
    log_content += f"Version: {display_ver}\n"
    
    if MOD_CACHE_INFO.exists():
        with open(MOD_CACHE_INFO, 'r', encoding='utf-8') as f:
            cache_info = f.read().strip().split('\n')
        has_mods = any(f.get('type') == 'mod' for f in selected_files)
        mod_indicator = " (with_mods)" if has_mods else ""
        if release_mode:
            cache_time = cache_info[0].replace('Cache Time: ', '') if len(cache_info) > 0 else 'unknown'
            cache_config = cache_info[1].replace('Config Version: ', '') if len(cache_info) > 1 else 'unknown'
            log_content += f"Mod Cache: {cache_time} (config:{cache_config}){mod_indicator}\n"
        else:
            for line in cache_info:
                log_content += f"{line}\n"
    
    log_content += "\n"
    
    for f_info in selected_files:
        tag = "[extra]" if is_extra_content(f_info) else "[core]"
        log_content += f"-{tag}{f_info['id']} {f_info['name']}\n"
    
    log_content += "\nconfig：\n"
    # 使用 indent=2 保持 JSON 的缩进层级
    log_content += json.dumps(config, ensure_ascii=False, indent=2)
    log_content += f"\n```" # 结束代码块

    # 2. 写入本地文本 (虽然多了反引号，但 TXT 查看也非常整齐)
    with open(pack_dir / "build_info.txt", "w", encoding="utf-8") as f:
        f.write(log_content)

    logger.info(f"✓ {pack_name} 构建完成")
    return log_content, display_ver

def parse_multi_input(user_input, items, is_file_mode=False):
    selected = set()
    raw = user_input.lower().strip()
    if raw == '0': return 'back'
    if is_file_mode:
        if 'q' in raw: selected.update([i for i, f in enumerate(items, start=1) if not is_extra_content(f)])
        if 'w' in raw: selected.update([i for i, f in enumerate(items, start=1) if is_extra_content(f)])
    for n in re.findall(r'\d+', raw):
        if 0 < int(n) <= len(items): selected.add(int(n))
    return [items[idx-1] for idx in sorted(list(selected))]

def main():
    show_init_warning()
    config, config_updated = load_config() 
    if not config: return
    
    ensure_assets(config)
    if config_updated:
        print("\n检测到配置版本更新，正在自动更新 mod 缓存...")
        sync_all_mods(config, force=True)
        print("[+] Mod 缓存已自动更新。")
    else:
        sync_all_mods(config)
    # ... 后面代码不变 ...

    core_files = [f for f in config.get('remote_files', []) if f.get('type') != 'mod']
    versions = [v.replace("1.21", "1.15+") for v in config.get('versions', [])]
    release_mode = False
    include_mods = True

    while True:
        os.system('cls')
        config_ver = config.get('config_version', 'unknown')
        if config.get('local_is_newer'):
            ver_parts = config_ver.split(',') if ',' in config_ver else ['unknown', 'unknown']
            config_display = f"[config:本地:{ver_parts[0]},云端:{ver_parts[1]}]"
        else:
            config_display = f"[config:{config_ver}]"
        release_display = "开启" if release_mode else "关闭"
        release_tip = "（仅保留有修改的键）" if release_mode else "（保留有修改和未修改的键）"
        release_box = "■" if release_mode else "□"
        include_display = "开启" if include_mods else "关闭"
        include_box = "■" if include_mods else "□"
        print(f"\n=== Neko Language Pack Builder (v{INTERNAL_VERSION}) ===")
        print("原地构建出最新版的你老婆")
        print(config_display)
        print(f"\n<t> {release_box} 发行版模式 - {release_display}{release_tip}")
        print(f"<y> {include_box} 包含小mod - {include_display}")
        if config.get('local_is_newer'):
            print("\n1. 标准构建\n2. 全量构建\n3. 选择构建\n4. 更新本地mod缓存\n5. 更新云端文件")
        else:
            print("\n1. 标准构建\n2. 全量构建\n3. 选择构建\n4. 更新本地mod缓存")
        print("\n选择模式：", end='', flush=True)
        mode = get_key()
        print(mode)

        if mode.lower() == 't':
            release_mode = not release_mode
            continue
        
        if mode.lower() == 'y':
            include_mods = not include_mods
            continue
        
        if mode.lower() == 'r':
            script_path = str(EXE_PATH)
            if sys.stdout is None or not sys.stdout.isatty():
                subprocess.Popen(['start', 'cmd', '/k', 'python', script_path], shell=True)
            else:
                subprocess.Popen(['start', 'cmd', '/c', 'python', script_path], shell=True)
            sys.exit(0)
        
        if mode.lower() == 'q':
            sys.exit(0)
        
        if mode == "1":
            selected_files, v_list, mode_name = [f for f in core_files if not is_extra_content(f)], versions, "Standard Build"
            break
        elif mode == "2":
            selected_files, v_list, mode_name = core_files, versions, "Full Build"
            break
        elif mode == "3":
            file_selected = False
            while not file_selected:
                os.system('cls')
                print(f"\n=== Neko Language Pack Builder (v{INTERNAL_VERSION}) ===")
                print("原地构建出最新版的你老婆")
                config_ver = config.get('config_version', 'unknown')
                if config.get('local_is_newer'):
                    ver_parts = config_ver.split(',') if ',' in config_ver else ['unknown', 'unknown']
                    config_display = f"[config:本地:{ver_parts[0]},云端:{ver_parts[1]}]"
                else:
                    config_display = f"[config:{config_ver}]"
                print(config_display)
                print(f"\n<t> {release_box} 发行版模式 - {'开启' if release_mode else '关闭'}{'（仅保留有修改的键）' if release_mode else '（保留有修改和未修改的键）'}")
                print(f"<y> {include_box} 包含小mod - {'开启' if include_mods else '关闭'}")
                print("\n【选择构建 - 选择文件】")
                print("\n[0] 返回模式选择\n\n允许多选，空格分割\n\n[q] 全部本体内容\n[w] 全部附加内容\n")
                sorted_files = sorted(core_files, key=lambda x: (is_extra_content(x), core_files.index(x)))
                for i, f in enumerate(sorted_files, start=1):
                    tag = "[附加]" if is_extra_content(f) else "[本体]"
                    print(f"[{i}]{tag} {f['name']}")  
                f_in = input("\n输入文件编号: ")
                selected_files = parse_multi_input(f_in, sorted_files, is_file_mode=True)
                if selected_files == 'back': break
                if not selected_files: continue
                
                os.system('cls')
                print(f"\n=== Neko Language Pack Builder (v{INTERNAL_VERSION}) ===")
                print("原地构建出最新版的你老婆")
                print(config_display)
                print(f"\n<t> {release_box} 发行版模式 - {'开启' if release_mode else '关闭'}{'（仅保留有修改的键）' if release_mode else '（保留有修改和未修改的键）'}")
                print(f"<y> {include_box} 包含小mod - {'开启' if include_mods else '关闭'}")
                print("\n【选择构建 - 已选文件】")
                selected_ids = {str(f['id']) for f in selected_files}
                for f in sorted_files:
                    tag = "[附加]" if is_extra_content(f) else "[本体]"
                    checkbox = "■" if str(f['id']) in selected_ids else "□"
                    print(f"{checkbox} {tag} {f['name']}")  
                
                print("\n[0] 返回选择文件\n")
                for i, v in enumerate(versions, start=1): print(f"[{i}] {v}")
                v_in = input("输入版本编号: ")
                v_list = parse_multi_input(v_in, versions)
                if v_list == 'back': continue
                if not v_list: continue
                mode_name = "Custom Build"
                file_selected = True
                break
            if not file_selected: continue
            break
        elif mode == "4":
            print("\n更新缓存中...")
            sync_all_mods(config, force=True)
            print("\n[+] Mod 缓存已强制更新。")
            time.sleep(1); continue
        elif mode == "5":
            import webbrowser
            webbrowser.open("https://paratranz.cn/projects/16715/settings/files")
            print("[+] 正在打开云端文件管理页面...")
            time.sleep(1); continue
        else: continue

    if not selected_files or not v_list: return
    
    raw_map = {}
    with ThreadPoolExecutor(max_workers=5) as ex:
        res_list = list(ex.map(download_file, selected_files))
        for fid, d in res_list:
            if d: raw_map[fid] = d

    log_data_list = []
    for ver in v_list:
        log_content, display_ver = build_resource_pack(ver, raw_map, config, mode_name, selected_files, release_mode, include_mods)
        log_data_list.append((log_content, display_ver))
    
    # 多线程上传所有日志
    # if log_data_list:
    #     logger.info("正在同步构建日志到 Gitee...")
    #     with ThreadPoolExecutor(max_workers=5) as ex:
    #         ex.map(lambda x: upload_to_gitee(x[0], x[1]), log_data_list)
    
    if HAS_ERROR: input("\n[!] 过程中有错误，按回车键关闭...")
    else: print("\n[+] 构建成功！"); time.sleep(1)

if __name__ == "__main__":
    main()