#!/usr/bin/env python
"""
Core Game Model Classes

This file contains the core data model classes for BaoLife (formerly Project Lichun).
These classes define the fundamental game entities including players, characters,
locations, activities, schedules, and relationships.

Classes:
    - locationClass: Represents a location in the game world
    - ActivityRecord: Base class for tracking activities
    - EducationRecord: Tracks education activities (extends ActivityRecord)
    - dailyEvent: Represents a scheduled daily event
    - playerClass: Main player/game state container
    - personClass: Represents any character (player or NPC)
    - oneTimeEvent: Represents a one-time scheduled event
    - scheduleDays: Defines days/times for scheduled events
    - scheduler: Manages recurring schedules for characters
    - relationshipClass: Tracks relationships between characters
"""

import datetime
import uuid
import random
from datetime import date
from types import SimpleNamespace

# Import configuration and logging
from config import config
import logging

# Set up logger
logger = logging.getLogger(__name__)


class locationClass:
    def __init__(self, id, type, image=None):
        self.id = id
        self.type = type
        self.image = image
        self.description = ""
        self.people = []
        self.type = "locationObject"


class ActivityRecord:
    def __init__(self, id, type, date):
        self.id = id
        self.type = type
        self.dateStarted = date
        self.achievements = []
        self.performance = 50
        self.level = None
        self.focus = 'Balanced'


class EducationRecord(ActivityRecord):
    def __init__(self, educationLevel, location, date):
        super().__init__(location.id, "education", date)
        self.educationLevel = educationLevel
        self.major = None
        self.minor = None
        self.GPA = 75


class dailyEvent:
    def __init__(self, time, location):
        self.time = time
        self.title = ''
        self.name = ''
        self.location = location


class playerClass:
    def __init__(self):
        # Import here to avoid circular imports
        from utils.helpers import get_season
        from education.education_manager import getSchools, getColleges, getMajors, getFocuses, getExtraCurriculars
        from shop.shop_manager import getStoreItems, getInAppPurchaseItems
        from health.health_manager import getHealthConditions
        from relationships.relationship_manager import getDateIdeas

        self.controller = 'inactive'
        self.connection = 'connected'
        self.updateClient = False
        self.status = 'creating'
        self.dayEvent = ''
        self.deviceToken = ''
        self.events = set()  # Changed from list to set for O(1) lookups
        self.askedQuestions = set()  # Changed from list to set for O(1) lookups
        self.conversations = []  # Keep as list - order matters for conversation history
        self.activeDilemmas = []  # Keep as list - order/state matters
        self.messageQueue = []
        self.messageQueue.append("Welcome to BaoLife! Your journey awaits.")
        self.messageLog = []
        self.offlineStats = SimpleNamespace(minutesOffline=0)
        self.gameSpeed = config.SPEED_DEFAULT
        self.previousGameSpeed = config.SPEED_DEFAULT
        self.messageEnergyCost = 5

        self.ticks = 0
        self.fps = 0
        self.dayOfYear = int(date.today().strftime('%j'))
        self.monthOfYear = int(date.today().strftime('%m'))
        self.season = get_season(self.monthOfYear)
        self.date = str(date.today().strftime('%m-%d'))
        self.minuteOfHour = 0
        self.hourOfDay = 0
        self.dayOfWeek = 0
        self.weekDay = date.today().weekday()
        self.weekend = False
        self.weekDayText = ""
        self.daysSinceSchoolStarted = 0
        self.daysUntilSchoolEnds = 0
        self.summerVacation = False
        self.moods = ["Calm", "Stressed", "Exhausted", "Fulfilled", "Depressed", "Happy"]
        self.elementary_schools = getSchools()[0]
        self.high_schools = getSchools()[1]
        self.colleges = getColleges()
        self.majors = getMajors(self.colleges)
        self.focuses = getFocuses()
        self.storeItems = getStoreItems()
        self.inAppPurchases = getInAppPurchaseItems()
        self.healthConditions = getHealthConditions()
        self.extraCurriculars = getExtraCurriculars()
        self.dateIdeas = getDateIdeas()
        self.female_hair_types = ['bob', 'bun', 'curly', 'long_not_too_long', 'shaggy', 'straight_1', 'straight_2']
        self.male_hair_types = ['buzzcut', 'short_flat', 'short_round', 'short_waved', 'sides']
        self.c = personClass()  # character
        self.c.image = ""
        self.r = []  # characters / relationships
        self.l = []  # locations
        self.relData = []
        self.type = "playerObject"


