"""
Unit tests for adolescence events (ages 10-18).

Tests events from:
- ws/events/adolescence/puberty.py (puberty, startedPeriod, braces, glasses)
- ws/events/adolescence/social.py (firstCrush, firstKiss, dating_choice, romanticDate, newFriend)
- ws/events/adolescence/life_events.py (groupProjectDrama, voiceCracking, bodySelfConsciousness,
  curfewArgument, growthSpurt, embarrassingSituation, sleepover, socialMediaPressure,
  fashionExperimentation, learningToDrive)

Test Pattern for Each Event:
- test_event_triggers_at_correct_age - Event only triggers in age range
- test_event_requires_conditions - Event needs specific conditions met
- test_event_not_duplicate - Event fname not in player.events/askedQuestions
- test_event_applies_costs_correctly - Money/energy/stats updated
- test_event_choice_consequences - Different answers → different outcomes
- test_event_chain_progression - Multi-part events sequence correctly

Run with: pytest tests/unit/events/test_adolescence_events.py -v
"""

import pytest
import sys
import os
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
from types import SimpleNamespace

# Add ws directory to path (same as conftest.py does)
ws_dir = Path(__file__).parent.parent.parent.parent / 'ws'
if str(ws_dir) not in sys.path:
    sys.path.insert(0, str(ws_dir))

# Set test mode
os.environ['TEST_MODE'] = 'true'

# Import event functions using importlib to avoid loading full event package
import importlib.util

def load_module_from_path(module_name, file_path):
    """Load a module from a file path without importing its package"""
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    sys.modules[module_name] = module
    spec.loader.exec_module(module)
    return module

# Load base modules and models directly to avoid package imports
ws_path = Path(__file__).parent.parent.parent.parent / 'ws'
base_module = load_module_from_path("events.base", ws_path / 'events' / 'base.py')
models_module = load_module_from_path("core.models", ws_path / 'core' / 'models.py')

# Extract base classes
messageEvent = base_module.messageEvent
questionEvent = base_module.questionEvent
answerOption = base_module.answerOption

# Extract model classes
playerClass = models_module.playerClass
personClass = models_module.personClass

# Load event modules directly
puberty_module = load_module_from_path("adolescence_puberty", ws_path / 'events' / 'adolescence' / 'puberty.py')
social_module = load_module_from_path("adolescence_social", ws_path / 'events' / 'adolescence' / 'social.py')
life_events_module = load_module_from_path("adolescence_life_events", ws_path / 'events' / 'adolescence' / 'life_events.py')

# Extract event functions
puberty = puberty_module.puberty
startedPeriod = puberty_module.startedPeriod
braces = puberty_module.braces
glasses = puberty_module.glasses

firstCrush = social_module.firstCrush
firstKiss = social_module.firstKiss
dating_choice = social_module.dating_choice
romanticDate = social_module.romanticDate
newFriend = social_module.newFriend

groupProjectDrama = life_events_module.groupProjectDrama
voiceCracking = life_events_module.voiceCracking
bodySelfConsciousness = life_events_module.bodySelfConsciousness
curfewArgument = life_events_module.curfewArgument
growthSpurt = life_events_module.growthSpurt
embarrassingSituation = life_events_module.embarrassingSituation
sleepover = life_events_module.sleepover
socialMediaPressure = life_events_module.socialMediaPressure
fashionExperimentation = life_events_module.fashionExperimentation
learningToDrive = life_events_module.learningToDrive


# ============================================================================
# FIXTURES
# ============================================================================

def create_mock_player(age=16, sex='Female'):
    """Create a minimal mock player object for testing"""
    player = SimpleNamespace()

    # Character
    player.c = SimpleNamespace()
    player.c.ageYears = age
    player.c.ageHours = age * 365 * 24
    player.c.ageDays = age * 365
    player.c.sex = sex
    player.c.occupation = 'student'
    player.c.location = 'school'
    player.c.energy = 100
    player.c.happiness = 70
    player.c.social = 60
    player.c.money = 100
    player.c.stress = 0
    player.c.braces = False
    player.c.glasses = False
    player.c.relationship = None
    player.c.partner = None
    player.c.firstCrush = None
    player.c.sexualOrientation = None
    player.c.hasSocialMedia = False

    # Player state
    player.events = set()
    player.askedQuestions = set()
    player.messageQueue = []
    player.r = []  # relationships
    player.date = '01-15'
    player.hourOfDay = 12
    player.gameSpeed = 1000
    player.previousGameSpeed = 1000

    return player


def create_mock_person(id='person123', firstname='Alex', lastname='Smith', age=16, sex='Male'):
    """Create a minimal mock person object for testing"""
    person = SimpleNamespace()
    person.id = id
    person.firstname = firstname
    person.lastname = lastname
    person.ageYears = age
    person.sex = sex
    person.relationships = ['friend']
    person.affinity = 60
    person.familyLevel = 0
    return person


