#!/usr/bin/env python
"""
Character Manager Module

This module contains all character creation and management functions for BaoLife.
Extracted from functions.py to improve code organization and maintainability.

Functions in this module handle:
- Character creation (players, NPCs, family members, friends, classmates, coworkers)
- Character data retrieval and manipulation
- Relationship management
- Avatar generation
- Bio and description generation
"""

import datetime
import random
import uuid
from datetime import timedelta


# ============================================================
# Character Description Functions
# ============================================================

def getPersonDescription(person):
    """
    Generate a human-readable description of a person based on their attributes.

    Args:
        person: personClass instance

    Returns:
        str: Formatted description of the person
    """
    description = f"{person.firstname} {person.lastname} is a {person.sex.lower()}."

    for i in person.relationships:
        description += f" They are your {i}. "

    if person.familiarity > 0:
        if hasattr(person, 'ageYears'):
            description += f" They are {person.ageYears} years old"
        if hasattr(person, 'job') and hasattr(person.job, 'title'):
            description += f", and work as a {person.job.title}."

    if person.familiarity > 20 and hasattr(person, 'education'):
        description += f" They have a {person.education} level of education"
        if hasattr(person, 'college') and person.college and hasattr(person.college, 'title'):
            description += f", and graduated from {person.college.title}."

    if person.familiarity > 40:
        if hasattr(person, 'likes') and person.likes:
            description += f". Their interests include {', '.join(person.likes)}"
        if hasattr(person, 'dislikes') and person.dislikes:
            description += f", but they dislike {', '.join(person.dislikes)}."

    if person.familiarity > 80:
        if hasattr(person, 'job') and hasattr(person.job, 'income'):
            description += f". They earn approximately {person.job.income} per month from their job"
        if hasattr(person, 'money') and person.money > 0:
            description += f", and have about {person.money} in savings."

    return description


def getOpenAIDescription(person):
    """
    Generate an OpenAI-formatted description for AI conversation prompts.

    Args:
        person: personClass instance

    Returns:
        str: Formatted description for AI prompts
    """
    description = f"Pretend you are {person.firstname} {person.lastname}, a {person.sex.lower()}"

    for i in person.relationships:
        if (i == 'dating_match'):
            description += f". Pretend you're on a dating app. You just met your conversation partner on a dating app. Be tastefuly flirty! If they are rude, you can end the conversation."
        else:
            description += f". You are a {i} to the conversation partner"

    if hasattr(person, 'ageYears'):
        description += f" You're {person.ageYears} years old"
    if hasattr(person, 'job') and hasattr(person.job, 'title'):
        description += f", a {person.job.title}."

    if hasattr(person, 'mood'):
        description += f" and you are {person.mood.lower()}."

    if hasattr(person, 'education'):
        description += f" you studied {person.education}"
        if hasattr(person, 'college') and person.college and hasattr(person.college, 'title'):
            description += f" at {person.college.title}."

    if hasattr(person, 'likes') and person.likes:
        description += f". you like {', '.join(person.likes)}"
    if hasattr(person, 'dislikes') and person.dislikes:
        description += f" & dislike {', '.join(person.dislikes)}."

    if hasattr(person, 'job') and hasattr(person.job, 'income'):
        description += f". you earn {person.job.income}/mo"
    if hasattr(person, 'money') and person.money > 0:
        description += f" & have {person.money} saved."

    return description


# ============================================================
# Character Avatar Functions
# ============================================================

