"""Test player factories"""
import pytest
import sys
import os
from pathlib import Path
from datetime import datetime
from unittest.mock import patch

# Add ws/ to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

# Enable test mode to use mock data for database calls
os.environ['BAOLIFE_TEST_MODE'] = 'true'

from functions import playerClass, personClass


# Factory functions (callable directly in tests)
def _add_test_occupations(player):
    """Add test occupations with proper structure to player"""
    from jobs.job_manager import OccupationClass, JobLevel

    # Create proper mock occupations with levels
    test_occupation = OccupationClass(
        title='Test Job',
        description='A test job for testing',
        shifts='Day shift',
        requirements='none',
        levels=[
            JobLevel('Junior Test Worker', 2000, 30),
            JobLevel('Senior Test Worker', 3000, 40)
        ]
    )

    teacher_occupation = OccupationClass(
        title='Elementary School Teacher',
        description='Teaches elementary school',
        shifts='Day shift',
        requirements='bachelors_degree',
        levels=[
            JobLevel('Teacher', 3000, 40),
            JobLevel('Senior Teacher', 4000, 50)
        ]
    )

    software_engineer = OccupationClass(
        title='Software Engineer',
        description='Develops software applications',
        shifts='Day shift',
        requirements='bachelors_degree',
        levels=[
            JobLevel('Junior Software Engineer', 4000, 40),
            JobLevel('Software Engineer', 6000, 50),
            JobLevel('Senior Software Engineer', 8000, 60)
        ]
    )

    player.occupations = [test_occupation, teacher_occupation, software_engineer]
    return player


def create_newborn_player():
    """Create player with newborn character"""
    player = playerClass()
    player.userID = 'test_user_newborn'
    player.c.firstname = 'Test'
    player.c.lastname = 'Baby'
    player.c.sex = 'Male'
    player.c.ageYears = 0
    player.c.ageDays = 0
    player.c.ageHours = 0
    player.c.birthday = datetime.now().strftime("%m-%d")
    player.date = datetime.now().strftime("%m-%d")
    player.hourOfDay = 0
    player.minuteOfHour = 0
    player.controller = 'active'
    _add_test_occupations(player)
    return player


def create_student_player(age_years=16, grade='High School'):
    """Create player with high school student"""
    player = playerClass()
    player.userID = 'test_user_student'
    player.c.firstname = 'Test'
    player.c.lastname = 'Student'
    player.c.sex = 'Female'
    player.c.ageYears = age_years
    player.c.ageDays = age_years * 365
    player.c.ageHours = age_years * 365 * 24
    player.c.occupation = 'student'
    player.c.education = grade
    if hasattr(player.c, 'grade'):
        if age_years >= 14 and age_years <= 18:
            player.c.grade = age_years - 5  # Approximate grade from age
        else:
            player.c.grade = 11
    # Add schedules for students
    player.c.schedules = [
        {'activity': 'school', 'start': 8, 'end': 15, 'days': [0, 1, 2, 3, 4]}
    ]
    player.date = '09-15'
    player.hourOfDay = 8
    player.minuteOfHour = 0
    player.controller = 'active'
    _add_test_occupations(player)
    return player


def create_child_player(age_years=8, user_id=None, firstname='Child'):
    """Create player with child character (ages 1-12)"""
    player = playerClass()
    player.userID = user_id or f'test_user_child_{age_years}'
    player.c.firstname = firstname
    player.c.lastname = 'TestChild'
    player.c.sex = 'Male'
    player.c.ageYears = age_years
    player.c.ageDays = age_years * 365
    player.c.ageHours = player.c.ageDays * 24
    player.c.birthday = datetime.now().strftime("%m-%d")
    player.date = datetime.now().strftime("%m-%d")
    player.hourOfDay = 8
    player.minuteOfHour = 0
    player.controller = 'active'

    # Child-specific properties
    if age_years >= 5:
        player.c.occupation = 'elementary school'
        player.c.education = 'Elementary School'

    _add_test_occupations(player)
    return player


def create_teen_player(age_years=15, user_id=None, firstname='Teen'):
    """Create player with teen character (ages 13-18)"""
    player = playerClass()
    player.userID = user_id or f'test_user_teen_{age_years}'
    player.c.firstname = firstname
    player.c.lastname = 'TestTeen'
    player.c.sex = 'Female'
    player.c.ageYears = age_years
    player.c.ageDays = age_years * 365
    player.c.ageHours = player.c.ageDays * 24
    player.c.occupation = 'student'
    player.c.education = 'High School'
    player.date = '09-15'
    player.hourOfDay = 8
    player.minuteOfHour = 0
    player.controller = 'active'
    _add_test_occupations(player)
    return player