@pytest.fixture
def teen_player():
    """Create a player with a 16-year-old character for testing"""
    return create_mock_player(age=16, sex='Female')


@pytest.fixture
def young_teen_player():
    """Create a player with a 12-year-old character"""
    return create_mock_player(age=12, sex='Male')


@pytest.fixture
def mock_classmate():
    """Create a mock classmate"""
    return create_mock_person(id='classmate123', firstname='Alex', lastname='Smith', age=16, sex='Male')


@pytest.fixture
def mock_friend():
    """Create a mock friend"""
    return create_mock_person(id='friend456', firstname='Jordan', lastname='Taylor', age=15, sex='Female')


# ============================================================================
# PUBERTY EVENTS (puberty.py) - 8 tests
# ============================================================================

class TestPubertyEvent:
    """Tests for puberty event"""

    def test_puberty_triggers_at_age_12(self, young_teen_player):
        """Test that puberty event triggers at exactly age 12"""
        assert young_teen_player.c.ageYears == 12
        event = puberty(young_teen_player)

        assert event is not None
        assert isinstance(event, messageEvent)
        assert 'puberty' in event.message.lower()
        assert 'puberty' in young_teen_player.events

    def test_puberty_does_not_trigger_before_age_12(self, teen_player):
        """Test that puberty doesn't trigger before age 12"""
        teen_player.c.ageYears = 11
        event = puberty(teen_player)

        assert event is None

    def test_puberty_does_not_trigger_after_age_12(self, teen_player):
        """Test that puberty doesn't trigger after age 12"""
        teen_player.c.ageYears = 13
        event = puberty(teen_player)

        assert event is None

    def test_puberty_not_duplicate(self, young_teen_player):
        """Test that puberty event doesn't trigger twice"""
        young_teen_player.events.add('puberty')
        event = puberty(young_teen_player)

        assert event is None


class TestStartedPeriodEvent:
    """Tests for first period event (female only)"""

    @patch('random.random', return_value=0.0001)  # Force trigger
    def test_started_period_triggers_for_female(self, mock_random, teen_player):
        """Test that first period triggers for female characters"""
        teen_player.c.sex = 'Female'
        teen_player.c.ageYears = 12
        event = startedPeriod(teen_player)

        assert event is not None
        assert isinstance(event, messageEvent)
        assert 'period' in event.message.lower()

    @patch('random.random', return_value=0.0001)
    def test_started_period_does_not_trigger_for_male(self, mock_random, teen_player):
        """Test that first period doesn't trigger for male characters"""
        teen_player.c.sex = 'Male'
        teen_player.c.ageYears = 12
        event = startedPeriod(teen_player)

        assert event is None

    @patch('random.random', return_value=0.0001)
    def test_started_period_age_range(self, mock_random, teen_player):
        """Test that first period only triggers in ages 10-14"""
        teen_player.c.sex = 'Female'

        # Test age 10
        teen_player.c.ageYears = 10
        event = startedPeriod(teen_player)
        assert event is not None

        # Test age 14
        teen_player.events.clear()
        teen_player.c.ageYears = 14
        event = startedPeriod(teen_player)
        assert event is not None

        # Test age 15 (should not trigger)
        teen_player.events.clear()
        teen_player.c.ageYears = 15
        event = startedPeriod(teen_player)
        assert event is None

    @patch('random.random', return_value=0.0001)
    def test_started_period_not_duplicate(self, mock_random, teen_player):
        """Test that first period doesn't trigger twice"""
        teen_player.c.sex = 'Female'
        teen_player.c.ageYears = 12
        teen_player.events.add('startedPeriod')
        event = startedPeriod(teen_player)

        assert event is None


class TestBracesEvent:
    """Tests for getting braces event"""

    @patch('random.random', side_effect=[0.00001, 0.3])  # Force trigger, assign braces
    def test_braces_triggers_and_assigns(self, mock_random, teen_player):
        """Test that braces event triggers and assigns braces"""
        teen_player.c.ageYears = 14
        event = braces(teen_player)

        assert event is not None or event is False  # Could be False if random says no
        assert 'braces' in teen_player.askedQuestions

    @patch('random.random', side_effect=[0.00001, 0.6])  # Force trigger, don't assign
    def test_braces_can_be_declined(self, mock_random, teen_player):
        """Test that braces event can result in no braces"""
        teen_player.c.ageYears = 14
        event = braces(teen_player)

        # Event triggered but random decided no braces
        assert event is False or (hasattr(teen_player.c, 'braces') and not teen_player.c.braces)

    def test_braces_age_range(self, teen_player):
        """Test that braces only triggers in ages 7-19"""
        # Age 6 - too young
        teen_player.c.ageYears = 6
        event = braces(teen_player)
        assert event is None

        # Age 20 - too old
        teen_player.askedQuestions.clear()
        teen_player.c.ageYears = 20
        event = braces(teen_player)
        assert event is None

    def test_braces_not_duplicate(self, teen_player):
        """Test that braces event doesn't trigger twice"""
        teen_player.c.ageYears = 14
        teen_player.askedQuestions.add('braces')
        event = braces(teen_player)

        assert event is None


