"""
Test data factories for BaoLife.

This module provides factory functions for creating test data objects
with customizable attributes.
"""
from typing import Any, Dict, Optional, List
from datetime import datetime, timedelta
import random


def create_test_player(**kwargs) -> Any:
    """
    Factory for creating test players.

    Args:
        **kwargs: Player attributes to override

    Returns:
        playerClass: Test player object

    Example:
        player = create_test_player(userID='test_123', age=25)
    """
    from core.models import playerClass, personClass

    player = playerClass()

    # Set default values
    player.userID = kwargs.get('userID', f'test_user_{random.randint(1000, 9999)}')
    player.status = kwargs.get('status', 'active')
    player.controller = kwargs.get('controller', 'active')
    player.date = kwargs.get('date', datetime.now())
    player.hourOfDay = kwargs.get('hourOfDay', 0)
    player.minuteOfHour = kwargs.get('minuteOfHour', 0)
    player.ticks = kwargs.get('ticks', 0)
    player.gameSpeed = kwargs.get('gameSpeed', 100)

    # Create character if not provided
    if 'c' not in kwargs:
        player.c = create_test_person(**kwargs)
    else:
        player.c = kwargs['c']

    return player


def create_test_person(**kwargs) -> Any:
    """
    Factory for creating test characters/persons.

    Args:
        **kwargs: Person attributes to override

    Returns:
        personClass: Test person object

    Example:
        person = create_test_person(firstname='John', age=30)
    """
    from core.models import personClass

    person = personClass()

    # Set default values
    person.firstname = kwargs.get('firstname', 'Test')
    person.lastname = kwargs.get('lastname', 'Person')
    person.sex = kwargs.get('sex', 'Male')

    # Age-related attributes
    age = kwargs.get('age', 25)
    person.ageYears = age
    person.ageDays = age * 365
    person.ageHours = age * 365 * 24
    person.birthday = kwargs.get('birthday', datetime.now() - timedelta(days=age*365))

    # Stats
    person.energy = kwargs.get('energy', 100)
    person.hunger = kwargs.get('hunger', 0)
    person.happiness = kwargs.get('happiness', 75)
    person.mood = kwargs.get('mood', 'Neutral')
    person.money = kwargs.get('money', 1000)

    # Education and career
    person.education = kwargs.get('education', None)
    person.occupation = kwargs.get('occupation', None)

    # Diamonds (premium currency)
    if hasattr(person, 'diamonds'):
        person.diamonds = kwargs.get('diamonds', 0)

    return person


def create_test_relationship(**kwargs) -> Any:
    """
    Factory for creating test relationships.

    Args:
        **kwargs: Relationship attributes to override

    Returns:
        relationshipClass: Test relationship object

    Example:
        rel = create_test_relationship(affinity=80, relationshipType='friend')
    """
    from core.models import relationshipClass

    rel = relationshipClass()
    rel.personID = kwargs.get('personID', f'person_{random.randint(1000, 9999)}')
    rel.affinity = kwargs.get('affinity', 50)
    rel.relationshipType = kwargs.get('relationshipType', 'acquaintance')
    rel.metDate = kwargs.get('metDate', datetime.now())
    rel.lastInteraction = kwargs.get('lastInteraction', datetime.now())

    return rel


def create_test_event(**kwargs) -> Dict[str, Any]:
    """
    Factory for creating test event dictionaries.

    Args:
        **kwargs: Event attributes to override

    Returns:
        Dict: Test event data

    Example:
        event = create_test_event(title='Birthday Party', type='messageEvent')
    """
    event = {
        'id': kwargs.get('id', f'event_{random.randint(1000, 9999)}'),
        'type': kwargs.get('type', 'messageEvent'),
        'title': kwargs.get('title', 'Test Event'),
        'description': kwargs.get('description', 'Test event description'),
        'datetime': kwargs.get('datetime', datetime.now().isoformat()),
        'cost': kwargs.get('cost', 0),
        'reward': kwargs.get('reward', 0),
    }

    # Add optional fields
    if 'energyCost' in kwargs:
        event['energyCost'] = kwargs['energyCost']
    if 'happinessReward' in kwargs:
        event['happinessReward'] = kwargs['happinessReward']

    return event


def create_test_question(**kwargs) -> Dict[str, Any]:
    """
    Factory for creating test question events.

    Args:
        **kwargs: Question attributes to override

    Returns:
        Dict: Test question data

    Example:
        question = create_test_question(
            title='Choose',
            question='What do you want to do?',
            answers=['Option A', 'Option B']
        )
    """
    question = {
        'id': kwargs.get('id', f'question_{random.randint(1000, 9999)}'),
        'type': 'questionEvent',
        'title': kwargs.get('title', 'Test Question'),
        'question': kwargs.get('question', 'What do you choose?'),
        'answers': kwargs.get('answers', ['Yes', 'No']),
        'datetime': kwargs.get('datetime', datetime.now().isoformat()),
    }

    return question


