//
//  PlayerViewModel.swift
//  lichunWebsocket
//
//  Manages player character state, relationships, and activities
//

import Foundation
import Combine
import SwiftUI

class PlayerViewModel: ObservableObject {
    // MARK: - Published Properties

    // Character Info
    @Published var person: Person = Person()
    @Published var relationships: [Person] = []
    @Published var relationshipData: [Relationship] = []

    // Activities
    @Published var activities: [any ActivityProtocol] = []
    @Published var activityRecords: [ActivityRecord] = []
    @Published var currentEducation: EducationRecord?

    // Inventory & Items
    @Published var inventory: [StoreItem] = []
    @Published var habits: [Habit] = []

    // Available Options
    @Published var availableConversations: [ConversationClass] = []
    @Published var focuses: [FocusOption] = []

    // MARK: - Private Properties
    private var webSocketService: WebSocketService
    private var cancellables = Set<AnyCancellable>()

    // MARK: - Initialization
    init(webSocketService: WebSocketService) {
        self.webSocketService = webSocketService
        setupBindings()
    }

    // MARK: - Setup
    private func setupBindings() {
        // Subscribe to person updates
        webSocketService.gameState.$person
            .sink { [weak self] person in
                self?.person = person
                self?.activities = person.activities
                self?.activityRecords = person.activityRecords
                self?.currentEducation = person.currentEducation
                self?.inventory = person.items
                self?.habits = person.habits
                self?.availableConversations = person.availableConversations
            }
            .store(in: &cancellables)

        // Subscribe to player updates for relationships
        webSocketService.gameState.$player
            .sink { [weak self] player in
                self?.relationships = player.r
                self?.relationshipData = player.relData
                self?.focuses = player.focuses
            }
            .store(in: &cancellables)
    }

    // MARK: - Character Info Computed Properties

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

    var age: Int {
        person.ageYears
    }

    var ageDisplay: String {
        "\(person.ageYears) years old"
    }

    var educationLevel: String {
        person.education
    }

    var occupation: String {
        person.occupation
    }

    // MARK: - Stats Computed Properties

    var health: Double {
        Double(person.health)
    }

    var happiness: Int {
        person.happiness
    }

    var prestige: Int {
        person.prestige
    }

    var healthPercentage: Int {
        Int(person.health)
    }

    // MARK: - Activities Methods

    /// Get current enrolled activities
    func getCurrentActivities() -> [any ActivityProtocol] {
        return activities
    }

    /// Get activity record by ID
    func getActivityRecord(for activityID: String) -> ActivityRecord? {
        return activityRecords.first { $0.id == activityID }
    }

    /// Check if currently enrolled in an activity
    func isEnrolledIn(activityType: String) -> Bool {
        return activities.contains { $0.type == activityType }
    }

    /// Get current job level (if employed)
    var currentJobLevel: jobLevel? {
        guard let currentJob = activities.first(where: { $0.type == "job" }) as? OccupationClass else {
            return nil
        }

        // Find the activity record for this job
        if let jobRecord = activityRecords.first(where: { $0.id == currentJob.id }) {
            return jobRecord.level
        }

        return nil
    }

    // MARK: - Relationships Methods

    /// Get relationship with a specific person
    func getRelationship(with personID: String) -> Person? {
        return relationships.first { $0.id == personID }
    }

    /// Get relationship data
    func getRelationshipData(with personID: String) -> Relationship? {
        return relationshipData.first { relationship in
            (relationship.person1 == person.id && relationship.person2 == personID) ||
            (relationship.person2 == person.id && relationship.person1 == personID)
        }
    }

    /// Get all romantic relationships
    var romanticRelationships: [Person] {
        return relationships.filter { relationship in
            !relationship.relationship.isEmpty &&
            ["dating", "married", "engaged", "boyfriend", "girlfriend", "spouse"].contains(relationship.relationship.lowercased())
        }
    }

    /// Get all family relationships
    var familyRelationships: [Person] {
        return relationships.filter { relationship in
            ["mother", "father", "sister", "brother", "parent", "sibling", "child", "son", "daughter"].contains(relationship.relationship.lowercased())
        }
    }

    /// Get all friend relationships
    var friendRelationships: [Person] {
        return relationships.filter { relationship in
            relationship.relationship.lowercased() == "friend"
        }
    }

    // MARK: - Inventory Methods

    /// Check if player owns a specific item
    func ownsItem(_ itemID: String) -> Bool {
        return inventory.contains { $0.id == itemID }
    }

    /// Get total prestige from items
    var totalItemPrestige: Int {
        return inventory.reduce(0) { $0 + $1.prestigeBoost }
    }

    // MARK: - Habits Methods

    /// Get active habits
    var activeHabits: [Habit] {
        return habits.filter { $0.status == "active" }
    }

    /// Get habits being quit
    var quittingHabits: [Habit] {
        return habits.filter { $0.status == "quitting" }
    }

    /// Check if currently quitting a habit
    func isQuitting(habitName: String) -> Bool {
        return habits.contains { $0.name == habitName && $0.status == "quitting" }
    }

    // MARK: - Server Actions

    /// Quit a habit
    func quitHabit(_ habitName: String) {
        webSocketService.sendMessage(message: WebSocketCommands.quitHabit(habitName))
    }

    func stopQuittingHabit(_ habitName: String) {
        webSocketService.sendMessage(message: WebSocketCommands.stopQuitHabit(habitName))
    }

    func retrievePerson(personID: String) {
        let message = WebSocketCommands.retrievePerson(personID)
        webSocketService.personReceived = false
        webSocketService.sendMessage(message: message)
    }
}