class TestGlassesEvent:
    """Tests for getting glasses event"""

    @patch('random.random', side_effect=[0.00001, 0.3])  # Force trigger, assign glasses
    def test_glasses_triggers_and_assigns(self, mock_random, teen_player):
        """Test that glasses event triggers and assigns glasses"""
        teen_player.c.ageYears = 14
        event = glasses(teen_player)

        assert event is not None or event is False
        assert 'glasses' in teen_player.askedQuestions

    @patch('random.random', side_effect=[0.00001, 0.7])  # Force trigger, don't assign
    def test_glasses_can_be_declined(self, mock_random, teen_player):
        """Test that glasses event can result in no glasses"""
        teen_player.c.ageYears = 14
        event = glasses(teen_player)

        # Event triggered but random decided no glasses
        assert event is False or (hasattr(teen_player.c, 'glasses') and not teen_player.c.glasses)

    def test_glasses_age_range(self, teen_player):
        """Test that glasses only triggers in ages 7-19"""
        # Age 6 - too young
        teen_player.c.ageYears = 6
        event = glasses(teen_player)
        assert event is None

        # Age 20 - too old
        teen_player.askedQuestions.clear()
        teen_player.c.ageYears = 20
        event = glasses(teen_player)
        assert event is None


# ============================================================================
# SOCIAL EVENTS (social.py) - 15 tests
# ============================================================================

class TestFirstCrushEvent:
    """Tests for first crush event"""

    @patch('random.random', return_value=0.001)
    @patch('ws.events.adolescence.social.get_random_classmate')
    @patch('ws.events.adolescence.social.get_random_friend')
    def test_first_crush_triggers_with_options(self, mock_get_friend, mock_get_classmate, mock_random, young_teen_player, mock_friend, mock_classmate):
        """Test that first crush event provides multiple options"""
        mock_get_friend.return_value = mock_friend
        mock_get_classmate.return_value = mock_classmate
        young_teen_player.c.ageYears = 11

        event = firstCrush(young_teen_player)

        assert event is not None
        assert isinstance(event, questionEvent)
        assert len(event.answers) > 0

    @patch('random.random', return_value=0.001)
    @patch('ws.events.adolescence.social.get_random_classmate')
    @patch('ws.events.adolescence.social.get_random_friend')
    @patch('ws.events.adolescence.social.get_person')
    @patch('ws.events.adolescence.social.update_relationship')
    def test_first_crush_sets_sexual_orientation_homosexual(
        self, mock_update, mock_get_person, mock_get_friend, mock_get_classmate, mock_random, young_teen_player, mock_classmate
    ):
        """Test that choosing same-sex crush sets homosexual orientation"""
        mock_get_friend.return_value = None
        mock_get_classmate.return_value = mock_classmate

        # Make classmate same sex as player
        mock_classmate.sex = young_teen_player.c.sex
        mock_get_person.return_value = mock_classmate

        # Answer the question
        response = {'data': mock_classmate.id}
        firstCrush(young_teen_player, type='answer', response=response)

        assert young_teen_player.c.sexualOrientation == 'homosexual'

    @patch('random.random', return_value=0.001)
    @patch('ws.events.adolescence.social.get_random_classmate')
    @patch('ws.events.adolescence.social.get_random_friend')
    @patch('ws.events.adolescence.social.get_person')
    @patch('ws.events.adolescence.social.update_relationship')
    def test_first_crush_sets_sexual_orientation_heterosexual(
        self, mock_update, mock_get_person, mock_get_friend, mock_get_classmate, mock_random, young_teen_player, mock_classmate
    ):
        """Test that choosing opposite-sex crush sets heterosexual orientation"""
        mock_get_friend.return_value = None
        mock_get_classmate.return_value = mock_classmate

        # Make classmate opposite sex
        mock_classmate.sex = 'Female' if young_teen_player.c.sex == 'Male' else 'Male'
        mock_get_person.return_value = mock_classmate

        # Answer the question
        response = {'data': mock_classmate.id}
        firstCrush(young_teen_player, type='answer', response=response)

        assert young_teen_player.c.sexualOrientation == 'heterosexual'

    def test_first_crush_age_range(self, young_teen_player):
        """Test that first crush only triggers in ages 10-12"""
        # Age 13 - too old
        young_teen_player.c.ageYears = 13
        event = firstCrush(young_teen_player)
        assert event is None


