"""
Unit tests for tutorial events system.

Tests tutorial mode detection, event generation, and modifications.
"""
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))

import pytest
from unittest.mock import Mock, patch
from types import SimpleNamespace


def create_test_player(age_hours=0):
    """Create a test player with specified age in hours"""
    # Create a mock player without importing functions.py
    # This avoids database connection issues in unit tests

    player = SimpleNamespace()
    player.c = SimpleNamespace()
    player.c.firstname = 'TestUser'
    player.c.lastname = 'Tutorial'
    player.c.sex = 'Male'
    player.c.ageYears = age_hours // 24 // 365
    player.c.ageDays = age_hours // 24
    player.c.ageHours = age_hours
    player.c.status = 'alive'
    player.c.energy = 100
    player.c.happiness = 50
    player.c.diamonds = 0
    player.c.intelligence = 50
    player.c.health = 50
    player.c.id = 'test_player_1'
    player.events = set()
    player.askedQuestions = set()
    player.messageQueue = []
    player.r = []  # Relationships
    player.gameSpeed = 10000
    player.previousGameSpeed = 10000
    player.date = '01-01'
    player.hourOfDay = 0

    return player


def create_test_npc(npc_id='npc1', firstname='Bob', affinity=50):
    """Create a test NPC"""
    npc = SimpleNamespace()
    npc.id = npc_id
    npc.firstname = firstname
    npc.affinity = affinity
    npc.status = 'alive'
    return npc


class TestTutorialMode:
    """Tests for tutorial mode detection."""

    def test_is_tutorial_mode_with_game_hours(self):
        """Test checking if player is in tutorial mode using game hours parameter."""
        from tutorial_events import is_tutorial_mode

        player = create_test_player()

        # First 24 in-game hours = tutorial mode
        assert is_tutorial_mode(player, game_hours=5) is True
        assert is_tutorial_mode(player, game_hours=23) is True
        assert is_tutorial_mode(player, game_hours=24) is False
        assert is_tutorial_mode(player, game_hours=25) is False

    def test_is_tutorial_mode_new_player(self):
        """Test that brand new player is in tutorial mode."""
        from tutorial_events import is_tutorial_mode

        player = create_test_player(age_hours=0)
        assert is_tutorial_mode(player) is True

    def test_is_tutorial_mode_after_24_hours(self):
        """Test that player exits tutorial mode after 24 hours."""
        from tutorial_events import is_tutorial_mode

        player = create_test_player(age_hours=24)
        assert is_tutorial_mode(player) is False

        player = create_test_player(age_hours=30)
        assert is_tutorial_mode(player) is False

    def test_is_tutorial_mode_during_tutorial(self):
        """Test that player is in tutorial mode during first 24 hours."""
        from tutorial_events import is_tutorial_mode

        player = create_test_player(age_hours=10)
        assert is_tutorial_mode(player) is True

        player = create_test_player(age_hours=23)
        assert is_tutorial_mode(player) is True


class TestWelcomeMessage:
    """Tests for welcome message generation."""

    def test_get_welcome_message(self):
        """Test getting welcome message for new player."""
        from tutorial_events import get_welcome_message

        player = create_test_player()
        player.c.firstname = 'Alice'

        event = get_welcome_message(player)

        assert event is not None
        assert event['type'] == 'tutorial_message'
        assert 'Alice' in event['message']
        assert 'Welcome' in event['message']
        assert event['character'] == 'system'
        assert event['dismissible'] is True

    def test_get_welcome_message_without_name(self):
        """Test welcome message with default name."""
        from tutorial_events import get_welcome_message

        player = create_test_player()
        player.c.firstname = None

        event = get_welcome_message(player)

        assert event is not None
        assert 'friend' in event['message']


