# Service Pattern Refactoring Guide

## Problem: Circular Dependencies

The current school demo has circular dependencies:
- `Student` imports and references `SchoolWorld`
- `SchoolWorld` creates `Student` instances (through `SchoolPopulation`)
- This creates import and initialization ordering issues

## Solution: Service Pattern

Instead of agents holding references to the entire World, they access specific **Services** they need.

## Key Changes

### 1. Make FriendshipManager a Service

```python
# demos/school_demo/src/networks.py
from src.layer1_core.managers.service import Service

class FriendshipManager(Service, NetworkManager):
    def __init__(self, service_id: str = "friendship_manager", friendships: List[Friendship] = None):
        Service.__init__(self, service_id)
        NetworkManager.__init__(self)
        self.friendships = self.edges

        if friendships:
            for friendship in friendships:
                self.register_friendship(friendship)
```

### 2. Remove World References from Agents

```python
# demos/school_demo/src/individual.py
class Student(Agent):
    def __init__(self, agent_id: str, age: int, race: str, neighborhood: Neighborhood = None):
        super().__init__(agent_id)
        self.age = age
        self.race = race
        self.mood = 0.5
        self.disciplinaryRecord = []
        self.using_substance = False
        self.neighborhood = neighborhood
        # No more self.world reference!

    def make_friend(self, new_friend: 'Student', friendship_manager: 'FriendshipManager'):
        """Make a friend using the provided friendship manager service."""
        from demos.school_demo.src.networks import Friendship
        new_friendship = Friendship(self, new_friend, 0.5)
        friendship_manager.register_friendship(new_friendship)
```

### 3. Register Services in SchoolWorld

```python
# demos/school_demo/src/schoolWorld.py
class SchoolWorld(WorldBuilder):
    def __init__(self, param_dict) -> None:
        super().__init__(param_dict)
        self.params = param_dict
        self.schedule = SchoolSchedule()

        # Create and register services
        self.friendshipManager = FriendshipManager("friendship_manager")
        self.services.register(self.friendshipManager)

        # Create neighborhoods and population
        self.neighborhoods = self.make_neighborhoods()
        self.population = SchoolPopulation(self.services, param_dict, self.neighborhoods)

        # Use the service
        self.friendshipManager.make_random_friendships(self.population)

        self.runner = SchoolSingleRunner(self, self.schedule, param_dict)
```

### 4. Update SchoolPopulation

```python
# demos/school_demo/src/schoolpopulation.py
class SchoolPopulation(Population):
    def __init__(self, services: ServiceRegistry, param_dict, neighborhoods):
        self.services = services
        self.param_dict = param_dict
        self.neighborhoods = neighborhoods

        # ... rest of initialization

    def make_new_students(self, studentCount: int, race_options: List[str]) -> List[Student]:
        studentList: List[Student] = []
        for i in range(studentCount):
            age = randint(13, 18)
            race = choice(race_options)
            neighborhood = choice(self.neighborhoods)
            new_student = Student(str(i), age, race, neighborhood)
            studentList.append(new_student)
        return studentList
```

### 5. Access Services Where Needed

When agents need to use services, pass them as parameters:

```python
# In SchoolWorld.setup_events()
def setup_events(self):
    friendship_mgr = self.services.get_by_type(FriendshipManager)

    for step in range(1, 1001):
        student = choice(self.population.students)

        self.schedule.add_event(
            step=step,
            event=lambda s=student: s.chance_to_misbehave()
        )

        friendship = choice(friendship_mgr.friendships)
        friendship.friendship_actions(step, self.schedule)
```

## Benefits

1. **No Circular Dependencies**: Agents don't import World classes
2. **Loose Coupling**: Agents only know about the specific services they need
3. **Testability**: Can easily mock services in tests
4. **Flexibility**: Can swap service implementations without changing agents
5. **Clear Dependencies**: Service requirements are explicit in method signatures