class TestFirstKissEvent:
    """Tests for first kiss event"""

    @patch('random.random', return_value=0.0001)
    def test_first_kiss_triggers_with_three_options(self, mock_random, teen_player):
        """Test that first kiss provides three response options"""
        teen_player.c.ageYears = 14
        event = firstKiss(teen_player)

        assert event is not None
        assert isinstance(event, questionEvent)
        assert len(event.answers) == 3

    @patch('random.random', return_value=0.0001)
    def test_first_kiss_lean_in_choice(self, mock_random, teen_player):
        """Test choosing to lean in for the kiss"""
        teen_player.c.ageYears = 14
        event = firstKiss(teen_player)

        # Choose first option (lean in)
        response = {'option': event.answers[0]}
        firstKiss(teen_player, type='answer', response=response)

        assert len(teen_player.messageQueue) > 0
        assert 'lips' in teen_player.messageQueue[-1].lower() or 'kiss' in teen_player.messageQueue[-1].lower()

    @patch('random.random', return_value=0.0001)
    def test_first_kiss_back_away_choice(self, mock_random, teen_player):
        """Test choosing to back away from the kiss"""
        teen_player.c.ageYears = 14
        event = firstKiss(teen_player)

        # Choose second option (back away)
        response = {'option': event.answers[1]}
        firstKiss(teen_player, type='answer', response=response)

        assert len(teen_player.messageQueue) > 0
        assert 'dodge' in teen_player.messageQueue[-1].lower() or 'away' in teen_player.messageQueue[-1].lower()

    @patch('random.random', return_value=0.0001)
    def test_first_kiss_let_down_easy_choice(self, mock_random, teen_player):
        """Test choosing to let them down easy (costs diamonds)"""
        teen_player.c.ageYears = 14
        event = firstKiss(teen_player)

        # Third option should cost diamonds
        assert event.answers[2].diamondCost == 5

        # Choose third option
        response = {'option': event.answers[2]}
        firstKiss(teen_player, type='answer', response=response)

        assert len(teen_player.messageQueue) > 0

    def test_first_kiss_age_requirement(self, teen_player):
        """Test that first kiss requires age 13+"""
        teen_player.c.ageYears = 12
        event = firstKiss(teen_player)
        assert event is None


class TestDatingChoiceEvent:
    """Tests for asking someone out event"""

    @patch('random.random', return_value=0.001)
    @patch('ws.events.adolescence.social.find_where_test')
    def test_dating_choice_requires_high_affinity(self, mock_find, teen_player, mock_friend):
        """Test that dating choice requires someone with affinity > 50"""
        teen_player.c.ageYears = 15
        teen_player.c.relationship = None
        mock_friend.affinity = 60
        mock_find.return_value = [mock_friend]

        event = dating_choice(teen_player)

        # Should show options since we have high-affinity people
        assert event is not None or event is False  # Depends on filtering

    @patch('random.random', return_value=0.001)
    @patch('ws.events.adolescence.social.find_where_test')
    def test_dating_choice_no_options_message(self, mock_find, teen_player):
        """Test message when no one likes you enough"""
        teen_player.c.ageYears = 15
        teen_player.c.relationship = None
        mock_find.return_value = []

        event = dating_choice(teen_player)

        # Should add to askedQuestions even if no valid options
        # Check if rejection message was added
        if 'dating_choice' in teen_player.askedQuestions:
            assert any('No one' in msg for msg in teen_player.messageQueue)

    @patch('random.random', side_effect=[0.001, 0.8])  # Trigger event, high success chance
    @patch('ws.events.adolescence.social.find_where_test')
    @patch('ws.events.adolescence.social.get_person')
    @patch('ws.events.adolescence.social.update_relationship')
    def test_dating_choice_acceptance_based_on_affinity(
        self, mock_update, mock_get_person, mock_find, teen_player, mock_friend
    ):
        """Test that high affinity increases acceptance chance"""
        teen_player.c.ageYears = 15
        teen_player.c.relationship = None
        teen_player.c.sex = 'Male'
        mock_friend.sex = 'Female'
        mock_friend.affinity = 80
        mock_friend.familyLevel = 0
        mock_find.return_value = [mock_friend]
        mock_get_person.return_value = mock_friend

        # Answer with this person's ID
        response = {'data': mock_friend.id}
        dating_choice(teen_player, type='answer', response=response)

        # With 80% affinity and random 0.8, should succeed
        assert 'yes' in teen_player.messageQueue[-1].lower()

    def test_dating_choice_age_requirement(self, teen_player):
        """Test that dating choice requires age 13+"""
        teen_player.c.ageYears = 12
        teen_player.c.relationship = None
        event = dating_choice(teen_player)
        assert event is None


class TestRomanticDateEvent:
    """Tests for romantic date event"""

    @patch('random.random', return_value=0.001)
    def test_romantic_date_provides_three_options(self, mock_random, teen_player):
        """Test that romantic date provides three date options"""
        teen_player.c.ageYears = 17
        event = romanticDate(teen_player)

        assert event is not None
        assert isinstance(event, questionEvent)
        assert len(event.answers) == 3

    @patch('random.random', return_value=0.001)
    def test_romantic_date_fancy_dinner_costs_money(self, mock_random, teen_player):
        """Test that fancy dinner option costs money"""
        teen_player.c.ageYears = 17
        event = romanticDate(teen_player)

        # First option should be fancy dinner with cost
        assert event.answers[0].moneyCost == 50

    @patch('random.random', return_value=0.001)
    def test_romantic_date_park_walk_costs_energy(self, mock_random, teen_player):
        """Test that park walk option costs energy"""
        teen_player.c.ageYears = 17
        event = romanticDate(teen_player)

        # Second option should be park walk with energy cost
        assert event.answers[1].energyCost == 10

    def test_romantic_date_age_range(self, teen_player):
        """Test that romantic date only triggers ages 16-18"""
        # Age 15 - too young
        teen_player.c.ageYears = 15
        event = romanticDate(teen_player)
        assert event is None

        # Age 19 - too old
        teen_player.c.ageYears = 19
        event = romanticDate(teen_player)
        assert event is None


