import os
import sys
import yaml
import importlib
import fnmatch

class Project:
    @staticmethod
    def _load_pbignore(root_path):
        """Load .pbignore file and return list of ignore patterns"""
        pbignore_path = os.path.join(root_path, '.pbignore')
        ignore_patterns = []
        
        if os.path.exists(pbignore_path):
            try:
                with open(pbignore_path, 'r', encoding='utf-8') as f:
                    for line in f:
                        line = line.strip()
                        # Skip empty lines and comments
                        if line and not line.startswith('#'):
                            ignore_patterns.append(line)
            except Exception as e:
                print(f"Warning: Could not read .pbignore file: {e}")
        
        return ignore_patterns
    
    @staticmethod
    def _should_ignore(path, ignore_patterns, root_path):
        """Check if a path should be ignored based on .pbignore patterns"""
        if not ignore_patterns:
            return False
        
        # Get relative path from root
        try:
            rel_path = os.path.relpath(path, root_path)
        except ValueError:
            # If path is not relative to root, don't ignore
            return False
        
        # Normalize path separators
        rel_path = rel_path.replace(os.sep, '/')
        
        for pattern in ignore_patterns:
            # Handle directory patterns (ending with /)
            if pattern.endswith('/'):
                pattern = pattern[:-1]
                if fnmatch.fnmatch(rel_path, pattern) or fnmatch.fnmatch(rel_path, pattern + '/*'):
                    return True
            else:
                # Handle file/directory patterns
                if fnmatch.fnmatch(rel_path, pattern) or fnmatch.fnmatch(os.path.basename(rel_path), pattern):
                    return True
        
        return False

    @staticmethod
    def scan_project(root_path):
        sys.path.append(root_path)
        if not os.path.exists(root_path) or not os.path.isdir(root_path):
            raise ValueError(f"The provided root_path '{root_path}' is not a valid directory.")
    
        parent_dir = os.path.dirname(root_path)
        sys.path.insert(0, parent_dir)
        
        # Load .pbignore patterns
        ignore_patterns = Project._load_pbignore(root_path)
        
        def import_all_modules(path, package_name):
            for root, dirs, files in os.walk(path):
                # Check if current directory should be ignored
                if Project._should_ignore(root, ignore_patterns, root_path):
                    dirs[:] = []  # Don't traverse into ignored directories
                    continue
                
                relative_path = os.path.relpath(root, root_path)
                if relative_path == '.':
                    module_package = package_name
                else:
                    module_package = f"{package_name}.{relative_path.replace(os.sep, '.')}"
                
                for file in files:
                    if file.endswith(".py") and file != "__init__.py":
                        file_path = os.path.join(root, file)
                        # Check if file should be ignored
                        if Project._should_ignore(file_path, ignore_patterns, root_path):
                            continue
                        
                        module_name = file[:-3]
                        full_module_name = f"{module_package}.{module_name}"
                        if full_module_name not in sys.modules:
                            importlib.import_module(full_module_name)
                
                # Filter out ignored directories from further traversal
                dirs[:] = [d for d in dirs if not d.startswith('.') and 
                          not Project._should_ignore(os.path.join(root, d), ignore_patterns, root_path)]
        
        package_name = os.path.basename(root_path)
        import_all_modules(root_path, package_name)
        
    @staticmethod
    def scan_configs(root_path):
        configs = {}
        for root, dirs, files in os.walk(root_path):
            for file in files:
                if file.endswith(('.yaml', '.yml')):
                    if file.startswith('__'):
                        continue
                    file_path = os.path.join(root, file)
                    with open(file_path, 'r', encoding='utf-8') as f:
                        try:
                            content = yaml.safe_load(f)
                            configs[os.path.splitext(file)[0]] = content
                        except yaml.YAMLError as e:
                            print(f"Error reading {file_path}: {e}")
        
        return configs