//
//  Person.swift
//  lichunWebsocket
//
//  Person model representing characters in the game
//  Synced with backend PersonData interface (server/src/models/Person.ts)
//

import Foundation
import Combine

// MARK: - Supporting Types

struct ChildPerson: Codable, Identifiable {
    let id: String
    let firstname: String
    var lastname: String?
    var ageDays: Int = 0
    var ageYears: Int = 0
    var sex: String = "Male"
    var image: String?
}

struct Schedule: Codable, Identifiable {
    var id: String?
    var title: String?
    var location: String?
    var duration: Int?
    var executions: Int?
    var days: ScheduleDays?
    var type: String?
    var energyModifier: Int?
}

struct ScheduleDays: Codable {
    var daysOfWeek: [String]?
    var hour: Int?
}

struct MessagingTraits: Codable {
    var verbosity: Int = 50         // 0-100 - how long messages tend to be
    var inquisitiveness: Int = 50   // 0-100 - how often asks questions
    var expressiveness: Int = 50    // 0-100 - how animated/enthusiastic
    var responsiveness: Int = 50    // 0-100 - how fully engages with messages
    var openness: Int = 50          // 0-100 - how much shares personal details
    var emojiUsage: Int = 50        // 0-100 - how often uses emojis
    var formality: Int = 50         // 0-100 - how formal/proper the language
    var responseTiming: Int = 50    // 0-100 - how quickly responds

    enum CodingKeys: String, CodingKey {
        case verbosity, inquisitiveness, expressiveness, responsiveness, openness, formality
        case emojiUsage = "emoji_usage"
        case responseTiming = "response_timing"
    }
}

struct MessagingPatterns: Codable {
    var timeOfDayPreference: String = "neutral"  // 'morning' | 'night' | 'neutral'
    var weekendAvailability: Int = 50            // 0-100
    var typingStyle: String = "casual"           // 'proper' | 'casual' | 'chaotic'

    enum CodingKeys: String, CodingKey {
        case timeOfDayPreference = "time_of_day_preference"
        case weekendAvailability = "weekend_availability"
        case typingStyle = "typing_style"
    }
}

struct OneTimeEvent: Codable, Identifiable {
    var id: String
    var date: String
    var hour: Int
    var message: String
    var completionFunc: String?
}

// MARK: - Person

class Person: ObservableObject, Hashable, Identifiable {
    // MARK: - Basic Info
    @Published var id: String = ""
    @Published var image: String = ""
    @Published var status: String = ""
    @Published var sex: String = ""
    @Published var firstname: String = ""
    @Published var lastname: String = ""
    @Published var description: String = ""
    @Published var pronoun: String = ""

    // MARK: - Age
    @Published var ageDays: Int = 0
    @Published var ageYears: Int = 0
    @Published var ageHours: Int = 0
    @Published var birthday: String = ""

    // MARK: - Core Stats
    @Published var mood: String = ""
    @Published var affinity: Int = 0
    @Published var familiarity: Int = 0  // How well they know the player (0-100)
    @Published var money: Int = 0
    @Published var diamonds: Int = 0
    @Published var prestige: Int = 0
    @Published var happiness: Int = 0
    @Published var health: Int = 100
    @Published var energy: Int = 100
    @Published var calcEnergy: Int = 0
    @Published var peakEnergy: Int = 0
    @Published var intelligence: Int = 50
    @Published var social: Int = 50
    @Published var stress: Int = 0
    @Published var creativity: Int = 50
    @Published var hunger: Int = 0       // 0-100, higher = more hungry
    @Published var thirst: Int = 0       // 0-100, higher = more thirsty

    // MARK: - Physical Attributes
    @Published var weight: Double = 55   // kg
    @Published var weightType: String = "normal"
    @Published var braces: Bool = false
    @Published var glasses: Bool = false
    @Published var canDrive: Bool = false

    // MARK: - Location & Status
    @Published var location: String = ""
    @Published var intraDayMessage: String = ""
    @Published var lastIntraDayMessage: String = ""

    // MARK: - Education
    @Published var education: String = ""
    @Published var currentEducation: EducationRecord?
    @Published var elementarySchool: String?
    @Published var highSchool: String?
    @Published var college: String?
    @Published var major: String?
    @Published var actScore: Int?
    @Published var satScore: Int?

    // MARK: - Career
    @Published var occupation: String = ""
    @Published var job: String?
    @Published var ownsBusiness: Bool = false
    @Published var salary: Int = 0

    // MARK: - Relationships
    @Published var relationship: String = ""
    @Published var relationships: [String] = []
    @Published var partner: String?
    @Published var firstCrush: String?
    @Published var sexualOrientation: String = ""
    @Published var children: [ChildPerson] = []
    @Published var tryingForChild: Bool = false
    @Published var pregnant: Bool = false
    @Published var engaged: Bool = false
    @Published var familyLevel: Int = 0

    // MARK: - Social
    @Published var hasSocialMedia: Bool = false
    @Published var hasBankAccount: Bool = false
    @Published var availableConversations: [ConversationClass] = []

    // MARK: - Profile & Personality
    @Published var bio: String = ""
    @Published var likes: [String] = []
    @Published var dislikes: [String] = []
    @Published var interests: [String] = []
    @Published var personalityTraits: [String] = []
    @Published var compatibilityScore: Int = 50

    // MARK: - Activities & Items
    @Published var activities: [any ActivityProtocol] = []
    @Published var activityRecords: [ActivityRecord] = []
    @Published var items: [StoreItem] = []
    @Published var habits: [Habit] = []

    // MARK: - Schedules
    @Published var schedules: [Schedule] = []
    @Published var dailyPlan: [Schedule] = []

    // MARK: - Health & Other
    @Published var immunizations: Bool = false
    @Published var deathChance: Double = 0
    @Published var spendingHabits: String = "normal"  // 'frugal' | 'normal' | 'extravagant'

    // MARK: - Messaging Style (for NPC conversations)
    @Published var messagingTraits: MessagingTraits?
    @Published var messagingPatterns: MessagingPatterns?

    // MARK: - One-time Events
    @Published var oneTimeEvents: [OneTimeEvent] = []

    // MARK: - Internal
    @Published var lastUpdatedTime: Date?

    // MARK: - Computed Properties

    var fullName: String {
        "\(firstname) \(lastname)"
    }

    var healthPercentage: Int {
        max(0, min(100, health))
    }

    var lifeStage: String {
        switch ageYears {
        case 0..<1: return "Baby"
        case 1..<4: return "Toddler"
        case 4..<13: return "Child"
        case 13..<18: return "Teen"
        case 18..<30: return "Young Adult"
        case 30..<60: return "Adult"
        case 60..<80: return "Senior"
        default: return "Elder"
        }
    }

    var moodEmoji: String {
        switch mood.lowercased() {
        case "happy": return "😊"
        case "calm": return "😌"
        case "stressed": return "😰"
        case "exhausted": return "😩"
        case "fulfilled": return "🥰"
        case "depressed": return "😢"
        case "angry": return "😠"
        case "excited": return "🤩"
        case "anxious": return "😬"
        case "content": return "😊"
        default: return "😐"
        }
    }

    // MARK: - Hashable & Equatable

    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.id == rhs.id
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}