def set_avatar(person):
    """
    Generate and set avatar URL for a person using DiceBear API.

    Args:
        person: personClass instance

    Returns:
        str: Avatar URL
    """
    if not hasattr(person.avatar_settings, 'hair'):
        person.avatar_settings.hair = 'NONE'
    if not hasattr(person.avatar_settings, 'facial_hair'):
        person.avatar_settings.facial_hair = 'NONE'
    if not hasattr(person.avatar_settings, 'accessory'):
        person.avatar_settings.accessory = 'NONE'


    style = ["transparent", "circle"]
    mode = ["include", "exclude"]

    top = ["longHair", "shortHair", "eyepatch", "hat", "hijab", "turban"]
    topChance = 100

    hatColor = ["black", "blue", "gray", "heather", "pastel", "pink", "red", "white"]
    hairColor = ["auburn", "black", "blonde", "brown", "pastel", "platinum", "red", "gray"]

    accessories = ["kurt", "prescription01", "prescription02", "round", "sunglasses", "wayfarers"]
    accessoriesChance = 10

    facialHair = ["medium", "light", "magestic", "fancy", "magnum"]
    facialHairChance = 10
    facialHairColor = ["auburn", "black", "blonde", "brown", "platinum", "red"]

    clothes = ["blazer", "sweater", "shirt", "hoodie", "overall"]
    clothesColor = ['3c4f5c', '65c9ff', '262e33', '5199e4', '25557c', '929598', 'a7ffc4', 'b1e2ff', 'e6e6e6', 'ff5c5c', 'ff488e', 'ffafb9', 'ffffb1', 'ffffff']
    clothingGraphic = ['bat', 'bear', 'cumbia', 'deer', 'diamond', 'hola', 'pizza', 'resist', 'skull', 'skullOutline']
    eyebrow = ["angry", "default", "flat", "raised", "sad", "unibrow", "up"]

    skin = ["tanned", "yellow", "pale", "light", "brown", "darkBrown", "black"]

    mouthOptions = ["concerned", "default", "disbelief", "sad", "serious", "smile", "twinkle"]
    skinColors = ["614335", "ae5d29", "d08b5b", "edb98a", "f8d25c", "fd9841", "ffdbb4"]
    haircolors = [
        {"name": "Black", "hex": "2c1b18"},
        {"name": "Dark Brown", "hex": "4a312c"},
        {"name": "Chestnut Brown", "hex": "724133"},
        {"name": "Auburn", "hex": "a55728"},
        {"name": "Golden Brown", "hex": "b58143"},
        {"name": "Red", "hex": "c93305"},
        {"name": "Blonde", "hex": "d6b370"},
        {"name": "Light Grey", "hex": "e8e1e1"},
        {"name": "Dark Grey", "hex": "ecdcbf"},
        {"name": "Copper", "hex": "f59797"}
    ]
    eyebrows = ["angry", "angryNatural", "default", "defaultNatural", "flatNatural", "frownNatural", "raisedExcited", "raisedExcitedNatural", "sadConcerned", "sadConcernedNatural", "unibrowNatural", "upDown"]
    eyes = ["closed", "cry", "default", "happy", "side", "squint", "surprised"]
    facial_hairs = ["beardLight", "beardMajestic", "beardMedium", "moustacheFancy", "moustacheMagnum"]

    # Construct the DiceBear URL for avataaars in png format
    base_url = "https://api.dicebear.com/7.x/avataaars/svg?seed={person.id}"

    # Checking for 'top'
    if person.avatar_settings.hair == "NONE":
        base_url += "&topProbability=0"
    else:
        base_url += f"&top={person.avatar_settings.hair}"

    # Checking for 'facialHair'
    if person.avatar_settings.facial_hair == "NONE":
        base_url += "&facialHairProbability=0"
    else:
        base_url += f"&facialHair={person.avatar_settings.facial_hair}"

    # Checking for 'accessory'
    if hasattr(person.avatar_settings, 'accessory') and person.avatar_settings.accessory == "NONE":  # Adding hasattr to check if 'accessory' attribute exists
        base_url += "&accessoryProbability=0"
    else:
        base_url += f"&accessory={person.avatar_settings.accessory}"

    # Adding the rest of the parameters without the "NONE" condition
    base_url += f"&hairColor={person.avatar_settings.hair_color}"
    base_url += f"&clothing={person.avatar_settings.clothing}"
    base_url += f"&clothesColor={random.choice(clothesColor)}"
    base_url += f"&clothingGraphic={random.choice(clothingGraphic)}"
    base_url += f"&skinColor={person.avatar_settings.skin_color}"
    base_url += f"&mouth={person.avatar_settings.mouth}"
    base_url += f"&eyes=default"
    base_url += f"&eyebrows=default"

    # seed = person.id  # using the person's ID as a seed ensures that the avatar remains consistent for a given person

    # url = base_url + ".png" + options

    # Here, instead of downloading and storing the PNG, we are directly returning the DiceBear URL.
    # This will make the application faster and reduce the storage requirements.
    person.imageURL = base_url
    return base_url