class TestNewFriendEvent:
    """Tests for making new friend event"""

    @patch('random.random', return_value=0.0001)
    @patch('ws.events.adolescence.social.get_random_classmate')
    def test_new_friend_triggers_at_school(self, mock_get_classmate, mock_random, teen_player, mock_classmate):
        """Test that new friend event triggers at school"""
        mock_get_classmate.return_value = mock_classmate
        teen_player.c.location = 'school'
        teen_player.c.occupation = 'student'
        teen_player.c.ageYears = 15

        event = newFriend(teen_player)

        assert event is not None
        assert isinstance(event, questionEvent)

    @patch('random.random', return_value=0.0001)
    @patch('ws.events.adolescence.social.get_random_classmate')
    @patch('ws.events.adolescence.social.add_friend')
    def test_new_friend_accepting_adds_friend(self, mock_add_friend, mock_get_classmate, mock_random, teen_player, mock_classmate):
        """Test that accepting friendship adds a friend"""
        mock_get_classmate.return_value = mock_classmate
        teen_player.c.location = 'school'
        teen_player.c.occupation = 'student'
        teen_player.c.ageYears = 15
        mock_add_friend.return_value = teen_player

        event = newFriend(teen_player)

        # Accept friendship
        response = {'option': 'Yes'}
        newFriend(teen_player, type='answer', response=response)

        mock_add_friend.assert_called_once()

    @patch('random.random', return_value=0.0001)
    @patch('ws.events.adolescence.social.get_random_classmate')
    def test_new_friend_declining_reduces_social(self, mock_get_classmate, mock_random, teen_player, mock_classmate):
        """Test that declining friendship reduces social stat"""
        mock_get_classmate.return_value = mock_classmate
        teen_player.c.location = 'school'
        teen_player.c.occupation = 'student'
        teen_player.c.ageYears = 15
        initial_social = teen_player.c.social

        event = newFriend(teen_player)

        # Decline friendship
        response = {'option': 'No'}
        newFriend(teen_player, type='answer', response=response)

        assert teen_player.c.social < initial_social


# ============================================================================
# LIFE EVENTS (life_events.py) - 27 tests
# ============================================================================

class TestGroupProjectDramaEvent:
    """Tests for group project drama event"""

    @patch('random.random', return_value=0.0001)
    def test_group_project_drama_requires_student(self, mock_random, teen_player):
        """Test that group project only triggers for students"""
        teen_player.c.ageYears = 15
        teen_player.c.occupation = 'student'

        event = groupProjectDrama(teen_player)

        assert event is not None
        assert isinstance(event, questionEvent)

    @patch('random.random', return_value=0.0001)
    def test_group_project_drama_four_options(self, mock_random, teen_player):
        """Test that group project provides four response options"""
        teen_player.c.ageYears = 15
        teen_player.c.occupation = 'student'

        event = groupProjectDrama(teen_player)

        assert len(event.answers) == 4

    @patch('random.random', return_value=0.0001)
    def test_group_project_doing_all_work_reduces_happiness(self, mock_random, teen_player):
        """Test that doing all work yourself reduces happiness"""
        teen_player.c.ageYears = 15
        teen_player.c.occupation = 'student'
        initial_happiness = teen_player.c.happiness

        event = groupProjectDrama(teen_player)

        # Choose option 0 (do all work)
        response = {'option': event.answers[0].option}
        groupProjectDrama(teen_player, type='answer', response=response)

        assert teen_player.c.happiness < initial_happiness

    @patch('random.random', return_value=0.0001)
    def test_group_project_telling_teacher_reduces_social(self, mock_random, teen_player):
        """Test that telling teacher reduces social stat"""
        teen_player.c.ageYears = 15
        teen_player.c.occupation = 'student'
        initial_social = teen_player.c.social

        event = groupProjectDrama(teen_player)

        # Choose option 1 (tell teacher)
        response = {'option': event.answers[1].option}
        groupProjectDrama(teen_player, type='answer', response=response)

        assert teen_player.c.social < initial_social

    @patch('random.random', return_value=0.0001)
    def test_group_project_leadership_increases_social(self, mock_random, teen_player):
        """Test that helping everyone increases social stat"""
        teen_player.c.ageYears = 15
        teen_player.c.occupation = 'student'
        initial_social = teen_player.c.social

        event = groupProjectDrama(teen_player)

        # Choose option 2 (help everyone)
        response = {'option': event.answers[2].option}
        groupProjectDrama(teen_player, type='answer', response=response)

        assert teen_player.c.social > initial_social


