"""
Integration tests for event chain sequences.

Tests complex multi-step event sequences including education chains, career
progression, romance milestones, health events, and dilemma progression.

Run with: pytest tests/integration/test_event_chains.py -v
"""

import pytest
import asyncio
from ws.game_engine import GameEngine
from ws.character.character_manager import create_character
from ws.education.education_manager import setEducation
from ws.jobs.job_manager import setJob
from ws.relationships.relationship_manager import updateAffinity, romance
from ws.config import config


class TestEventChains:
    """
    Test multi-step event sequences and chains.

    These integration tests verify that complex event sequences trigger
    in the correct order and produce expected outcomes.
    """

    @pytest.mark.asyncio
    async def test_education_event_chain(
        self, child_player, game_engine, mock_output
    ):
        """
        Test complete education chain: Enrollment → Classes → Exams → Graduation.

        Arrange: Child ready for school
        Act: Simulate school enrollment through graduation
        Assert: All education milestones trigger in sequence
        """
        player = child_player
        player.c.ageYears = 5
        player.c.ageDays = 5 * 365
        player.c.ageHours = 5 * 365 * 24

        # Enroll in elementary school
        setEducation(player.c, "elementary_school")
        assert player.c.occupation == "elementary_school"

        player.gameSpeed = 1

        # Simulate school year (180 days)
        for _ in range(180 * 24):
            player = await game_engine.run_game_tick(player, force_update=True)

        # Education should be progressing
        assert player.c.occupation == "elementary_school"

        # Check that education events occurred
        events = mock_output.get_events()
        # Events may include school-related activities

    @pytest.mark.asyncio
    async def test_career_event_chain(
        self, adult_player, game_engine, mock_output
    ):
        """
        Test career chain: Job application → Hire → Promotion → Retirement.

        Arrange: Adult ready for work
        Act: Simulate career progression
        Assert: Career milestones occur in order
        """
        player = adult_player
        player.c.ageYears = 22
        player.c.ageDays = 22 * 365
        player.c.ageHours = 22 * 365 * 24
        player.c.occupation = "unemployed"

        initial_money = player.c.money

        # Get hired
        setJob(player.c, "Professional")
        assert player.c.occupation == "professional"

        player.gameSpeed = 1

        # Simulate first month of work
        for _ in range(30 * 24):
            player = await game_engine.run_game_tick(player, force_update=True)

        # Should have received salary payments
        # Money may have changed due to salary and expenses

        # Job should still be active
        assert player.c.occupation != "unemployed"

    @pytest.mark.asyncio
    async def test_romance_event_chain(
        self, adult_player, game_engine, mock_output
    ):
        """
        Test romance chain: Meet → Date → Relationship → Marriage → Children.

        Arrange: Adult ready for relationship
        Act: Simulate relationship progression
        Assert: Romance milestones occur in sequence
        """
        from ws.relationships.relationship_manager import getActiveRelationship
        from ws.character.character_manager import add_child

        player = adult_player

        # Create potential partner
        partner = create_character(player, "Partner", 30, "Male")
        player.r.append(partner)

        # Stage 1: Meet (low affinity)
        updateAffinity(player, player.c, partner, 30)
        initial_affinity = 30

        player.gameSpeed = 1

        # Stage 2: Date (increase affinity)
        updateAffinity(player, player.c, partner, 40)  # Total 70

        # Stage 3: Relationship
        romance(player, player.c, partner)

        # Verify relationship started
        active_rel = getActiveRelationship(player, player.c)
        assert active_rel is not None

        # Simulate relationship time
        for _ in range(90 * 24):  # 3 months
            player = await game_engine.run_game_tick(player, force_update=True)

        # Relationship should still be active
        assert getActiveRelationship(player, player.c) is not None

        # Stage 4: Marriage (future feature - may not be implemented)
        # Stage 5: Children
        # add_child(player, player.c, partner)
        # Child count would increase

    @pytest.mark.asyncio
    async def test_health_event_chain(
        self, adult_player, game_engine, mock_output
    ):
        """
        Test health chain: Develop habit → Health decline → Treatment → Recovery.

        Arrange: Adult character
        Act: Develop bad habit, simulate health impact, recover
        Assert: Health events trigger in sequence
        """
        from ws.health.health_manager import setHabits, quitHabit

        player = adult_player
        initial_health = player.c.health

        # Stage 1: Develop bad habit
        setHabits(player.c, "smoking")
        assert "smoking" in [h.name for h in player.c.habits]

        player.gameSpeed = 1

        # Stage 2: Simulate health decline
        for _ in range(30 * 24):  # 1 month
            player = await game_engine.run_game_tick(player, force_update=True)

        # Habit should affect health over time
        # (depends on handleHabitChanges implementation)

        # Stage 3: Treatment - quit habit
        quitHabit(player.c, "smoking")

        # Stage 4: Recovery
        for _ in range(30 * 24):  # 1 month recovery
            player = await game_engine.run_game_tick(player, force_update=True)

        # Health events should have occurred
        events = mock_output.get_events()

    @pytest.mark.asyncio
    async def test_dilemma_multi_step_progression(
        self, adult_player, game_engine, mock_output
    ):
        """
        Test dilemma progression: Part 1 → Part 2 → Resolution.

        Arrange: Player eligible for dilemma
        Act: Trigger dilemma, make choices
        Assert: Dilemma progresses through all steps
        """
        player = adult_player
        player.gameSpeed = 1

        # Simulate until a dilemma might trigger
        for _ in range(7 * 24):  # 1 week
            player = await game_engine.run_game_tick(player, force_update=True)

        # Check if any dilemmas were triggered
        # (depends on dilemma conditions)
        assert player.activeDilemmas is not None

    @pytest.mark.asyncio
    async def test_tutorial_event_sequence(
        self, newborn_player, game_engine, mock_output
    ):
        """
        Test tutorial events trigger in correct order.

        Arrange: New player
        Act: Simulate early game
        Assert: Tutorial events occur sequentially
        """
        player = newborn_player
        player.gameSpeed = 1

        # Clear existing events to track tutorial
        player.events.clear()
        mock_output.clear()

        # Simulate first few days
        for _ in range(3 * 24):  # 3 days
            player = await game_engine.run_game_tick(player, force_update=True)

        # Tutorial messages should have been sent
        events = mock_output.get_events()
        # Events may include tutorial or first-day messages

    @pytest.mark.asyncio
    async def test_birthday_event_chain(
        self, child_player, game_engine, mock_output
    ):
        """
        Test birthday chain: Birthday → Party → Gifts → Aging.

        Arrange: Child approaching birthday
        Act: Simulate through birthday
        Assert: Birthday events occur in sequence
        """
        player = child_player
        player.c.ageYears = 8
        player.c.ageDays = 8 * 365 - 1  # 1 day before birthday
        player.c.ageHours = (8 * 365 - 1) * 24

        initial_age = player.c.ageYears

        player.gameSpeed = 1
        mock_output.clear()

        # Simulate 2 days (through birthday)
        for _ in range(2 * 24):
            player = await game_engine.run_game_tick(player, force_update=True)

        # Age should have incremented
        # (exact timing depends on birthday calculation)

        # Birthday events should have triggered
        events = mock_output.get_events()

    @pytest.mark.asyncio
    async def test_graduation_event_chain(
        self, teen_player, game_engine, mock_output
    ):
        """
        Test graduation chain: Final exam → Graduation → Celebration.

        Arrange: Teen in final year of high school
        Act: Simulate to graduation
        Assert: Graduation events trigger
        """
        player = teen_player
        player.c.ageYears = 18
        player.c.ageDays = 18 * 365
        player.c.ageHours = 18 * 365 * 24
        player.c.occupation = "high_school"

        player.gameSpeed = 1
        mock_output.clear()

        # Simulate graduation period (end of school year)
        # School typically ends around day 152 (late May)
        player.dayOfYear = 150

        for _ in range(30 * 24):  # 1 month
            player = await game_engine.run_game_tick(player, force_update=True)

        # Graduation-related events may have occurred
        events = mock_output.get_events()

    @pytest.mark.asyncio
    async def test_job_promotion_chain(
        self, adult_player, game_engine, mock_output
    ):
        """
        Test promotion chain: Good performance → Promotion offer → Salary increase.

        Arrange: Adult in job
        Act: Simulate good performance period
        Assert: Promotion events trigger
        """
        from ws.jobs.job_manager import handleJob

        player = adult_player
        setJob(player.c, "Professional")

        initial_occupation = player.c.occupation
        initial_money = player.c.money

        player.gameSpeed = 1

        # Simulate 1 year of work
        for _ in range(365 * 24):
            player = await game_engine.run_game_tick(player, force_update=True)

        # Job should still exist
        assert player.c.occupation != "unemployed"

        # Money should have changed due to salary
        # (actual promotion depends on performance metrics)

    @pytest.mark.asyncio
    async def test_relationship_milestone_chain(
        self, adult_player, game_engine, mock_output
    ):
        """
        Test relationship milestones: Dating → Engagement → Wedding → Anniversary.

        Arrange: Adult in relationship
        Act: Simulate relationship over time
        Assert: Milestones trigger at appropriate times
        """
        from ws.relationships.relationship_manager import getActiveRelationship

        player = adult_player

        # Create partner
        partner = create_character(player, "Partner", 30, "Male")
        player.r.append(partner)

        # Start relationship
        updateAffinity(player, player.c, partner, 80)
        romance(player, player.c, partner)

        # Verify relationship started
        assert getActiveRelationship(player, player.c) is not None

        relationship_start = player.c.ageDays

        player.gameSpeed = 1
        mock_output.clear()

        # Simulate 1 year together
        for _ in range(365 * 24):
            player = await game_engine.run_game_tick(player, force_update=True)

        # Relationship should have progressed
        relationship_duration = player.c.ageDays - relationship_start

        # Relationship milestone events may have occurred
        events = mock_output.get_events()

        # Relationship should still be active
        assert getActiveRelationship(player, player.c) is not None