def get_hair_color(person):
    """
    Get appropriate hair color based on person's age and skin tone.

    Args:
        person: personClass instance

    Returns:
        str: Hex color code for hair
    """
    # Hair color reflecting skin color
    haircolors = [
        {"name": "Black", "hex": "2c1b18"},
        {"name": "Dark Brown", "hex": "4a312c"},
        {"name": "Chestnut Brown", "hex": "724133"},
        {"name": "Auburn", "hex": "a55728"},
        {"name": "Golden Brown", "hex": "b58143"},
        {"name": "Red", "hex": "c93305"},
        {"name": "Blonde", "hex": "d6b370"},
        {"name": "Light Grey", "hex": "e8e1e1"},
        {"name": "Dark Grey", "hex": "ecdcbf"},
        {"name": "Copper", "hex": "f59797"}
    ]

    # Helper function to get hex from name
    def get_hex(color_name):
        for color in haircolors:
            if color["name"] == color_name:
                return color["hex"]
        return None

    print(person)

    if person.avatar_settings.skin_color in ['PALE', 'LIGHT']:
        hair_colors = [get_hex('Auburn'), get_hex('Blonde'), get_hex('Chestnut Brown'), get_hex('Blonde')]
    elif person.avatar_settings.skin_color == 'BROWN':
        hair_colors = [get_hex('Black'), get_hex('Chestnut Brown'), get_hex('Dark Brown')]
    elif person.avatar_settings.skin_color in ['DARK_BROWN', 'BLACK']:
        hair_colors = [get_hex('Black'), get_hex('Dark Brown')]
    else:
        hair_colors = [get_hex('Auburn'), get_hex('Golden Brown'), get_hex('Red')]

    # Adjusting for older people to have a higher chance of light hair
    if person.ageYears > 50:
        if get_hex('Blonde') in hair_colors:
            hair_colors.extend([get_hex('Blonde')] * 2)    # Multiply chances of BLONDE
        if get_hex('Blonde') in hair_colors:
            hair_colors.extend([get_hex('Blonde')] * 2)    # Multiply chances of BLONDE

    return random.choice(hair_colors)


def get_hair_type(person):
    """
    Get appropriate hair type based on person's age and sex.

    Args:
        person: personClass instance

    Returns:
        str: Hair type identifier
    """
    hair_types = ['NONE']
    if person.ageYears < 1:
        hair_type = 'NONE'
    elif person.ageYears > 50 and person.sex == "Male":
        hair_types = ['NONE','sides']
    else:
        if person.sex == "Male":
            hair_types = [ "dreads", "dreads01", "dreads02", "fro", "shaggy", "shaggyMullet", "shortFlat", "theCaesar", "theCaesarAndSidePart", "shavedSides", "sides", "shortWaved", "frizzle", "shortRound", "shortCurly"]
        else:
            hair_types = [ "bigHair", "bob", "bun", "curly", "fro", "curvy", "froBand", "longButNotTooLong", "miaWallace", "straight01", "straight02", "straightAndStrand" ]
    hair_type = random.choice(hair_types)

    return hair_type


def get_facial_hair(person):
    """
    Get appropriate facial hair based on person's age and sex.

    Args:
        person: personClass instance

    Returns:
        str: Facial hair type identifier
    """
    if person.sex == "Male" and person.ageYears >= 18 and person.ageYears <= 50:
        facial_hair = random.choice(['beardLight', 'beardMedium', 'moustacheMagnum'])
    else:
        facial_hair = 'NONE'

    return facial_hair


def get_accessory(person):
    """
    Get appropriate accessory (glasses) based on person's age.

    Args:
        person: personClass instance

    Returns:
        str: Accessory type identifier
    """
    accessories = ['NONE', 'round', 'round', 'round']

    # Probabilities based on age
    if person.ageYears < 18:
        # Assuming 20% of children wear glasses
        probs = [0.80, 0.067, 0.067, 0.067]
    elif 18 <= person.ageYears <= 39:
        # Assuming 40% of young adults wear glasses, considering contact lens usage
        probs = [0.60, 0.133, 0.133, 0.133]
    else:
        # Assuming 60% of older adults wear glasses, considering both glasses and contact lens usage
        probs = [0.40, 0.2, 0.2, 0.2]

    accessory = random.choices(accessories, weights=probs, k=1)[0]

    return accessory


# ============================================================
# Character Name Functions
# ============================================================

def get_lastname():
    """
    Get a random last name from the database.

    Returns:
        str: Capitalized last name
    """
    import os

    # In test mode, return a dummy lastname to avoid database calls
    if os.environ.get('BAOLIFE_TEST_MODE', 'false').lower() == 'true':
        test_lastnames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', 'Rodriguez', 'Martinez']
        return random.choice(test_lastnames)

    from database.db_operations import get_database_connection
    mydb = get_database_connection()
    try:
        mycursor = mydb.cursor()
        # rand = random.randint(1, 20000)
        mycursor.execute("SELECT name FROM lastnames_race WHERE lastnames_race.rank < 500 order by RAND() limit 1")
        myresult = mycursor.fetchall()
        return myresult[0][0].capitalize()
    finally:
        if mycursor:
            mycursor.close()
        mydb.close()