class TestVoiceCrackingEvent:
    """Tests for voice cracking event (male only)"""

    @patch('random.random', return_value=0.0001)
    def test_voice_cracking_only_males(self, mock_random, young_teen_player):
        """Test that voice cracking only happens to males"""
        young_teen_player.c.sex = 'Male'
        young_teen_player.c.ageYears = 13

        event = voiceCracking(young_teen_player)

        assert event is not None
        assert isinstance(event, messageEvent)

    @patch('random.random', return_value=0.0001)
    def test_voice_cracking_not_females(self, mock_random, young_teen_player):
        """Test that voice cracking doesn't happen to females"""
        young_teen_player.c.sex = 'Female'
        young_teen_player.c.ageYears = 13

        event = voiceCracking(young_teen_player)

        assert event is None

    def test_voice_cracking_age_range(self, young_teen_player):
        """Test that voice cracking only occurs ages 12-14"""
        young_teen_player.c.sex = 'Male'

        # Age 11 - too young
        young_teen_player.c.ageYears = 11
        event = voiceCracking(young_teen_player)
        assert event is None

        # Age 15 - too old
        young_teen_player.events.clear()
        young_teen_player.c.ageYears = 15
        event = voiceCracking(young_teen_player)
        assert event is None


class TestBodySelfConsciousnessEvent:
    """Tests for body self-consciousness event"""

    @patch('random.random', return_value=0.0001)
    def test_body_self_consciousness_triggers(self, mock_random, young_teen_player):
        """Test that body self-consciousness event triggers"""
        young_teen_player.c.ageYears = 12

        event = bodySelfConsciousness(young_teen_player)

        assert event is not None
        assert isinstance(event, messageEvent)
        assert 'mirror' in event.message.lower()

    def test_body_self_consciousness_age_range(self, young_teen_player):
        """Test that event only triggers ages 11-14"""
        # Age 10 - too young
        young_teen_player.c.ageYears = 10
        event = bodySelfConsciousness(young_teen_player)
        assert event is None

        # Age 15 - too old
        young_teen_player.events.clear()
        young_teen_player.c.ageYears = 15
        event = bodySelfConsciousness(young_teen_player)
        assert event is None


class TestCurfewArgumentEvent:
    """Tests for curfew negotiation event"""

    @patch('random.random', return_value=0.0001)
    def test_curfew_argument_provides_four_options(self, mock_random, teen_player):
        """Test that curfew event provides four choices"""
        teen_player.c.ageYears = 15

        event = curfewArgument(teen_player)

        assert event is not None
        assert isinstance(event, questionEvent)
        assert len(event.answers) == 4

    @patch('random.random', return_value=0.0001)
    def test_curfew_following_rules_reduces_happiness_and_social(self, mock_random, teen_player):
        """Test that following rules reduces happiness and social"""
        teen_player.c.ageYears = 15
        initial_happiness = teen_player.c.happiness
        initial_social = teen_player.c.social

        event = curfewArgument(teen_player)

        # Choose option 0 (follow rules)
        response = {'option': event.answers[0].option}
        curfewArgument(teen_player, type='answer', response=response)

        assert teen_player.c.happiness < initial_happiness
        assert teen_player.c.social < initial_social

    @patch('random.random', return_value=0.0001)
    def test_curfew_negotiation_increases_happiness(self, mock_random, teen_player):
        """Test that successful negotiation increases happiness"""
        teen_player.c.ageYears = 15
        initial_happiness = teen_player.c.happiness

        event = curfewArgument(teen_player)

        # Choose option 2 (negotiate)
        response = {'option': event.answers[2].option}
        curfewArgument(teen_player, type='answer', response=response)

        assert teen_player.c.happiness > initial_happiness

    def test_curfew_argument_age_range(self, teen_player):
        """Test that curfew argument only triggers ages 14-17"""
        # Age 13 - too young
        teen_player.c.ageYears = 13
        event = curfewArgument(teen_player)
        assert event is None

        # Age 18 - too old
        teen_player.askedQuestions.clear()
        teen_player.c.ageYears = 18
        event = curfewArgument(teen_player)
        assert event is None


class TestGrowthSpurtEvent:
    """Tests for growth spurt event"""

    @patch('random.random', return_value=0.0001)
    def test_growth_spurt_triggers(self, mock_random, young_teen_player):
        """Test that growth spurt event triggers"""
        young_teen_player.c.ageYears = 13

        event = growthSpurt(young_teen_player)

        assert event is not None
        assert isinstance(event, messageEvent)
        assert 'grew' in event.message.lower() or 'inch' in event.message.lower()

    def test_growth_spurt_age_range(self, young_teen_player):
        """Test that growth spurt only triggers ages 12-15"""
        # Age 11 - too young
        young_teen_player.c.ageYears = 11
        event = growthSpurt(young_teen_player)
        assert event is None

        # Age 16 - too old
        young_teen_player.events.clear()
        young_teen_player.c.ageYears = 16
        event = growthSpurt(young_teen_player)
        assert event is None


