# -*- coding: UTF-8 -*-
import os,sys
import random
import string
import re
import time
import json
import shutil
import hashlib 
import time
import argparse
#该脚本目前只针对Assets.xcassets目录下的文件进行副本、添加;
#即:在该脚本执行完毕之后,请将指定的--target 对应目录下的Assets.xcassets拷贝回工程项目替换原有的Assets.xcassets即可
#该脚本会修改原来的png图片的sha值,以及随机添加一些无效的且无法预览fake图片
script_path = os.path.split(os.path.realpath(sys.argv[0]))[0]

resource_path = ""
target_path = os.path.join(script_path, "target_resource")

#匹配规则，路径包含path_include且不包含path_exclude的才会创建对应类型的文件  os.path.sep:代表路径分隔符,即 /
match_rule = {
    ".png": {
#        "path_include": os.path.sep + "res",
    },
}
#确保添加的函数不重名
funcname_set = set()

#单词列表，用以随机名称
with open(os.path.join(script_path, "./ClassName_list.json"), "r") as fileObj:
    word_name_list = json.load(fileObj)

#获取一个随机名称
def getOneName():
    global word_name_list
    return random.choice(word_name_list)



#获取png内容
def getPngText():
    hexbyte = "0000000049454e44ae426082"
    text = str(random.randint(1, 100)) * random.randint(1024, 10240)
    text = text + bytes.fromhex(hexbyte).hex()
    text = text.encode('utf-8')
    return text

#添加单个文件
def addSingleFile(file_path):
    global target_path
    print ("add file " + file_path.replace(target_path, ""))
    _, file_type = os.path.splitext(file_path)
    if file_type == ".png":
#        print("发现png文件,准备在文件末尾追加hex文件操作...")
        with open(file_path, "wb") as fileObj:
            fileObj.write(getPngText())
            fileObj.close()
    
def addFileTo(parent_folder, level, min_file_num=0):
    global match_rule, target_path
    create_folder_list = []
    for parent, folders, files in os.walk(parent_folder):
        target_file_type = ""
        relative_path = parent.replace(target_path, "")
        print("relative_path:"+relative_path)
        for file_type, match_config in match_rule.items():
#            print("file_type:" + file_type)
            print("match_config:" + str(match_config))
            
            if "path_exclude" in match_config and relative_path.find(match_config["path_exclude"]) != -1:
                continue
            if "path_include" not in match_config or relative_path.find(match_config["path_include"]) != -1:
                target_file_type = file_type
#                print("target_file_type:"+target_file_type)
                break
        if not target_file_type:
            print("不在执行后续的addSingleFile步骤")
            continue

        # Create file count 创建 指定的最小文件数量 + 文件列表长度一半 到 文件列表长度 之间 的数量
        new_file_num = random.randint(len(files) // 2, len(files)) + min_file_num
        for i in range(new_file_num):
            #根据随机的文件名 + 文件后缀类型 拼接为要创建的文件路径
            file_path = os.path.join(parent, getOneName() + target_file_type)
            addSingleFile(file_path)
            print("已经执行addSingleFile步骤...")
        # Prevent creating too many levels 如果该目录下已经被自动创建目录,则不再继续自动创建
        if level > 2:
            continue

        # Create folder count
        new_fold_num = random.randint(len(folders) // 2, len(folders))
        for i in range(new_fold_num):
            target_folder = os.path.join(parent, getOneName())
            # Defer folder creation to avoid interrupting os.walk
            create_folder_list.append(target_folder)

    for folder_path in create_folder_list:
        try:
            print("create folder", folder_path.replace(target_path, ""))
            os.makedirs(folder_path, exist_ok=True)  # Handle existing folders
            addFileTo(folder_path, level + 1, random.randint(2, 5))
        except Exception as e:
            print(e)

#----------------------------------------ended add file----------------------
def changeSingleFileMD5(file_path):
    pre_hash_valaue = calculate_sha256_hash(file_path)
#    print("pre_hash_value:\n" + pre_hash_valaue)
    _, file_type = os.path.splitext(file_path)
    with open(file_path, "ab") as fileObj:
        if file_type == ".png":
            text = "".join(random.sample(string.ascii_letters, 11))
        elif file_type == ".jpg":
            text = "".join(random.sample(string.ascii_letters, 20))
        else:
            text = " "*random.randint(1, 100)
        fileObj.write(text.encode('utf-8'))
        fileObj.close()
        after_hash_valaue = calculate_sha256_hash(file_path)
#        print("after_hash_valaue:\n" + after_hash_valaue)

#改变文件md5
def changeFolderMD5(target_path):
#    type_filter = set([".png", ".jpg", ".json", ".plist", ".fnt"])
#暂时不处理json、pilist文件
    type_filter = set([".png", ".jpg"])
    for parent, folders, files in os.walk(target_path):
        for file in files:
            full_path = os.path.join(parent, file)
            _, file_type = os.path.splitext(full_path)
            if file_type in type_filter:
                changeSingleFileMD5(full_path)

#返回文件的hash值
def calculate_sha256_hash(file_path):
    with open(file_path, 'rb') as f:
        data = f.read()
    hasher = hashlib.sha256()
    hasher.update(data)
    return hasher.hexdigest()
#----------------------------------------------------main------------------------------------------------
        
def parse_args():
    global res_path
    parser = argparse.ArgumentParser(description='资源变异工具')
    parser.add_argument('--res', dest='res_dir', type=str, required=True, help='资源目录')
    parser.add_argument('--target', dest='target_dir', type=str, required=False, default=target_path, help='资源导出目录')

    args = parser.parse_args()
    return args

def main():
    global resource_path, target_path
    app_args = parse_args()
    resource_path = app_args.res_dir
    target_path = app_args.target_dir

    if not os.path.exists(resource_path):
        print ("res path not exists: " + resource_path)
        exit(0)
    if target_path != resource_path:
        if os.path.exists(target_path):
            shutil.rmtree(target_path)
        shutil.copytree(resource_path, target_path)
    #执行png文件的添加、目录的创建
    addFileTo(target_path, 0)
    
    print ("\n\nstart modify file md5")
    changeFolderMD5(target_path)
    print ("finish!")

if __name__ == "__main__":
    main()
