

import os
import sys
from pathlib import Path

def _is_path_ignored(path, root_dir, ignored_folders=None):
    """
    Checks if a given path should be ignored.
    `path` should be an absolute path.
    `root_dir` should be the absolute path to the project root.
    `ignored_folders` is a list of paths relative to `root_dir`.
    """
    if ignored_folders is None:
        return False
    
    try:
        relative_path = Path(path).relative_to(root_dir).as_posix()
    except ValueError:
        # The path is not within the root_dir, so we don't ignore it based on project rules.
        return False

    for ignored in ignored_folders:
        if relative_path.startswith(ignored):
            return True
    return False

def find_files_by_extension(root_dir, extension, ignored_folders=None, project_root=None):
    """
    Locates all files with a specific extension, excluding specified folders.
    """
    if not extension.startswith('.'):
        print("Error: Extension must start with a dot (e.g., '.txt').", file=sys.stderr)
        return []
    
    # If project_root isn't specified, assume it's the same as the search root.
    if project_root is None:
        project_root = root_dir
        
    found_files = []
    for root, dirs, files in os.walk(root_dir):
        # Prune ignored directories to prevent descending into them
        dirs[:] = [d for d in dirs if not _is_path_ignored(os.path.join(root, d), project_root, ignored_folders)]
        
        for file in files:
            if file.endswith(extension):
                full_path = os.path.join(root, file)
                if not _is_path_ignored(full_path, project_root, ignored_folders):
                    found_files.append(full_path)
    return found_files

def replicate_directory_structure(source_root, target_root, ignored_folders=None, project_root=None):
    """
    Copies a directory tree, excluding specified folders.
    """
    source_root_path = Path(source_root)
    target_root_path = Path(target_root)

    if not source_root_path.is_dir():
        print(f"Error: Source path '{source_root_path}' is not a valid directory.", file=sys.stderr)
        return

    if project_root is None:
        project_root = source_root

    for dirpath, dirnames, _ in os.walk(source_root):
        # Prune ignored directories
        dirnames[:] = [d for d in dirnames if not _is_path_ignored(os.path.join(dirpath, d), project_root, ignored_folders)]

        relative_path = Path(dirpath).relative_to(source_root_path)
        target_path = target_root_path / relative_path
        target_path.mkdir(parents=True, exist_ok=True)

def create_guid_to_path_map(root_dir, ignored_folders=None):
    """
    Creates a dictionary mapping GUIDs to their corresponding asset file paths,
    respecting an ignore list.
    """
    guid_map = {}
    # Define scan directories relative to the project root
    relative_scan_dirs = ['Assets', 'Packages', 'Library/PackageCache']
    
    for rel_dir in relative_scan_dirs:
        scan_dir = os.path.join(root_dir, rel_dir)
        if not os.path.isdir(scan_dir):
            continue
            
        meta_files = find_files_by_extension(scan_dir, '.meta', ignored_folders, project_root=root_dir)
        for meta_file_path in meta_files:
            asset_path = meta_file_path[:-5]
            guid = None
            is_folder = False
            try:
                with open(meta_file_path, 'r', encoding='utf-8') as f:
                    for line in f:
                        stripped_line = line.strip()
                        if stripped_line.startswith('guid:'):
                            guid = stripped_line.split(':')[1].strip()
                        if stripped_line == 'folderAsset: yes':
                            is_folder = True
                            break
                
                if is_folder:
                    continue

                if guid and guid not in guid_map:
                    # Store path relative to the root_dir for consistency
                    guid_map[guid] = Path(asset_path).relative_to(root_dir).as_posix()
            except Exception as e:
                print(f"Warning: Could not process meta file {meta_file_path}. {e}", file=sys.stderr)
    return guid_map

if __name__ == '__main__':
    # Example usage for testing the module directly.
    import shutil

    test_root = Path('./tmp_test_root')
    test_source_dir = test_root / 'Assets'
    test_target_dir = Path('./tmp_target_for_testing')
    ignored_list = ['Assets/ThirdParty']

    try:
        print("Setting up test directory structure...")
        (test_source_dir / 'scenes').mkdir(parents=True, exist_ok=True)
        (test_source_dir / 'prefabs').mkdir(parents=True, exist_ok=True)
        (test_source_dir / 'ThirdParty' / 'ignored').mkdir(parents=True, exist_ok=True)

        (test_source_dir / 'scenes' / 'level1.unity').touch()
        (test_source_dir / 'prefabs' / 'player.prefab').touch()
        (test_source_dir / 'ThirdParty' / 'ignored' / 'plugin.cs').touch()
        
        print(f"\n--- Testing find_files_by_extension with ignore list: {ignored_list} ---")
        
        # Test finding files (should ignore the .cs file)
        all_files = find_files_by_extension(str(test_source_dir), '.cs', ignored_folders=ignored_list, project_root=test_root)
        print(f"Found .cs files: {all_files}")
        assert len(all_files) == 0

        unity_files = find_files_by_extension(str(test_source_dir), '.unity', ignored_folders=ignored_list, project_root=test_root)
        print(f"Found .unity files: {unity_files}")
        assert len(unity_files) == 1

        print("\n--- Testing replicate_directory_structure with ignore list ---")
        replicate_directory_structure(str(test_source_dir), str(test_target_dir), ignored_folders=ignored_list, project_root=test_root)
        
        print("Checking replicated structure:")
        assert (test_target_dir / 'scenes').is_dir()
        assert not (test_target_dir / 'ThirdParty').exists()
        print("Replicated structure seems correct (ignored folder was skipped).")

    finally:
        if test_root.exists():
            shutil.rmtree(test_root)
        if test_target_dir.exists():
            shutil.rmtree(test_target_dir)
        print("\nCleaned up test directories.")