class TestEmbarrassingSituationEvent:
    """Tests for embarrassing situation event"""

    @patch('random.random', return_value=0.0001)
    def test_embarrassing_situation_triggers(self, mock_random, teen_player):
        """Test that embarrassing situation event triggers"""
        teen_player.c.ageYears = 15

        event = embarrassingSituation(teen_player)

        assert event is not None
        assert isinstance(event, messageEvent)
        # Message should be one of the embarrassing scenarios
        assert len(event.message) > 0

    def test_embarrassing_situation_age_range(self, teen_player):
        """Test that embarrassing situation only triggers ages 13-17"""
        # Age 12 - too young
        teen_player.c.ageYears = 12
        event = embarrassingSituation(teen_player)
        assert event is None

        # Age 18 - too old
        teen_player.events.clear()
        teen_player.c.ageYears = 18
        event = embarrassingSituation(teen_player)
        assert event is None


class TestSleepoverEvent:
    """Tests for sleepover event"""

    @patch('random.random', return_value=0.0001)
    def test_sleepover_provides_four_options(self, mock_random, young_teen_player):
        """Test that sleepover provides four truth-or-dare choices"""
        young_teen_player.c.ageYears = 13

        event = sleepover(young_teen_player)

        assert event is not None
        assert isinstance(event, questionEvent)
        assert len(event.answers) == 4

    @patch('random.random', return_value=0.0001)
    def test_sleepover_truth_increases_social(self, mock_random, young_teen_player):
        """Test that picking truth increases social"""
        young_teen_player.c.ageYears = 13
        initial_social = young_teen_player.c.social

        event = sleepover(young_teen_player)

        # Choose option 0 (truth)
        response = {'option': event.answers[0].option}
        sleepover(young_teen_player, type='answer', response=response)

        assert young_teen_player.c.social > initial_social

    @patch('random.random', return_value=0.0001)
    def test_sleepover_dare_increases_social_more(self, mock_random, young_teen_player):
        """Test that picking dare increases social more than truth"""
        young_teen_player.c.ageYears = 13
        initial_social = young_teen_player.c.social

        event = sleepover(young_teen_player)

        # Choose option 1 (dare)
        response = {'option': event.answers[1].option}
        sleepover(young_teen_player, type='answer', response=response)

        # Dare gives +10 vs truth's +5
        assert young_teen_player.c.social >= initial_social + 10

    @patch('random.random', return_value=0.0001)
    def test_sleepover_pretend_sleep_reduces_social_and_happiness(self, mock_random, young_teen_player):
        """Test that pretending to sleep reduces social and happiness"""
        young_teen_player.c.ageYears = 13
        initial_social = young_teen_player.c.social
        initial_happiness = young_teen_player.c.happiness

        event = sleepover(young_teen_player)

        # Choose option 2 (pretend to sleep)
        response = {'option': event.answers[2].option}
        sleepover(young_teen_player, type='answer', response=response)

        assert young_teen_player.c.social < initial_social
        assert young_teen_player.c.happiness < initial_happiness


class TestSocialMediaPressureEvent:
    """Tests for social media decision event"""

    @patch('random.random', return_value=0.0001)
    def test_social_media_pressure_provides_three_options(self, mock_random, young_teen_player):
        """Test that social media event provides three choices"""
        young_teen_player.c.ageYears = 12

        event = socialMediaPressure(young_teen_player)

        assert event is not None
        assert isinstance(event, questionEvent)
        assert len(event.answers) == 3

    @patch('random.random', return_value=0.0001)
    def test_social_media_yes_sets_flag_and_increases_stats(self, mock_random, young_teen_player):
        """Test that making public account sets flag and increases stats"""
        young_teen_player.c.ageYears = 12
        initial_social = young_teen_player.c.social

        event = socialMediaPressure(young_teen_player)

        # Choose option 0 (make account)
        response = {'option': event.answers[0].option}
        socialMediaPressure(young_teen_player, type='answer', response=response)

        assert young_teen_player.c.hasSocialMedia is True
        assert young_teen_player.c.social > initial_social

    @patch('random.random', return_value=0.0001)
    def test_social_media_no_increases_happiness(self, mock_random, young_teen_player):
        """Test that declining social media increases happiness"""
        young_teen_player.c.ageYears = 12
        initial_happiness = young_teen_player.c.happiness

        event = socialMediaPressure(young_teen_player)

        # Choose option 1 (no)
        response = {'option': event.answers[1].option}
        socialMediaPressure(young_teen_player, type='answer', response=response)

        assert young_teen_player.c.happiness > initial_happiness
        assert not hasattr(young_teen_player.c, 'hasSocialMedia') or not young_teen_player.c.hasSocialMedia

    @patch('random.random', return_value=0.0001)
    def test_social_media_private_account_sets_flag(self, mock_random, young_teen_player):
        """Test that making private account sets flag"""
        young_teen_player.c.ageYears = 12

        event = socialMediaPressure(young_teen_player)

        # Choose option 2 (private account)
        response = {'option': event.answers[2].option}
        socialMediaPressure(young_teen_player, type='answer', response=response)

        assert young_teen_player.c.hasSocialMedia is True