class TestTutorialEventGeneration:
    """Tests for generating tutorial events."""

    def test_generate_tutorial_event_first_friend(self):
        """Test generating first friend tutorial event."""
        from tutorial_events import generate_tutorial_event

        player = create_test_player()

        # Add a friendly NPC
        npc = create_test_npc()
        player.r.append(npc)

        event = generate_tutorial_event(player, 'first_friend')

        assert event is not None
        assert event['type'] == 'tutorial_interaction'
        assert event['guaranteed_success'] is True
        assert event['reward_diamonds'] == 5
        assert event['affinity_bonus'] == 20
        assert 'tutorial_hint' in event

    def test_generate_tutorial_event_first_friend_no_npcs(self):
        """Test first friend event with no NPCs available."""
        from tutorial_events import generate_tutorial_event

        player = create_test_player()
        # No relationships

        event = generate_tutorial_event(player, 'first_friend')

        assert event is None

    def test_generate_tutorial_event_first_activity(self):
        """Test generating first activity tutorial event."""
        from tutorial_events import generate_tutorial_event

        player = create_test_player()

        event = generate_tutorial_event(player, 'first_activity')

        assert event is not None
        assert event['type'] == 'tutorial_activity_selection'
        assert event['simplified_choices'] is True
        assert len(event['choices']) == 3
        assert 'tutorial_hint' in event

    def test_generate_tutorial_event_first_purchase(self):
        """Test generating first purchase tutorial event."""
        from tutorial_events import generate_tutorial_event

        player = create_test_player()

        event = generate_tutorial_event(player, 'first_purchase')

        assert event is not None
        assert event['type'] == 'tutorial_store_visit'
        assert event['reward_diamonds'] == 10
        assert 'tutorial_hint' in event

    def test_generate_tutorial_event_first_class(self):
        """Test generating first class tutorial event."""
        from tutorial_events import generate_tutorial_event

        player = create_test_player()

        event = generate_tutorial_event(player, 'first_class')

        assert event is not None
        assert event['type'] == 'tutorial_class_result'
        assert event['guaranteed_good_grade'] is True
        assert event['grade'] == 'A'
        assert event['reward_diamonds'] == 5

    def test_generate_tutorial_event_unknown_type(self):
        """Test generating unknown event type returns None."""
        from tutorial_events import generate_tutorial_event

        player = create_test_player()

        event = generate_tutorial_event(player, 'unknown_event_type')

        assert event is None


class TestTutorialModifiers:
    """Tests for tutorial event modifiers."""

    def test_apply_tutorial_modifiers_reduces_difficulty(self):
        """Test that tutorial mode reduces event difficulty."""
        from tutorial_events import apply_tutorial_modifiers

        player = create_test_player(age_hours=10)

        event_data = {'difficulty': 5, 'type': 'test'}
        modified = apply_tutorial_modifiers(player, event_data)

        assert modified['difficulty'] == 3  # Reduced by 2

    def test_apply_tutorial_modifiers_increases_rewards(self):
        """Test that tutorial mode increases rewards."""
        from tutorial_events import apply_tutorial_modifiers

        player = create_test_player(age_hours=10)

        event_data = {
            'money_reward': 100,
            'diamonds_reward': 10,
            'type': 'test'
        }
        modified = apply_tutorial_modifiers(player, event_data)

        assert modified['money_reward'] == 150  # 1.5x
        assert modified['diamonds_reward'] == 15  # 1.5x

    def test_apply_tutorial_modifiers_reduces_costs(self):
        """Test that tutorial mode reduces energy costs."""
        from tutorial_events import apply_tutorial_modifiers

        player = create_test_player(age_hours=10)

        event_data = {'energyCost': 20, 'type': 'test'}
        modified = apply_tutorial_modifiers(player, event_data)

        assert modified['energyCost'] == 15  # 0.75x

    def test_apply_tutorial_modifiers_adds_hints(self):
        """Test that tutorial mode adds helpful hints."""
        from tutorial_events import apply_tutorial_modifiers

        player = create_test_player(age_hours=10)

        event_data = {'type': 'social'}
        modified = apply_tutorial_modifiers(player, event_data)

        assert 'tutorial_mode' in modified
        assert modified['tutorial_mode'] is True
        assert 'tutorial_hint' in modified
        assert len(modified['tutorial_hint']) > 0

    def test_apply_tutorial_modifiers_not_in_tutorial(self):
        """Test that modifiers don't apply outside tutorial mode."""
        from tutorial_events import apply_tutorial_modifiers

        player = create_test_player(age_hours=30)  # Past tutorial

        event_data = {'difficulty': 5, 'money_reward': 100}
        modified = apply_tutorial_modifiers(player, event_data)

        # Should be unchanged
        assert modified['difficulty'] == 5
        assert modified['money_reward'] == 100
        assert 'tutorial_mode' not in modified


