import os
import fnmatch
import time
import hashlib
from pathspec import PathSpec
from pathspec.patterns import GitWildMatchPattern

def read_gitignore(gitignore_path):
    print(f"Reading .gitignore file from {gitignore_path}")
    if os.path.exists(gitignore_path):
        with open(gitignore_path, 'r', encoding='utf-8', errors='ignore') as f:
            gitignore_content = f.read()
        spec = PathSpec.from_lines(GitWildMatchPattern, gitignore_content.splitlines())
        print(f"Found {len(spec.patterns)} ignore patterns")
        return spec
    print("No .gitignore file found")
    return PathSpec([])

def should_ignore(path, gitignore_spec):
    # Ignore any path that starts with a dot at any level
    if any(part.startswith('.') for part in path.split(os.sep)):
        return True
    
    return gitignore_spec.match_file(path)

def get_file_hash(file_path):
    hash_md5 = hashlib.md5()
    with open(file_path, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

def count_files(folder, gitignore_spec):
    file_count = 0
    for root, dirs, files in os.walk(folder):
        dirs[:] = [d for d in dirs if not should_ignore(os.path.join(root, d), gitignore_spec)]
        file_count += sum(1 for f in files if not should_ignore(os.path.relpath(os.path.join(root, f), folder), gitignore_spec))
    return file_count

def compare_folders(folder1, folder2, output_file):
    start_time = time.time()
    print(f"Starting comparison of {folder1} and {folder2}")
    
    gitignore_path = os.path.join(folder1, '.gitignore')
    gitignore_spec = read_gitignore(gitignore_path)
    
    print(f"Total files in {folder1}: {count_files(folder1, gitignore_spec)}")
    print(f"Total files in {folder2}: {count_files(folder2, gitignore_spec)}")
    
    files1 = {}
    files2 = set()
    
    with open(output_file, 'w', encoding='utf-8') as out:
        # Process folder1
        print(f"\nProcessing {folder1}")
        processed_files = 0
        for root, dirs, files in os.walk(folder1):
            dirs[:] = [d for d in dirs if not should_ignore(os.path.join(root, d), gitignore_spec)]
            rel_path = os.path.relpath(root, folder1)
            if rel_path == '.':
                rel_path = ''
            
            for file in files:
                file_path = os.path.join(rel_path, file)
                if not should_ignore(file_path, gitignore_spec):
                    processed_files += 1
                    if processed_files % 100 == 0:
                        print(f"Processed {processed_files} files in folder1")
                    
                    full_path = os.path.join(folder1, file_path)
                    file_hash = get_file_hash(full_path)
                    files1[file_path] = file_hash
        
        print(f"Total processed files in folder1: {processed_files}")
        
        # Process folder2
        print(f"\nProcessing {folder2}")
        processed_files = 0
        for root, dirs, files in os.walk(folder2):
            dirs[:] = [d for d in dirs if not should_ignore(os.path.join(root, d), gitignore_spec)]
            rel_path = os.path.relpath(root, folder2)
            if rel_path == '.':
                rel_path = ''
            
            for file in files:
                file_path = os.path.join(rel_path, file)
                if not should_ignore(file_path, gitignore_spec):
                    processed_files += 1
                    if processed_files % 100 == 0:
                        print(f"Processed {processed_files} files in folder2")
                    
                    files2.add(file_path)
                    full_path = os.path.join(folder2, file_path)
                    if file_path in files1:
                        file_hash = get_file_hash(full_path)
                        if file_hash != files1[file_path]:
                            out.write(f"Different: {file_path}\n")
                            out.write(f"  Path 1: {os.path.join(folder1, file_path)}\n")
                            out.write(f"  Path 2: {full_path}\n\n")
        
        print(f"Total processed files in folder2: {processed_files}")
        
        # Find missing and extra files
        print("\nCalculating missing and extra files")
        missing_files = files2 - set(files1.keys())
        extra_files = set(files1.keys()) - files2
        
        # Write missing files
        print(f"Writing {len(missing_files)} missing files to output")
        for file_path in missing_files:
            full_path = os.path.join(folder2, file_path)
            out.write(f"Missing in folder1: {file_path}\n")
            out.write(f"  Path: {full_path}\n\n")
        
        # Write extra files
        print(f"Writing {len(extra_files)} extra files to output")
        for file_path in extra_files:
            full_path = os.path.join(folder1, file_path)
            out.write(f"Extra in folder1: {file_path}\n")
            out.write(f"  Path: {full_path}\n\n")

    end_time = time.time()
    print(f"\nComparison completed in {end_time - start_time:.2f} seconds")

# Example usage
folder1 = r'R:\LivePortrait_v3\LivePortrait'
folder2 = r'R:\live_temp_sync\LivePortrait'
output_file = 'outputs.txt'

compare_folders(folder1, folder2, output_file)
print(f"Comparison results have been written to {output_file}")