class TestFashionExperimentationEvent:
    """Tests for fashion experimentation event"""

    @patch('random.random', return_value=0.0001)
    def test_fashion_experimentation_provides_four_options(self, mock_random, teen_player):
        """Test that fashion event provides four style choices"""
        teen_player.c.ageYears = 15

        event = fashionExperimentation(teen_player)

        assert event is not None
        assert isinstance(event, questionEvent)
        assert len(event.answers) == 4

    @patch('random.random', return_value=0.0001)
    def test_fashion_change_increases_social(self, mock_random, teen_player):
        """Test that changing style increases social"""
        teen_player.c.ageYears = 15
        initial_social = teen_player.c.social

        event = fashionExperimentation(teen_player)

        # Choose option 0 (edgy)
        response = {'option': event.answers[0].option}
        fashionExperimentation(teen_player, type='answer', response=response)

        assert teen_player.c.social > initial_social

    @patch('random.random', return_value=0.0001)
    def test_fashion_stay_same_reduces_happiness(self, mock_random, teen_player):
        """Test that staying the same reduces happiness"""
        teen_player.c.ageYears = 15
        initial_happiness = teen_player.c.happiness

        event = fashionExperimentation(teen_player)

        # Choose option 3 (stay same)
        response = {'option': event.answers[3].option}
        fashionExperimentation(teen_player, type='answer', response=response)

        assert teen_player.c.happiness < initial_happiness


class TestLearningToDriveEvent:
    """Tests for learning to drive event"""

    @patch('random.random', return_value=0.00001)
    def test_learning_to_drive_triggers(self, mock_random, teen_player):
        """Test that learning to drive event triggers"""
        teen_player.c.ageYears = 16

        event = learningToDrive(teen_player)

        assert event is not None
        assert isinstance(event, messageEvent)
        assert 'driving' in event.message.lower() or 'parking lot' in event.message.lower()

    def test_learning_to_drive_age_range(self, teen_player):
        """Test that learning to drive only triggers ages 15-16"""
        # Age 14 - too young
        teen_player.c.ageYears = 14
        event = learningToDrive(teen_player)
        assert event is None

        # Age 17 - too old
        teen_player.events.clear()
        teen_player.c.ageYears = 17
        event = learningToDrive(teen_player)
        assert event is None

    @patch('random.random', return_value=0.00001)
    def test_learning_to_drive_not_duplicate(self, mock_random, teen_player):
        """Test that learning to drive doesn't trigger twice"""
        teen_player.c.ageYears = 16
        teen_player.events.add('learningToDrive')

        event = learningToDrive(teen_player)

        assert event is None


# ============================================================================
# SUMMARY STATS
# ============================================================================

def test_summary():
    """
    Summary of adolescence events tested:

    PUBERTY EVENTS (4 events, 8 tests):
    - puberty: General puberty start (age 12)
    - startedPeriod: First period for females (ages 10-14)
    - braces: Getting braces (ages 7-19)
    - glasses: Getting glasses (ages 7-19)

    SOCIAL EVENTS (5 events, 15 tests):
    - firstCrush: First romantic crush (ages 10-12, sets sexual orientation)
    - firstKiss: First kiss decision (age 13+, 3 choices)
    - dating_choice: Asking someone out (age 13+, affinity-based)
    - romanticDate: Romantic date activities (ages 16-18, costs money/energy)
    - newFriend: Making friends at school (ages 4-22, at school)

    LIFE EVENTS (10 events, 27 tests):
    - groupProjectDrama: Dealing with lazy group partners (ages 12-18, students)
    - voiceCracking: Voice changes during puberty (males, ages 12-14)
    - bodySelfConsciousness: Physical appearance awareness (ages 11-14)
    - curfewArgument: Negotiating curfew (ages 14-17)
    - growthSpurt: Rapid growth (ages 12-15)
    - embarrassingSituation: Random embarrassing moments (ages 13-17)
    - sleepover: Truth or dare at sleepover (ages 12-15)
    - socialMediaPressure: Deciding on social media (ages 11-14)
    - fashionExperimentation: Trying new styles (ages 13-17)
    - learningToDrive: First time driving (ages 15-16)

    TOTAL: 19 events, 50+ test cases

    Test coverage includes:
    - Age-appropriate triggering
    - Gender-specific events
    - Condition requirements (student, location, relationships)
    - Duplicate prevention
    - Stat impacts (happiness, social, energy, money)
    - Multiple answer paths and consequences
    - Cost application (energy, money, diamonds)
    """
    assert True
