//
//  Constants.swift
//  lichunWebsocket
//
//  App-wide constants and configuration values
//

import Foundation

struct Constants {
    // MARK: - WebSocket Configuration
    struct WebSocket {
        static let serverURL = "wss://lichun.app/wss/"
        static let maxRetryAttempts = 1000
        static let reconnectInterval: TimeInterval = 2.0
    }

    // MARK: - Game Speed Values
    struct GameSpeed {
        static let slowest = 10000
        static let slow = 1000
        static let normal = 500
        static let fast = 50
        static let fastest = 20
        static let instant = 1
        static let allLevels = [slowest, slow, normal, fast, fastest, instant]

        /// Single source of truth for the named speed vocabulary used everywhere
        /// in the UI (header, controls, status card). The six raw tick values map
        /// onto four player-facing names: Slow / Normal / Fast / Instant. (T014)
        static func label(for rawValue: Int) -> String {
            switch rawValue {
            case slowest, slow:
                return "Slow"
            case normal:
                return "Normal"
            case fast, fastest:
                return "Fast"
            case instant:
                return "Instant"
            default:
                // Map unknown values by proximity so we never show a raw "500x".
                if rawValue >= slow { return "Slow" }
                if rawValue >= normal { return "Normal" }
                if rawValue >= fastest { return "Fast" }
                return "Instant"
            }
        }
    }

    // MARK: - Energy & Resources
    struct Resources {
        static let maxEnergy = 100
        static let startingMoney = 0
        static let startingDiamonds = 0
    }

    // MARK: - Store Product IDs
    struct StoreProducts {
        static let diamond1 = "diamond1"
        static let diamond2 = "diamond2"
    }

    // MARK: - User Defaults Keys
    struct UserDefaultsKeys {
        static let deviceToken = "deviceToken"
        static let hasSeenOnboarding = "hasSeenOnboarding"
    }

    // MARK: - Notification Names
    struct Notifications {
        static let purchaseCompleted = "PurchaseCompleted"
        static let energyDepleted = "EnergyDepleted"
        static let characterDeath = "CharacterDeath"
    }

    // MARK: - Animation Durations
    struct Animation {
        static let short: Double = 0.2
        static let medium: Double = 0.3
        static let long: Double = 0.5
    }

    // MARK: - Habit System
    struct Habits {
        static let quittingDurationDays = 30
    }
}

// MARK: - WebSocket Command Builders

enum WebSocketCommands {
    private static func envelope(type: String, payload: Any) -> [String: Any] {
        ["type": type, "message": payload]
    }

    private static func typeOnly(_ type: String) -> [String: Any] {
        ["type": type]
    }

    static func connect(userID: String) -> [String: Any] {
        ["type": "init", "userID": userID]
    }

    static func initSession(userID: String) -> [String: Any] {
        connect(userID: userID)
    }

    static func command(_ action: String) -> [String: Any] {
        ["type": "command", "message": action]
    }

    /// Begin a new life from the death screen. Sends the optional `mode` in the
    /// message field: "heir" continues the lineage as the eldest living child
    /// (preserving family prestige + tree and applying inheritance), "fresh"
    /// does a clean reset. The server falls back to "fresh" when no heir exists.
    static func startNewLife(mode: String) -> [String: Any] {
        envelope(type: "startNewLife", payload: ["mode": mode])
    }

    static func speed(_ value: Any) -> [String: Any] {
        envelope(type: "speed", payload: value)
    }

    static func getExtraCurriculars() -> [String: Any] {
        envelope(type: "getExtraCurriculars", payload: "")
    }

    static func swipeMatch(characterId: String) -> [String: Any] {
        envelope(type: "swipeMatch", payload: characterId)
    }

    static func getSwipeCharacter(preferredSex: String) -> [String: Any] {
        envelope(type: "getSwipeCharacter", payload: preferredSex)
    }

    static func deviceToken(_ token: String) -> [String: Any] {
        envelope(type: "deviceToken", payload: token)
    }

    static func getAchievements() -> [String: Any] {
        typeOnly("getAchievements")
    }

    static func getDailyRewards() -> [String: Any] {
        typeOnly("getDailyRewards")
    }

    static func getDailyQuests() -> [String: Any] {
        typeOnly("getDailyQuests")
    }

    static func getEnergyRefillTiers() -> [String: Any] {
        typeOnly("getEnergyRefillTiers")
    }

    static func getTimeSkipTiers() -> [String: Any] {
        typeOnly("getTimeSkipTiers")
    }

    static func purchaseEnergyRefill(refillType: String) -> [String: Any] {
        envelope(type: "purchaseEnergyRefill", payload: ["refillType": refillType])
    }

    static func purchaseTimeSkip(skipType: String) -> [String: Any] {
        envelope(type: "purchaseTimeSkip", payload: ["skipType": skipType])
    }

    static func acknowledgeAchievement(_ achievementId: String) -> [String: Any] {
        envelope(type: "acknowledgeAchievement", payload: ["achievementId": achievementId])
    }

