import os
import zlib
import json
from datetime import datetime
from multiprocessing import Pool, cpu_count

root_dir = './files/'
output_file = 'file_list.json'
output_patcher_version = 'patcher_version.json'
version = '1.0.0'  # Update this when releasing new version

def get_file_info(path):
    """Get file info including path, hash, and size."""
    crc32 = 0
    size = 0
    relative_path = os.path.relpath(path, start=root_dir)
    with open(path, 'rb') as f:
        for chunk in iter(lambda: f.read(4096), b''):
            crc32 = zlib.crc32(chunk, crc32)
            size += len(chunk)
    return {
        "path": relative_path.replace('\\', '/'),
        "hash": format(crc32 & 0xFFFFFFFF, '08x'),  # Format as lowercase hex
        "size": size
    }

def process_file(file_path):
    """Process a single file - wrapper for multiprocessing."""
    try:
        return get_file_info(file_path)
    except Exception as e:
        print(f"Error processing {file_path}: {e}")
        return None

def get_all_files(root_dir):
    """Get all files with parallel processing."""
    file_paths = []
    for dirpath, dirnames, filenames in os.walk(root_dir):
        for filename in filenames:
            file_path = os.path.join(dirpath, filename)
            file_paths.append(file_path)
    
    # Use multiprocessing for parallel checksum calculation
    num_workers = max(1, cpu_count() - 1)  # Leave one core free
    with Pool(processes=num_workers) as pool:
        file_info = pool.map(process_file, file_paths)
    
    # Filter out None results (errors)
    file_info = [f for f in file_info if f is not None]
    return file_info

def generate_file_list():
    """Generate file list with metadata."""
    print("Scanning files...")
    files = get_all_files(root_dir)
    
    total_size = sum(f["size"] for f in files)
    file_count = len(files)
    
    return {
        "version": version,
        "file_count": file_count,
        "total_size": total_size,
        "generated_at": datetime.now().isoformat(),
        "files": files
    }

def save_to_json(data, output_file):
    """Save data to JSON file."""
    with open(output_file, 'w') as f:
        json.dump(data, f, indent=4)
    print(f"File: {output_file} was successfully generated.")
    print(f"  - Version: {data.get('version', 'N/A')}")
    print(f"  - Files: {data.get('file_count', 0)}")
    print(f"  - Total size: {data.get('total_size', 0):,} bytes ({data.get('total_size', 0) / 1024 / 1024:.2f} MB)")

# Generate file list
file_list_data = generate_file_list()
save_to_json(file_list_data, output_file)

def compute_crc32(file_path):
    """Compute the CRC32 hash of a file."""
    prev = 0
    with open(file_path, "rb") as f:
        for line in f:
            prev = zlib.crc32(line, prev)
    return "%08x" % (prev & 0xFFFFFFFF)

def find_file_and_save_crc(folder, filename, output_json=output_patcher_version):
    """Find the file in the specified folder, compute its CRC32 hash, and save to JSON."""
    file_path = os.path.join(folder, filename)
    
    # Check if the file exists
    if os.path.exists(file_path):
        # Compute the CRC32 hash
        crc32_hash = compute_crc32(file_path)
        
        # Prepare the output JSON
        output_data = {"hash": crc32_hash}
        
        # Save to JSON
        with open(output_json, "w") as json_file:
            json.dump(output_data, json_file, indent=4)
        
        print(f"CRC32 hash of {filename} saved to {output_json}.")
    else:
        print(f"{filename} not found in the folder {folder}.")

find_file_and_save_crc("./patcher", "NothyrLauncher.exe")