def create_test_location(**kwargs) -> Any:
    """
    Factory for creating test locations.

    Args:
        **kwargs: Location attributes to override

    Returns:
        locationClass: Test location object

    Example:
        loc = create_test_location(id='home', type='residence')
    """
    from core.models import locationClass

    location = locationClass(
        id=kwargs.get('id', f'loc_{random.randint(1000, 9999)}'),
        type=kwargs.get('type', 'generic'),
        image=kwargs.get('image', None)
    )

    location.description = kwargs.get('description', 'Test location')
    location.people = kwargs.get('people', [])

    return location


def create_test_education_record(**kwargs) -> Any:
    """
    Factory for creating test education records.

    Args:
        **kwargs: Education record attributes to override

    Returns:
        EducationRecord: Test education record

    Example:
        edu = create_test_education_record(
            educationLevel='High School',
            GPA=3.5
        )
    """
    from core.models import EducationRecord, locationClass

    location = kwargs.get('location')
    if location is None:
        location = create_test_location(type='school')

    record = EducationRecord(
        educationLevel=kwargs.get('educationLevel', 'High School'),
        location=location,
        date=kwargs.get('date', datetime.now())
    )

    record.GPA = kwargs.get('GPA', 75)
    record.major = kwargs.get('major', None)
    record.minor = kwargs.get('minor', None)
    record.focus = kwargs.get('focus', 'Balanced')

    return record


def create_test_daily_event(**kwargs) -> Any:
    """
    Factory for creating test daily events.

    Args:
        **kwargs: Daily event attributes to override

    Returns:
        dailyEvent: Test daily event object

    Example:
        event = create_test_daily_event(time=8, title='School')
    """
    from core.models import dailyEvent, locationClass

    location = kwargs.get('location')
    if location is None:
        location = create_test_location()

    event = dailyEvent(
        time=kwargs.get('time', 8),
        location=location
    )

    event.title = kwargs.get('title', 'Test Event')
    event.name = kwargs.get('name', event.title)

    return event


def create_test_schedule(**kwargs) -> Any:
    """
    Factory for creating test schedules.

    Args:
        **kwargs: Schedule attributes to override

    Returns:
        scheduler: Test scheduler object

    Example:
        schedule = create_test_schedule(
            title='Work',
            time=9,
            days=[0,1,2,3,4]
        )
    """
    from core.models import scheduler, scheduleDays

    schedule = scheduler()
    schedule.title = kwargs.get('title', 'Test Schedule')
    schedule.time = kwargs.get('time', 9)

    # Create schedule days
    days = kwargs.get('days', [0, 1, 2, 3, 4, 5, 6])  # All days by default
    schedule.days = scheduleDays()
    for day in days:
        if day == 0:
            schedule.days.monday = True
        elif day == 1:
            schedule.days.tuesday = True
        elif day == 2:
            schedule.days.wednesday = True
        elif day == 3:
            schedule.days.thursday = True
        elif day == 4:
            schedule.days.friday = True
        elif day == 5:
            schedule.days.saturday = True
        elif day == 6:
            schedule.days.sunday = True

    return schedule


def create_player_at_age(age: int, **kwargs) -> Any:
    """
    Create a test player at a specific age with appropriate defaults.

    Args:
        age: Age of the character
        **kwargs: Additional attributes to override

    Returns:
        playerClass: Test player at specified age

    Example:
        teen = create_player_at_age(16)  # Creates teenage player
    """
    # Set age-appropriate defaults
    if age < 5:
        education = None
        occupation = None
        money = 0
    elif age < 14:
        education = 'Elementary School'
        occupation = 'student'
        money = 100
    elif age < 18:
        education = 'High School'
        occupation = 'student'
        money = 500
    elif age < 22:
        education = 'College'
        occupation = 'student'
        money = 1000
    else:
        education = kwargs.get('education', 'Bachelor')
        occupation = kwargs.get('occupation', 'Employee')
        money = kwargs.get('money', 10000)

    return create_test_player(
        age=age,
        education=education,
        occupation=occupation,
        money=money,
        **kwargs
    )


def create_player_with_family(age: int = 25, **kwargs) -> tuple:
    """
    Create a test player with a family.

    Args:
        age: Age of the player character
        **kwargs: Additional attributes for player

    Returns:
        tuple: (player, mother, father, siblings)

    Example:
        player, mom, dad, siblings = create_player_with_family(age=16)
    """
    player = create_player_at_age(age, **kwargs)

    # Create parents
    mother = create_test_person(
        firstname='Mother',
        sex='Female',
        age=player.c.ageYears + 30
    )

    father = create_test_person(
        firstname='Father',
        sex='Male',
        age=player.c.ageYears + 32
    )

    # Create sibling
    sibling = create_test_person(
        firstname='Sibling',
        sex='Female',
        age=max(5, player.c.ageYears - 3)
    )

    siblings = [sibling]

    # Add family members to player's relationships
    player.r = [mother, father, sibling]

    return player, mother, father, siblings


def batch_create_players(count: int, **kwargs) -> List[Any]:
    """
    Create multiple test players.

    Args:
        count: Number of players to create
        **kwargs: Common attributes for all players

    Returns:
        List: List of player objects

    Example:
        players = batch_create_players(10, age=25)
    """
    return [create_test_player(**kwargs) for _ in range(count)]