class TestContextualHints:
    """Tests for contextual hint generation."""

    def test_get_contextual_hint_known_types(self):
        """Test getting hints for known event types."""
        from tutorial_events import get_contextual_hint

        hints = {
            'work': get_contextual_hint('work'),
            'school': get_contextual_hint('school'),
            'social': get_contextual_hint('social'),
            'health': get_contextual_hint('health'),
            'money': get_contextual_hint('money'),
        }

        for event_type, hint in hints.items():
            assert hint is not None
            assert len(hint) > 0
            assert isinstance(hint, str)

    def test_get_contextual_hint_unknown_type(self):
        """Test getting hint for unknown event type returns default."""
        from tutorial_events import get_contextual_hint

        hint = get_contextual_hint('unknown_type')

        assert hint is not None
        assert 'choices' in hint or 'goal' in hint


class TestTutorialEvents:
    """Tests for specific tutorial event functions."""

    def test_first_conversation_event(self):
        """Test first conversation tutorial event."""
        from tutorial_events import firstConversation

        player = create_test_player(age_hours=5)

        # Add a friendly NPC
        npc = create_test_npc(npc_id='npc1', firstname='Charlie')
        player.r.append(npc)

        event = firstConversation(player, type='message')

        assert event is not None
        assert event.type == 'questionEvent'
        assert 'Charlie' in event.message or 'smile' in event.message.lower()

    def test_first_conversation_answer(self):
        """Test answering first conversation event."""
        from tutorial_events import firstConversation

        player = create_test_player(age_hours=5)
        player.c.happiness = 50
        player.c.diamonds = 0

        response = {'option': 'Say hello!'}
        firstConversation(player, type='answer', response=response)

        assert player.c.happiness == 55  # Increased
        assert player.c.diamonds == 5  # Reward
        assert len(player.messageQueue) > 0

    def test_first_activity_choice_event(self):
        """Test first activity choice tutorial event."""
        from tutorial_events import firstActivityChoice

        player = create_test_player(age_hours=10)
        player.c.ageYears = 5

        event = firstActivityChoice(player, type='message')

        assert event is not None
        assert event.type == 'questionEvent'
        assert 'free time' in event.message.lower()

    def test_first_activity_choice_answer_study(self):
        """Test answering first activity with Study option."""
        from tutorial_events import firstActivityChoice

        player = create_test_player(age_hours=10)
        player.c.ageYears = 5
        player.c.intelligence = 50
        player.c.diamonds = 0

        response = {'option': 'Study (Gain Intelligence)'}
        firstActivityChoice(player, type='answer', response=response)

        assert player.c.intelligence == 60  # Increased by 10
        assert player.c.diamonds == 3  # Reward
        assert len(player.messageQueue) > 0

    def test_tutorial_complete_event(self):
        """Test tutorial completion event."""
        from tutorial_events import tutorialComplete

        player = create_test_player(age_hours=24)
        player.c.diamonds = 0

        event = tutorialComplete(player, type='message')

        assert event is not None
        assert event.type == 'messageEvent'
        assert '25 diamonds' in event.message.lower()

    def test_tutorial_complete_only_triggers_once(self):
        """Test that tutorial complete only triggers at 24 hours."""
        from tutorial_events import tutorialComplete

        # Before 24 hours
        player = create_test_player(age_hours=23)
        event = tutorialComplete(player, type='message')
        assert event is None

        # At 24 hours
        player = create_test_player(age_hours=24)
        event = tutorialComplete(player, type='message')
        assert event is not None

        # After 25 hours
        player = create_test_player(age_hours=26)
        event = tutorialComplete(player, type='message')
        assert event is None


class TestTutorialTriggers:
    """Tests for tutorial event trigger checking."""

    def test_check_tutorial_triggers_new_player(self):
        """Test checking triggers for new player."""
        from tutorial_events import check_tutorial_triggers

        player = create_test_player(age_hours=5)
        player.c.ageYears = 5

        # Add NPCs
        npc = create_test_npc()
        player.r.append(npc)

        triggers = check_tutorial_triggers(player)

        # Should have triggers for first conversation and first activity
        assert len(triggers) >= 2

    def test_check_tutorial_triggers_after_tutorial(self):
        """Test that no triggers fire after tutorial."""
        from tutorial_events import check_tutorial_triggers

        player = create_test_player(age_hours=30)

        triggers = check_tutorial_triggers(player)

        assert len(triggers) == 0

    def test_check_tutorial_triggers_respects_events(self):
        """Test that triggers respect already-fired events."""
        from tutorial_events import check_tutorial_triggers

        player = create_test_player(age_hours=5)
        player.events.add('firstConversation')

        npc = create_test_npc()
        player.r.append(npc)

        triggers = check_tutorial_triggers(player)

        # firstConversation should not be in triggers
        trigger_names = [f.__name__ for f in triggers]
        assert 'firstConversation' not in trigger_names