def get_firstname(gender):
    """
    Get a random first name from the database based on gender.

    Args:
        gender: "Male" or "Female"

    Returns:
        str: Capitalized first name
    """
    import os

    # In test mode, return a dummy firstname to avoid database calls
    if os.environ.get('BAOLIFE_TEST_MODE', 'false').lower() == 'true':
        if gender == "Female":
            test_names = ['Emma', 'Olivia', 'Ava', 'Isabella', 'Sophia', 'Mia', 'Charlotte', 'Amelia', 'Harper', 'Evelyn']
        else:
            test_names = ['Liam', 'Noah', 'Oliver', 'Elijah', 'James', 'William', 'Benjamin', 'Lucas', 'Henry', 'Alexander']
        return random.choice(test_names)

    from database.db_operations import get_database_connection
    mydb = get_database_connection()
    try:
        mycursor = mydb.cursor()
        genderSelector = 'M'
        if (gender == "Female"):
            genderSelector = 'F'
        # Use parameterized query to prevent SQL injection
        sql = "SELECT Name FROM firstnames WHERE Cnt > 1000000 AND Gender = %s ORDER BY RAND() LIMIT 1"
        mycursor.execute(sql, (genderSelector,))
        myresult = mycursor.fetchall()
        return myresult[0][0].capitalize()
    finally:
        if mycursor:
            mycursor.close()
        mydb.close()


# ============================================================
# Character Birthday Functions
# ============================================================

def setBirthday(person, player):
    """
    Set a person's birthday based on their age in days and current date.

    Args:
        person: personClass instance
        player: playerClass instance
    """
    if person.ageDays:
        from datetime import datetime, timedelta
        current_date = datetime.strptime(player.date, "%m-%d")
        birthday = current_date - timedelta(days=person.ageDays)
        person.birthday = birthday.strftime("%m-%d")


# ============================================================
# Family Creation Functions
# ============================================================

def get_partner(player):
    """
    Create a partner (boyfriend/girlfriend) for the player character.

    Args:
        player: playerClass instance

    Returns:
        playerClass: Updated player object
    """
    from core.models import personClass, relationshipClass
    player.r.insert(0, personClass())
    if (player.c.sex == "Male"):
        player.r[0].sex = 'Female'
        player.r[0].setPronoun()
        player.r[0].title = 'Girlfriend'
    else:
        player.r[0].sex = 'Male'
        player.r[0].setPronoun()
        player.r[0].title = 'Boyfriend'

    player.r[0].relationships.append('partner')
    player.r[0].firstname = get_firstname(player.r[0].sex)
    player.r[0].lastname = get_lastname()
    player.r[0].ageYears = player.c.ageYears + random.randint(1, 6) - 3
    player.r[0].ageDays = player.r[0].ageYears * 365 + (random.randint(1,365))
    player.r[0].birthday = player.r[0].ageDays
    player.r[0] = setValues(player, player.r[0])
    player.c.partner = player.r[0].id

    # Create relationship entry for relData (required for frontend DatingView)
    rel = relationshipClass(player.c.id, player.r[0].id, player.date, "Dating", "You are dating!")
    player.c.relationship = rel.id
    player.r[0].relationship = rel.id
    player.relData.append(rel)

    return player


def add_child(player):
    """
    Create a child for the player character.

    Args:
        player: playerClass instance

    Returns:
        personClass: The newly created child
    """
    from core.models import personClass
    player.r.insert(0, personClass())
    player.r[0].relationships.append('child')
    player.r[0].relationships.append('family')
    if (player.r[0].sex == 'Male'):
        player.r[0].title = 'Son'
    else:
        player.r[0].title = 'Daughter'
    player.r[0].familyLevel = 1
    player.r[0].firstname = get_firstname(player.r[0].sex)
    player.r[0].lastname = player.c.lastname
    player.r[0].ageYears = 0
    player.r[0].ageDays = 0
    player.r[0] = setValues(player, player.r[0])
    return player.r[0]


def get_youngestChild(player):
    """
    Get the youngest child from player's relationships.

    Args:
        player: playerClass instance

    Returns:
        personClass or False: The youngest child or False if no children
    """
    youngest = False
    for r in player.r:
        if ('child' in r.relationships):
            if (not youngest):
                youngest = r
            elif youngest and youngest.ageDays < r.ageDays:
                youngest = r
    return youngest