class personClass:
    def __init__(self):
        # Import here to avoid circular imports
        from character.character_manager import get_lastname
        from health.health_manager import getWeightType
        from character.appearance import get_skin_color, get_hair_type, get_facial_hair, get_accessory

        self.id = uuid.uuid4().hex
        self.type = "personObject"
        self.relationships = []
        self.firstname = ""
        self.lastname = get_lastname()
        index = random.randint(0, 1)
        self.sex = ["Male", "Female"][index]
        self.pronoun = ["He", "She"][index]
        self.message = False
        self.ageHours = 0
        self.ageDays = 0
        self.ageYears = 0
        self.image = "https://api.dicebear.com/7.x/avataaars/svg"
        self.mood = "Calm"
        self.money = 0
        self.weight = 55
        self.weightType = getWeightType(self.weight)
        self.hunger = 0
        self.thirst = 0
        self.energy = 100
        self.calcEnergy = 100
        self.peakEnergy = 0
        self.prestige = 0
        self.diamonds = 35
        self.stress = 0
        self.social = 0
        self.happiness = random.randint(0, 100)
        self.location = 'home'
        self.health = 1
        self.deathChance = 0
        self.familyLevel = 0
        self.spendingHabits = ["frugal", "normal", "extravagant"][random.randint(0, 2)]
        self.activityRecords = []
        self.education = 'None'
        self.current_education = None
        self.elementary_school = None
        self.high_school = None
        self.college = None
        self.actScore = 0
        self.occupation = 'preschool'
        self.job = None
        self.major = None
        self.minor = None
        self.activities = []
        self.habits = []
        self.healthConditions = []
        self.dislikes = []
        self.likes = []
        self.items = []
        self.canDrive = False
        self.affinity = random.randint(1, 50) - 25
        self.familiarity = 0
        self.status = "alive"
        self.dailyPlan = []
        self.schedules = []
        self.oneTimeEvents = []
        self.intraDayMessage = False
        self.tryingForChild = False
        self.partner = False
        self.avatar_settings = SimpleNamespace(
            clothing=random.choice(['blazerAndShirt', 'blazerAndSweater', 'collarAndSweater',
                                    'graphicShirt', 'hoodie',
                                    'shirtCrewNeck', 'shirtScoopNeck', 'shirtVNeck']),

            skin_color=get_skin_color(),
            hair=get_hair_type(self),
            hair_color="AUBURN",
            facial_hair=get_facial_hair(self),
            accessory=get_accessory(self),
            mouth=self.get_mouth_type()
        )
        self.image = False

        # Messaging style traits - dynamic personality-driven texting behavior
        from messaging_style import initialize_messaging_traits, initialize_messaging_patterns
        self.messaging_traits = initialize_messaging_traits()
        self.messaging_patterns = initialize_messaging_patterns()

    def setPronoun(self):
        if self.sex == "Male":
            self.pronoun = "He"
        else:
            self.pronoun = "She"

    def get_mouth_type(self):  # based on mood
        """
        Get mouth expression type based on current mood.

        Returns:
            str: Mouth expression type for avatar
        """
        # First draft, simple moods.
        # self.moods = ["Calm","Stressed","Exhausted","Fulfilled","Depressed","Happy"]
        mood_mouth_mapping = {
            "Calm": "default",        # Assuming 'Calm' corresponds to a neutral expression
            "Stressed": "concerned",  # 'Stressed' matches 'concerned'
            "Exhausted": "serious",   # 'Exhausted' might be best represented by a 'serious' expression
            "Fulfilled": "smile",     # 'Fulfilled' aligns with a 'smile'
            "Depressed": "sad",       # 'Depressed' could correspond to 'sad'
            "Happy": "smile"          # 'Happy' obviously maps to 'smile'
        }

        # Return the corresponding mouth type or a default value if mood is not in the dictionary
        return mood_mouth_mapping.get(self.mood, "default")


class oneTimeEvent:
    def __init__(self, title, message, date, location=False, hour=0, dateType="date",
                 dateModifier=False, completionFunc=None, completionArgs=(), completionKwargs={}):
        self.id = uuid.uuid4().hex
        self.message = message
        self.title = title
        self.dateType = dateType
        self.dateModifier = dateModifier
        self.hour = hour
        self.location = location
        self.type = "oneTimeEventObject"
        self.completionFunc = completionFunc
        self.completionArgs = completionArgs
        self.completionKwargs = completionKwargs
        if (self.dateType == "date"):
            self.date = date
        elif (self.dateType == "daysFromNow"):
            self.date = date
            self.date = self.findDate()

    def findDate(self):
        if (self.dateType == "date"):
            return self.date
        elif (self.dateType == "daysFromNow" and self.dateModifier):
            # print('finding date from string')
            # add dateString days to date (5-20 format)
            from datetime import datetime, timedelta
            self.date += '-{}'.format(datetime.now().year)
            date_object = datetime.strptime(self.date, '%m-%d-%Y')
            new_date_object = date_object + timedelta(days=self.dateModifier)
            self.date = new_date_object.strftime('%m-%d')
            return self.date

    def run_func(self, player):
        if self.completionFunc:
            self.completionFunc(player, *self.completionArgs, **self.completionKwargs)


class scheduleDays():
    def __init__(self, days, hour, type):
        self.daysOfWeek = days
        self.hour = hour
        self.type = type


