# ╔═══════════════════════════════════════════════════════════════════════════════╗
# ║                        🚨 CRITICAL WARNING 🚨                                ║
# ║                     AUTOGENERATED! DO NOT EDIT!                              ║
# ║                                                                               ║
# ║  This file is AUTOMATICALLY GENERATED from source modules.                   ║
# ║  ANY CHANGES MADE HERE WILL BE LOST when modules are re-exported!            ║
# ║                                                                               ║
# ║  ✅ TO EDIT: modules/source/XX_modules/modules_dev.py               ║
# ║  ✅ TO EXPORT: Run 'tito module complete <module_name>'                      ║
# ║                                                                               ║
# ║  🛡️ STUDENT PROTECTION: This file contains critical fixes for Variable/      ║
# ║     Tensor compatibility. Editing it directly WILL break CIFAR-10 training.  ║
# ║                                                                               ║
# ║  🎓 LEARNING TIP: Work in modules/source/ - that's where real development    ║
# ║     happens! The tinytorch/ directory is just the compiled output.           ║
# ╚═══════════════════════════════════════════════════════════════════════════════╝
"""
Base Module class for TinyTorch neural network layers.

This module provides the foundational Module class that enables:
- Automatic parameter registration
- Recursive parameter collection
- Clean composition of neural networks
- PyTorch-compatible interface

Students implement the core algorithms while this infrastructure 
provides the clean API patterns they expect.
"""

from typing import Iterator, List


class Module:
    """
    Base class for all neural network modules.
    
    Your models should subclass this class to automatically get:
    - Parameter registration when you set attributes
    - Recursive parameter collection via parameters()
    - Clean callable interface model(x) instead of model.forward(x)
    
    This matches PyTorch's nn.Module interface for familiar patterns.
    """
    
    def __init__(self):
        """Initialize module with parameter and submodule tracking."""
        # Use object.__setattr__ to avoid triggering our custom __setattr__
        object.__setattr__(self, '_parameters', [])
        object.__setattr__(self, '_modules', [])
        object.__setattr__(self, '_initialized', True)
    
    def __setattr__(self, name: str, value):
        """
        Automatically register parameters and submodules.
        
        When you do: self.weight = Parameter(...), it gets auto-registered.
        When you do: self.layer = Linear(...), it gets auto-registered.
        """
        if not hasattr(self, '_initialized'):
            # Still in __init__, use normal assignment
            object.__setattr__(self, name, value)
            return
            
        # Check if this is a Parameter (has requires_grad attribute and is True)
        if hasattr(value, 'requires_grad') and value.requires_grad:
            if value not in self._parameters:
                self._parameters.append(value)
        
        # Check if this is a Module subclass
        elif isinstance(value, Module):
            if value not in self._modules:
                self._modules.append(value)
        
        # Normal attribute assignment
        object.__setattr__(self, name, value)
    
    def parameters(self) -> Iterator:
        """
        Return an iterator over module parameters.
        
        This is used by optimizers to find all trainable parameters:
        optimizer = Adam(model.parameters())
        """
        # Return our direct parameters
        for param in self._parameters:
            yield param
        
        # Recursively collect parameters from submodules
        for module in self._modules:
            for param in module.parameters():
                yield param
    
    def __call__(self, *args, **kwargs):
        """
        Make modules callable: model(x) calls model.forward(x).
        
        This is the standard PyTorch pattern that students expect.
        """
        return self.forward(*args, **kwargs)
    
    def forward(self, *args, **kwargs):
        """
        Define the forward pass computation.
        
        Subclasses must implement this method.
        """
        raise NotImplementedError("Subclasses must implement forward()")