def add_parents(player):
    """
    Create mother and father for the player character.

    Args:
        player: playerClass instance

    Returns:
        playerClass: Updated player object
    """
    from core.models import personClass, relationshipClass
    from utils.helpers import generate_random_date, rand

    father = personClass()
    father.sex = 'Male'
    father.setPronoun()
    father.relationships.append('father')
    father.relationships.append('family')
    father.title = 'Father'
    father.familyLevel = 1
    father.firstname = get_firstname(father.sex)
    father.lastname = player.c.lastname
    father.ageYears = player.c.ageYears + random.randint(18, 34)
    father.ageDays = father.ageYears * 365 + (random.randint(1,365))
    father.avatar_settings.skin_color = player.c.avatar_settings.skin_color
    father = setValues(player, father)
    player.r.insert(0, father)

    mother = personClass()
    mother.sex = 'Female'
    mother.setPronoun()
    mother.relationships.append('mother')
    mother.relationships.append('family')
    mother.title = 'Mother'
    mother.familyLevel = 1
    mother.firstname = get_firstname(mother.sex)
    mother.lastname = player.c.lastname
    mother.ageYears = player.c.ageYears + random.randint(18, 34)
    mother.ageDays = mother.ageYears * 365 + (random.randint(1,365))
    mother.avatar_settings.skin_color = player.c.avatar_settings.skin_color
    mother = setValues(player, mother)
    player.r.insert(0, mother)

    # Now, let's create their relationship
    parents_relationship = relationshipClass(mother.id, father.id, generate_random_date(), "Married", "Happily married for years.")
    father.relationship = parents_relationship.id
    mother.relationship = parents_relationship.id
    mother.affinity = rand(1,50) + 50
    father.affinity = rand(1,50) + 50
    player.relData.append(parents_relationship)

    return player


def add_older_siblings(player):
    """
    Create older siblings for the player character (with some randomness).

    Args:
        player: playerClass instance

    Returns:
        playerClass: Updated player object
    """
    from core.models import personClass

    # 50% chance you have an older sibling
    print('adding older siblings')
    if random.randint(0,1) == 0:
        print('adding older sibling')
        sibling = personClass()
        sibling.relationships.append('sibling')
        sibling.relationships.append('family')
        if sibling.sex == "Male":
            sibling.title = 'Brother'
        else:
            sibling.title = 'Sister'
        sibling.familyLevel = 1
        sibling.firstname = get_firstname(sibling.sex)
        sibling.setPronoun()
        sibling.lastname = player.c.lastname
        sibling.ageYears = player.c.ageYears + random.randint(0,3)
        sibling.ageDays = sibling.ageYears * 365 + 270 + random.randint(1,365) # at least 9 months older
        sibling.avatar_settings.skin_color = player.c.avatar_settings.skin_color
        sibling = setValues(player, sibling)
        player.r.insert(0, sibling)

        #10% chance you have another older sibling
        if random.randint(0,9) == 0:
            print('adding another older sibling')
            sibling = personClass()
            sibling.relationships.append('sibling')
            sibling.relationships.append('family')
            if sibling.sex == "Male":
                sibling.title = 'Brother'
            else:
                sibling.title = 'Sister'
            sibling.familyLevel = 1
            sibling.setPronoun()
            sibling.firstname = get_firstname(sibling.sex)
            sibling.lastname = player.c.lastname
            sibling.ageYears = player.r[1].ageYears + random.randint(1,3) #older than the other sibling
            sibling.ageDays = sibling.ageYears * 365 + 270 + random.randint(1,365) # at least 9 months older
            sibling.avatar_settings.skin_color = player.c.avatar_settings.skin_color
            sibling = setValues(player, sibling)
            player.r.insert(0, sibling)

    return player