class scheduler():
    def __init__(self, person, planname, conditions, location, duration=5):
        self.id = planname + uuid.uuid4().hex
        self.title = planname
        self.executions = 0
        self.duration = duration
        self.location = location
        self.conditions = conditions
        self.conditionsOptions = ["once", "weekly", 'daily', 'twice-week', 'thrice-week',
                                   "morning", "afternoon", "evening", "night", "weekend",
                                   "weekday", "workday", "school", "college", "work", "home", "out"]
        self.type = "schedulerObject"
        self.days = self.findWeekDays(person)

    def parseConditions(self, day, time, person, condition):
        # print('parsing ..' + condition +' ..' + str(day) + ' ..' + str(time))
        if condition == "morning":
            return time < 12 and time > 6
        elif condition == "afternoon":
            return time < 18 and time > 12
        elif condition == "evening":
            return time <= 20 and time > 18
        elif condition == "night":
            return time > 20 and time < 23
        elif condition == "afterSchool":
            return time > 15 and time < 23
        elif condition == "afterWork":
            return time > 17 and time < 23
        elif condition == "weekend":
            return day > 5
        elif condition == "weekday":
            return day < 6
        elif condition == "workday":
            return day < 6 and person.occupation == "work"
        elif condition == "school":
            return "school" in person.location
        elif condition == "college":
            return "college" in person.location
        elif condition == "work":
            return "work" in person.location
        elif condition == "home":
            return "home" in person.location
        elif condition == "out":
            return "home" not in person.location
        else:
            return False

    def checkConditions(self, dayTest, hourTest, person):
        for i in range(0, len(self.conditions)):
            if (self.conditions[i] != 'weekly' and self.conditions[i] != 'daily' and
                self.conditions[i] != 'twice-week' and self.conditions[i] != 'thrice-week'):
                if (self.parseConditions(dayTest, hourTest, person, self.conditions[i])):
                    return True
        return False

    def findWeekDays(self, person):
        if ("once" in self.conditions):
            # check every day of week
            for day in range(1, 7):
                for hour in range(0, 23):
                    if (self.checkConditions(day, hour, person)):
                        return scheduleDays(str(day), hour, "once")
        if ('weekly' in self.conditions):
            # check every day of week
            for day in range(1, 7):
                for hour in range(0, 23):
                    if (self.checkConditions(day, hour, person)):
                        return scheduleDays(str(day), hour, "weekly")
        elif ('daily' in self.conditions):
            daysFound = ""
            for day in range(1, 7):
                for hour in range(0, 23):
                    if (self.checkConditions(day, hour, person)):
                        daysFound = daysFound + str(day)
                        break
            return scheduleDays(daysFound, hour, "daily")
        elif ('twice-week' in self.conditions):
            # check every day of week
            daysFound = ""
            for day in range(1, 7):
                for hour in range(0, 23):
                    if (self.checkConditions(day, hour, person) and len(daysFound) < 2):
                        daysFound = daysFound + str(day)
                        break
            return scheduleDays(daysFound, hour, "twice-week")
        elif ('thrice-week' in self.conditions):
            # check every day of week
            daysFound = ""
            for day in range(1, 7):
                for hour in range(0, 23):
                    if (self.checkConditions(day, hour, person) and len(daysFound) < 3):
                        daysFound = daysFound + str(day)
                        break
            return scheduleDays(daysFound, hour, "thrice-week")
        return False


class relationshipClass:
    def __init__(self, person1, person2, startDate, relationshipStatus, relationshipNotes, score=None):
        # Name or ID of the partner character
        self.id = uuid.uuid4().hex
        self.person1 = person1
        self.person2 = person2

        self.startDate = startDate
        self.anniversaryDate = startDate
        self.relationshipStatus = relationshipStatus
        self.relationshipNotes = relationshipNotes
        self.eventsLog = []
        self.relationshipScore = score if score is not None else random.randint(1, 100)
        self.commonInterests = []
        self.challenges = []
        self.futurePlans = []

        # Messaging style modifiers - per-relationship messaging behavior
        self.messaging_modifiers = {
            'verbosity': 0,
            'inquisitiveness': 0,
            'expressiveness': 0,
            'responsiveness': 0,
            'openness': 0,
            'emoji_usage': 0,
            'formality': 0,
            'response_timing': 0,
            'mood_state': 'neutral',
            'current_topic_engagement': 0,
        }

    @classmethod
    def from_dict(cls, data):
        relationship = cls(
            data["person1"],
            data["person2"],
            data["startDate"],
            data["relationshipStatus"],
            data["relationshipNotes"],
            data["relationshipScore"]
        )
        relationship.id = data["id"]
        relationship.anniversaryDate = data["anniversaryDate"]
        relationship.eventsLog = data["eventsLog"]
        relationship.commonInterests = data["commonInterests"]
        relationship.challenges = data["challenges"]
        relationship.futurePlans = data["futurePlans"]
        return relationship