def create_adult_player(age_years=30, user_id=None, firstname='Adult', occupation='Software Developer'):
    """Create player with working adult (ages 19-64)"""
    player = playerClass()
    player.userID = user_id or f'test_user_adult_{age_years}'
    player.c.firstname = firstname
    player.c.lastname = 'TestAdult'
    player.c.sex = 'Male'
    player.c.ageYears = age_years
    player.c.ageDays = age_years * 365
    player.c.ageHours = player.c.ageDays * 24
    player.c.occupation = occupation
    player.c.education = 'Bachelor'
    player.c.money = 50000
    player.date = '06-15'
    player.hourOfDay = 9
    player.minuteOfHour = 0
    player.controller = 'active'
    _add_test_occupations(player)
    return player


def create_elderly_player(age_years=70, user_id=None, firstname='Elder'):
    """Create player with elderly character (ages 65+)"""
    player = playerClass()
    player.userID = user_id or f'test_user_elder_{age_years}'
    player.c.firstname = firstname
    player.c.lastname = 'TestElder'
    player.c.sex = 'Male'
    player.c.ageYears = age_years
    player.c.ageDays = age_years * 365
    player.c.ageHours = player.c.ageDays * 24
    player.c.occupation = 'Retired'
    player.c.education = 'Bachelor'
    player.c.money = 100000
    player.date = '06-15'
    player.hourOfDay = 9
    player.minuteOfHour = 0
    player.controller = 'active'
    _add_test_occupations(player)
    return player


def create_player_with_relationships(user_id=None, num_friends=3, has_family=False):
    """Create player with relationships"""
    player = create_adult_player(user_id=user_id)

    # Add friends
    for i in range(num_friends):
        friend = personClass()
        friend.firstname = f'Friend{i+1}'
        friend.lastname = 'Test'
        friend.sex = 'Male' if i % 2 == 0 else 'Female'
        friend.ageYears = player.c.ageYears + (i - num_friends//2)
        friend.ageDays = friend.ageYears * 365
        friend.relationships = ['friend']
        friend.title = 'Friend'
        friend.affinity = 60 + i * 5
        friend.familiarity = 70
        player.r.append(friend)

    # Add family if requested
    if has_family:
        # Add parents
        mother = personClass()
        mother.firstname = 'Mother'
        mother.sex = 'Female'
        mother.ageYears = player.c.ageYears + 30
        mother.ageDays = mother.ageYears * 365
        mother.relationships = ['mother']
        mother.title = 'Mother'
        mother.affinity = 90
        mother.familiarity = 100
        player.r.append(mother)

        father = personClass()
        father.firstname = 'Father'
        father.sex = 'Male'
        father.ageYears = player.c.ageYears + 32
        father.ageDays = father.ageYears * 365
        father.relationships = ['father']
        father.title = 'Father'
        father.affinity = 85
        father.familiarity = 100
        player.r.append(father)

    return player


def create_player_with_partner(user_id=None, age_years=28, married=False):
    """Create player with romantic partner"""
    player = create_adult_player(age_years=age_years, user_id=user_id)

    partner = personClass()
    partner.firstname = 'Partner'
    partner.sex = 'Female' if player.c.sex == 'Male' else 'Male'
    partner.ageYears = age_years - 1
    partner.ageDays = partner.ageYears * 365
    partner.relationships = ['spouse' if married else 'dating']
    partner.title = 'Spouse' if married else 'Partner'
    partner.affinity = 95
    partner.familiarity = 90
    player.r.append(partner)

    return player


def add_test_locations(player):
    """Add common test locations to player"""
    from functions import locationClass

    # Home
    home = locationClass('home', 'residence')
    home.description = 'Test Home'
    player.l.append(home)

    # Work
    work = locationClass('work', 'office')
    work.description = 'Test Office'
    player.l.append(work)

    # School
    school = locationClass('school', 'school')
    school.description = 'Test School'
    player.l.append(school)

    return player


def set_player_stats(player, energy=100, happiness=75, stress=25, money=None):
    """Set player stats to specific values"""
    player.c.energy = energy
    if hasattr(player.c, 'happiness'):
        player.c.happiness = happiness
    if hasattr(player.c, 'mood'):
        player.c.mood = happiness
    if hasattr(player.c, 'stress'):
        player.c.stress = stress
    if money is not None:
        player.c.money = money
    return player


# Pytest fixtures (for use as test parameters)
@pytest.fixture
def newborn_player():
    """Fixture that returns a newborn player"""
    return create_newborn_player()


@pytest.fixture
def student_player():
    """Fixture that returns a student player"""
    return create_student_player()


@pytest.fixture
def adult_player():
    """Fixture that returns an adult player"""
    return create_adult_player()