def add_grandparents(player):
    """
    Create all four grandparents for the player character.

    Args:
        player: playerClass instance

    Returns:
        playerClass: Updated player object
    """
    from core.models import personClass, relationshipClass
    from utils.helpers import generate_random_date

    grandmother1 = personClass()
    grandmother1.sex = 'Female'
    grandmother1.setPronoun()
    grandmother1.relationships.append('paternal_grandmother')
    grandmother1.relationships.append('family')
    grandmother1.title = 'Grandmother'
    grandmother1.familyLevel = 2
    grandmother1.firstname = get_firstname(grandmother1.sex)
    grandmother1.lastname = player.c.lastname
    grandmother1.ageYears = get_relationship(player,'father').ageYears + random.randint(18, 34)
    grandmother1.ageDays = grandmother1.ageYears * 365 + (random.randint(1,365))
    grandmother1.avatar_settings.skin_color = player.c.avatar_settings.skin_color
    grandmother1 = setValues(player, grandmother1)
    player.r.insert(0, grandmother1)

    grandfather1 = personClass()
    grandfather1.sex = 'Male'
    grandfather1.setPronoun()
    grandfather1.relationships.append('paternal_grandfather')
    grandfather1.relationships.append('family')
    grandfather1.title = 'Grandfather'
    grandfather1.familyLevel = 2
    grandfather1.firstname = get_firstname(grandfather1.sex)
    grandfather1.lastname = player.c.lastname
    grandfather1.ageYears = get_relationship(player,'father').ageYears + random.randint(18, 34)
    grandfather1.ageDays = grandfather1.ageYears * 365 + (random.randint(1,365))
    grandfather1.avatar_settings.skin_color = player.c.avatar_settings.skin_color
    grandfather1 = setValues(player, grandfather1)
    player.r.insert(0, grandfather1)

    # Now, let's create their relationship
    g_rel = relationshipClass(grandmother1.id, grandfather1.id, generate_random_date(), "Married", "Happily married for years.")
    grandmother1.relationship = g_rel.id
    grandfather1.relationship = g_rel.id
    player.relData.append(g_rel)

    grandfather2 = personClass()
    grandfather2.sex = 'Male'
    grandfather2.setPronoun()
    grandfather2.relationships.append('maternal_grandfather')
    grandfather2.relationships.append('family')
    grandfather2.title = 'Grandfather'
    grandfather2.familyLevel = 2
    grandfather2.firstname = get_firstname(grandfather2.sex)
    grandfather2.lastname = get_lastname()
    grandfather2.ageYears = get_relationship(player,'mother').ageYears + random.randint(18, 34)
    grandfather2.ageDays = grandfather2.ageYears * 365 + (random.randint(1,365))
    grandfather2.avatar_settings.skin_color = player.c.avatar_settings.skin_color
    grandfather2 = setValues(player, grandfather2)
    player.r.insert(0, grandfather2)

    grandmother2 = personClass()
    grandmother2.sex = 'Female'
    grandmother2.setPronoun()
    grandmother2.relationships.append('maternal_grandmother')
    grandmother2.relationships.append('family')
    grandmother2.title = 'Grandmother'
    grandmother2.familyLevel = 2
    grandmother2.firstname = get_firstname(grandmother2.sex)
    grandmother2.lastname = player.r[1].lastname
    grandmother2.ageYears = get_relationship(player,'mother').ageYears + random.randint(18, 34)
    grandmother2.ageDays = grandmother2.ageYears * 365 + (random.randint(1,365))
    grandmother2.avatar_settings.skin_color = player.c.avatar_settings.skin_color
    grandmother2 = setValues(player, grandmother2)
    player.r.insert(0, grandmother2)
    # Now, let's create their relationship
    g_rel = relationshipClass(grandmother2.id, grandfather2.id, generate_random_date(), "Married", "Happily married for years.")
    grandmother2.relationship = g_rel.id
    grandfather2.relationship = g_rel.id
    player.relData.append(g_rel)

    return player


# ============================================================
# Friend and Social Character Creation Functions
# ============================================================

def add_friend(player, sex, age):
    """
    Create a friend for the player character.

    Args:
        player: playerClass instance
        sex: "Male" or "Female"
        age: "similar", "younger", "older", or other

    Returns:
        playerClass: Updated player object
    """
    from core.models import personClass

    friend = personClass()
    friend.sex = sex
    friend.setPronoun()
    friend.relationships.append('friend')
    friend.title = 'Friend'
    friend.affinity = random.randint(70, 100)
    friend.firstname = get_firstname(friend.sex)
    friend.lastname = get_lastname()
    if age == "similar":
        friend.ageYears = player.c.ageYears + random.randint(1, 3)
    elif age == "younger":
        friend.ageYears = player.c.ageYears + random.randint(1, 6) - 3
    elif age == "older":
        friend.ageYears = player.c.ageYears + random.randint(1, 6) + 3
    else:
        friend.ageYears = player.c.ageYears + random.randint(1, 6)
    friend = setValues(player, friend)
    player.r.insert(0, friend)
    return player


# ============================================================
# Character Retrieval Functions
# ============================================================

def get_random_classmate(player):
    """
    Get a random classmate from player's relationships.
    Creates classmates if none exist.

    Args:
        player: playerClass instance

    Returns:
        personClass: A random classmate
    """
    classmates = []
    for i in range(0,len(player.r)):
        if ('classmate' in player.r[i].relationships):
            classmates.append(player.r[i])
    if (len(classmates) == 0):
        create_classmates(player)
        for i in range(0,len(player.r)):
            if ('classmate' in player.r[i].relationships):
                classmates.append(player.r[i])
    return classmates[random.randint(0,len(classmates)-1)]