    static func claimDailyReward(day: Int) -> [String: Any] {
        envelope(type: "claimDailyReward", payload: ["day": day])
    }

    static func claimQuestReward(questId: String) -> [String: Any] {
        envelope(type: "claimQuestReward", payload: ["questId": questId])
    }

    static func quitHabit(_ habitId: String) -> [String: Any] {
        envelope(type: "quitHabit", payload: ["habitId": habitId])
    }

    static func stopQuitHabit(_ habitId: String) -> [String: Any] {
        envelope(type: "stopQuitHabit", payload: ["habitId": habitId])
    }

    static func applyForJob(_ jobId: String) -> [String: Any] {
        envelope(type: "applyForJob", payload: ["jobId": jobId])
    }

    static func quitJob(_ jobId: String) -> [String: Any] {
        envelope(type: "quitJob", payload: ["jobId": jobId])
    }

    static func applyForExtracurricular(_ activityId: String) -> [String: Any] {
        envelope(type: "applyForExtracurricular", payload: ["activityId": activityId])
    }

    static func quitExtracurricular(_ activityId: String) -> [String: Any] {
        envelope(type: "quitExtracurricular", payload: ["activityId": activityId])
    }

    static func focusUpdate(activityId: String, newFocus: String) -> [String: Any] {
        envelope(type: "focusUpdate", payload: [
            "activityId": activityId,
            "newFocus": newFocus,
        ])
    }

    static func purchaseItem(_ itemId: String) -> [String: Any] {
        envelope(type: "purchaseItem", payload: ["itemId": itemId])
    }

    static func purchaseInAppItem(productId: String) -> [String: Any] {
        envelope(type: "purchaseInAppItem", payload: ["productId": productId])
    }

    static func partnerGift(partnerId: String) -> [String: Any] {
        envelope(type: "partnerGift", payload: ["partnerId": partnerId])
    }

    static func romance(partnerId: String) -> [String: Any] {
        envelope(type: "romance", payload: ["partnerId": partnerId])
    }

    static func dateNight(activityName: String) -> [String: Any] {
        envelope(type: "dateNight", payload: ["ideaName": activityName])
    }

    static func breakUp(partnerId: String) -> [String: Any] {
        envelope(type: "breakUp", payload: ["partnerId": partnerId])
    }

    static func divorce(partnerId: String) -> [String: Any] {
        envelope(type: "divorce", payload: ["partnerId": partnerId])
    }

    static func startDate(activityId: String, partnerId: String) -> [String: Any] {
        envelope(type: "startDate", payload: [
            "activityId": activityId,
            "partnerId": partnerId,
        ])
    }

    static func relationshipEventResponse(eventId: String, choiceId: String) -> [String: Any] {
        envelope(type: "relationshipEventResponse", payload: [
            "eventId": eventId,
            "choiceId": choiceId,
        ])
    }

    static func dateMiniGameResponse(gameId: String, round: Int, responseId: String) -> [String: Any] {
        envelope(type: "dateMiniGameResponse", payload: [
            "gameId": gameId,
            "round": round,
            "responseId": responseId,
        ])
    }

    static func deleteAccount(confirmation: String) -> [String: Any] {
        envelope(type: "deleteAccount", payload: ["confirmation": confirmation])
    }

    /// Cancel a scheduled account deletion (within the 30-day grace period).
    /// Server clears the persisted `deletionScheduledAt` marker and replies with
    /// `accountDeletionCancelled`.
    static func cancelAccountDeletion() -> [String: Any] {
        typeOnly("cancelAccountDeletion")
    }

    static func tutorialStepComplete(step: Int) -> [String: Any] {
        envelope(type: "tutorialStepComplete", payload: ["step": step])
    }

    static func tooltipSeen(tooltipId: String) -> [String: Any] {
        envelope(type: "tooltipSeen", payload: ["tooltipId": tooltipId])
    }

    static func debugSetup(preset: String) -> [String: Any] {
        envelope(type: "debugSetup", payload: ["preset": preset])
    }

    static func debugGrant(
        money: Int? = nil,
        energy: Int? = nil,
        diamonds: Int? = nil,
        mode: String = "add"
    ) -> [String: Any] {
        var payload: [String: Any] = ["mode": mode]
        if let money { payload["money"] = money }
        if let energy { payload["energy"] = energy }
        if let diamonds { payload["diamonds"] = diamonds }
        return envelope(type: "debugGrant", payload: payload)
    }

    static func retrievePerson(_ personId: String) -> [String: Any] {
        envelope(type: "retrievePerson", payload: ["personId": personId])
    }

    /// Player-initiated activity. The server applies the activity's stat/energy/
    /// money deltas (study / exercise / socialize / sideHustle / hobby) and
    /// responds with `activityPerformed` plus a refreshed playerObject. Pass
    /// `override: true` to queue the choice for the upcoming evening/weekend slot
    /// instead of consuming a free slot right now.
    static func performActivity(activityId: String, override: Bool = false) -> [String: Any] {
        var payload: [String: Any] = ["activityId": activityId]
        if override { payload["override"] = true }
        return envelope(type: "performActivity", payload: payload)
    }
}
