import sys
from pathlib import Path
from typing import List, Dict
from random import random, randint, choice
import networkx as nx

# Add framework src to path for imports
framework_src_path = Path(__file__).parent.parent.parent.parent / "src"
sys.path.insert(0, str(framework_src_path))

from demos.school_demo.src.individual import Student, Teacher, Counselor
from demos.school_demo.src.schoolSchedule import SchoolSchedule
from layer1_core.entities.agent import Agent
from layer1_core.managers.network_manager import NetworkManager
from layer1_core.entities.edge_agent import EdgeAgent
from layer1_core.managers.service import Service



class Friendship(EdgeAgent):
    """A friendship edge between two students - primarily a data container.
    All behavior logic is handled by FriendshipManager service.
    """

    def __init__(self, student1, student2, strength: float = 0.5):
        self.strength = strength
        super().__init__(student1, student2)

class FriendshipManager(Service, NetworkManager):
    """Service for managing friendships between students.

    This service handles all friendship-related behavior including:
    - Creating friendships
    - Strengthening/weakening friendships
    - Affecting student moods through friendships
    - Scheduling friendship interactions
    """

    def __init__(self, service_id: str = "friendship_manager", param_dict: dict = None, friendships: List[Friendship] = None):
        Service.__init__(self, service_id)
        NetworkManager.__init__(self)
        self.param_dict = param_dict or {}
        self.friendships = self.edges

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

    def register_friendship(self, friendship: Friendship):
        """Register a new friendship in the network.

        Args:
            friendship: The Friendship edge to register
        """
        self.edges.append(friendship)

    def make_friend(self, student1: Student, student2: Student, initial_strength: float = 0.5):
        """Create a friendship between two students.

        Args:
            student1: First student
            student2: Second student
            initial_strength: Initial friendship strength (default 0.5)
        """
        new_friendship = Friendship(student1, student2, initial_strength)
        self.register_friendship(new_friendship)

    def make_random_friendships(self, population, count: int = 50):
        """Create random friendships between students in the population.

        Args:
            population: SchoolPopulation containing students
            count: Number of random friendships to create
        """
        for i in range(count):
            student1 = choice(population.students)
            student2 = choice(population.students)

            if student1 is not student2:
                self.make_friend(student1, student2, random())

    def strengthen_friendship(self, friendship: Friendship, amount: float = 0.1):
        """Strengthen a friendship.

        Args:
            friendship: The friendship to strengthen
            amount: Amount to increase strength by
        """
        friendship.strength += amount

    def weaken_friendship(self, friendship: Friendship, amount: float = 0.1):
        """Weaken a friendship.

        Args:
            friendship: The friendship to weaken
            amount: Amount to decrease strength by
        """
        friendship.strength -= amount

    def affect_student_moods_from_friendship(self, friendship: Friendship):
        """Affect the moods of both students in a friendship based on friendship strength.

        Args:
            friendship: The friendship to process
        """
        mood_change = friendship.strength * 0.1

        # Affect both students' moods
        student1 = friendship.agent_1
        student2 = friendship.agent_2

        student1.mood = student1.mood + (mood_change * 0.1)
        student2.mood = student2.mood + (mood_change * 0.1)

    def process_friendship_interaction(self, friendship: Friendship):
        """Process a single friendship interaction - may strengthen or weaken.

        Args:
            friendship: The friendship to process
        """
        # Randomly decide whether to strengthen or weaken
        strengthen_or_weaken = choice(['s', 'w'])

        if strengthen_or_weaken == 's':
            self.strengthen_friendship(friendship)
        else:
            self.weaken_friendship(friendship)

        # Affect student moods based on friendship strength
        self.affect_student_moods_from_friendship(friendship)

    def schedule_friendship_interactions(self, schedule: SchoolSchedule,
                                         start_step: int, end_step: int):
        """Schedule friendship interactions throughout the simulation.

        Args:
            schedule: The simulation schedule
            start_step: First step to schedule events
            end_step: Last step to schedule events
        """
        if not self.friendships:
            return

        for step in range(start_step, end_step):
            # Pick a random friendship for each step
            friendship = choice(self.friendships)

            # Schedule the interaction
            schedule.add_event(
                step=step,
                event=lambda f=friendship: self.process_friendship_interaction(f)
            )




class StudentTeacherRelationship(EdgeAgent):
    def __init__(self, student: Student, teacher: Teacher):
        self.student = student
        self.teacher = teacher
        super().__init__(student, teacher)

class StudentTeacherRelationshipManager(NetworkManager):
    def __init__(self, studentTeacherRelationships: List[StudentTeacherRelationship] = None):
        super().__init__()
        if studentTeacherRelationships:
            for relationship in studentTeacherRelationships:
                self.add_edge(relationship)


class CounselingRelationship(EdgeAgent):
    def __init__(self, student: Student, counselor: Counselor):
        super().__init__(student, counselor)

class CounselingRelationshipsManager(NetworkManager):
    def __init__(self, counseling_relationships: List[CounselingRelationship] = None):
        super().__init__()
        if counseling_relationships:
            for relationship in counseling_relationships:
                self.add_edge(relationship)