def get_random_friend(player):
    """
    Get a random friend from player's relationships.

    Args:
        player: playerClass instance

    Returns:
        personClass or False: A random friend or False if no friends
    """
    friends = []
    for i in range(0,len(player.r)):
        if ('friend' in player.r[i].relationships):
            friends.append(player.r[i])
    if (len(friends) == 0):
        return False
    return friends[random.randint(0,len(friends)-1)]


def get_random_character(player):
    """
    Get a random character from player's relationships.

    Args:
        player: playerClass instance

    Returns:
        personClass: A random character
    """
    return player.r[random.randint(0,len(player.r)-1)]


def get_random_family(player):
    """
    Get a random immediate family member (familyLevel == 1).

    Args:
        player: playerClass instance

    Returns:
        personClass: A random family member or None if no family
    """
    family = []
    for i in range(0,len(player.r)):
        if (player.r[i].familyLevel == 1):
            family.append(player.r[i])
    if len(family) == 0:
        return None
    return family[random.randint(0,len(family)-1)]


def get_allFamily(player):
    """
    Get all immediate family members (familyLevel == 1).

    Args:
        player: playerClass instance

    Returns:
        list: List of all immediate family members
    """
    family = []
    for i in range(0,len(player.r)):
        if (player.r[i].familyLevel == 1):
            family.append(player.r[i])
    return family


# ============================================================
# Generic Character Creation Functions
# ============================================================

def create_character(player, sex='random', age='similar', relationship='friend'):
    """
    Create a generic character with customizable attributes.

    Args:
        player: playerClass instance
        sex: "Male", "Female", or "random"
        age: "similar", "random_adults", "random_teens_adults", or other
        relationship: Relationship type or "none"

    Returns:
        personClass: The newly created character
    """
    from core.models import personClass

    new_character = personClass()

    # Set relationship
    if relationship != 'none':
        new_character.relationships.append(relationship)
        new_character.title = relationship.capitalize()

    # Set sex
    if sex != 'random':
        new_character.sex = sex

    new_character.setPronoun()
    new_character.firstname = get_firstname(new_character.sex)
    new_character.lastname = get_lastname()

    # Set age
    if age == "similar":
        new_character.ageYears = player.c.ageYears + random.randint(0, 1)
    elif age == "random_adults":
        new_character.ageYears = 18 + random.randint(0, 40)
    elif age == "random_teens_adults":
        new_character.ageYears = 13 + random.randint(0, 45)
    new_character.ageDays = new_character.ageYears * 365 + random.randint(1, 270)

    # Set other values
    new_character = setValues(player, new_character)

    if relationship == 'none':
        return new_character
    else:
        player.r.insert(0, new_character)
        return player.r[0]


def create_classmates(player, activity=None):
    """
    Create 10 classmates and 1 teacher for the player.

    Args:
        player: playerClass instance
        activity: Optional activity parameter (unused currently)
    """
    from utils.helpers import find_where_test

    if (activity == None):
        #create 10 classmates with
        for i in range(0,10):
            create_character(player, relationship='classmate')
        # create teacher
        c = create_character(player, relationship='teacher', age='random_adults')
        c.job = list(find_where_test(player.occupations, {'title': 'Elementary School Teacher'}))[0]


def create_coworkers(player, occupation):
    """
    Create coworkers and a boss for the player.

    Args:
        player: playerClass instance
        occupation: Job occupation object
    """
    from utils.helpers import rand

    #create coworkers
    for i in range(0, rand(5,8)):
        c = create_character(player, relationship='coworker', age='random_teens_adults')
        c.job = occupation
    #create boss
    c = create_character(player, relationship='boss', age='random_adults')
    c.job = occupation


# ============================================================
# Character Lookup Functions
# ============================================================

def get_person(player, id):
    """
    Get a person by their ID from player's relationships.

    Args:
        player: playerClass instance
        id: Person's ID

    Returns:
        personClass or None: The person if found, None otherwise
    """
    return next((item for item in player.r if item.id == id), None)


def get_relationship(player, type):
    """
    Get a person by their relationship type.

    Args:
        player: playerClass instance
        type: Relationship type (e.g., "father", "mother", "friend")

    Returns:
        personClass or None: The person if found, None otherwise
    """
    return next((item for item in player.r if type in item.relationships), None)


# ============================================================
# Relationship Management Functions
# ============================================================

def update_relationship(player, oldRelationship, newRelationship, title=False):
    """
    Update a relationship type for all matching characters.

    Args:
        player: playerClass instance
        oldRelationship: Current relationship type
        newRelationship: New relationship type
        title: Optional new title for the relationship

    Returns:
        playerClass: Updated player object
    """
    for index, item in enumerate(player.r):
        if type in item.relationships:
            player.r[index].relationships.remove(oldRelationship)
            player.r[index].relationships.append(newRelationship)
            if (title): #update title if included
                player.r[index].title = title
    return player


# ============================================================
# Character Update Functions
# ============================================================

def updateBio(player):
    """
    Update player character's biological stats (hunger, thirst, weight).

    Args:
        player: playerClass instance

    Returns:
        playerClass: Updated player object
    """
    from health.health_manager import handleHunger, getWeightType, handleHealth, handleWeight
    from utils.helpers import rand

    top = 2
    bottom = -2
    if (player.c.weightType == 'Underweight'):
        bottom = -4
    if (player.c.weightType == 'Obese'):
        top = 4
    player.c.hunger = player.c.hunger + rand(bottom,top)
    player.c.thirst = player.c.thirst + rand(bottom,top)
    player.c = handleHunger(player.c)
    player.c.weightType = getWeightType(player.c.weight)
    if (player.c.hunger > 100):
        player.c.hunger = 100
    if (player.c.thirst > 100):
        player.c.thirst = 100
    if (player.c.hunger < 2):
        player.c.weight = player.c.weight + .5
    if (player.c.hunger > 98):
        player.c.weight = player.c.weight - .5
    handleHealth(player, player.c)
    handleWeight(player.c)
    return player


def setValues(player, person):
    """
    Set all default values for a character (education, job, avatar, etc.).

    Args:
        player: playerClass instance
        person: personClass instance

    Returns:
        personClass: Updated person object
    """
    from education.education_manager import setEducation
    from stats.stats_manager import setLikesDislikes
    from health.health_manager import setHabits
    from jobs.job_manager import randomJob

    setEducation(player, person)
    setLikesDislikes(person)
    setHabits(person)
    randomJob(player, person)
    setBirthday(person, player)
    person.avatar_settings.hair = get_hair_type(person)
    person.avatar_settings.hair_color = get_hair_color(person)
    person.avatar_settings.facial_hair = get_facial_hair(person)
    person.avatar_settings.accessory = get_accessory(person)
    person.image = set_avatar(person)
    if (person.ageYears >= 18):
        person.actScore = random.randint(10,36)
    return person


def characterSetup(player, data):
    """
    Set up the main player character with initial family and relationships.

    Args:
        player: playerClass instance
        data: Dictionary with 'name', 'age', 'sex' keys

    Returns:
        playerClass: Configured player object
    """
    from core.models import locationClass, relationshipClass
    from utils.helpers import getOppositeSex

    #{"type":"characterSetup","message":{"name":"Craig Vander Galien","age":"27","sex":"Male"}}
    if (data['name']):
        name_parts = data['name'].split(' ')
        player.c.firstname = name_parts[0]
        player.c.lastname = name_parts[1] if len(name_parts) > 1 else ''
    if (data['age']):
        player.c.ageYears = int(data['age'])
    else:
        player.c.ageYears = 15
    player.c.ageDays = player.c.ageYears * 365
    player.c.sex = data['sex']
    player.c.affinity = 100
    if player.c.sex == "Male":
        player.c.pronoun = "He"
    else:
        player.c.pronoun = "She"

    player.c.image = set_avatar(player.c)
    if (not player.c.firstname):
        player.c.firstname = get_firstname(player.c.sex)
    if (not player.c.lastname):
        player.c.lastname = get_lastname()
    player.l.append(locationClass('home'+player.c.id,'home','https://cdn.midjourney.com/fe048fc6-f534-4ffe-9fb2-02297a3e1d2d/0_2.png'))
    player = add_parents(player)
    player = add_older_siblings(player)
    player = add_grandparents(player)
    player.c = setValues(player, player.c)
    player.controller = "active"

    # test, add relationship
    add_friend(player, getOppositeSex(player.c.sex), 'similar')
    player.r[0].relationships.append('partner')
    rel = relationshipClass(player.c.id, player.r[0].id, player.date, "Dating", "You are dating!")
    player.c.relationship = rel.id
    player.r[0].relationship = rel.id
    player.relData.append(rel)

    player.status = "setupComplete"

    return player


# ============================================================
# Helper Functions (imported from functions.py)
# ============================================================

# Note: The following helper functions are imported from functions.py:
# - setEducation(player, person)
# - setLikesDislikes(person)
# - setHabits(person)
# - randomJob(player, person)
# - handleHunger(person)
# - getWeightType(weight)
# - handleHealth(player, person)
# - handleWeight(person)
# - rand(num1, num2)
# - generate_random_date()
# - getOppositeSex(sex)
# - personClass
# - relationshipClass
# - locationClass
# - find_where_test(iterable, dct)
