// // GameState.swift // IceGlass // // Copyright 2026 Rouslan Zenetl. All Rights Reserved. // import Foundation enum GameState: String, Codable { case future = "FUT" // More than 30 minutes prior to game start case pre = "PRE" // Pre-game, <30 minutes until puck drops case live = "LIVE" // Game has started case crit = "CRIT" // Last 5 minutes of regulation, OT or SO case over = "OVER" // Soft final case final_ = "FINAL" // Hard final case official = "OFF" // Official var isLive: Bool { self == .live || self == .crit } var isOver: Bool { self == .over || self == .final_ || self == .official } var isFuture: Bool { self == .future || self == .pre } /// Short tag for display in menu rows. Empty for future games — the start /// time already implies that state. var shortTag: String { switch self { case .future: return "" case .pre: return "PRE" case .live: return "LIVE" case .crit: return "CRIT" case .over: return "OVER" case .final_: return "FINAL" case .official: return "OFF" } } /// Monotonic ordering along the FUT→PRE→LIVE→CRIT→OVER→FINAL→OFF progression. /// Used to detect — and reject — API regressions that briefly downgrade a /// finished game back to FUT during the daily focusedDate rollover. var progressionRank: Int { switch self { case .future: return 0 case .pre: return 1 case .live: return 2 case .crit: return 3 case .over: return 4 case .final_: return 5 case .official: return 6 } } /// Same ranking, addressable by the raw API string. Unknown states get -1 /// so any known state replaces them. static func progressionRank(of rawState: String) -> Int { GameState(rawValue: rawState)?.progressionRank ?? -1 } var pollingInterval: PollingInterval { switch self { case .future: return .gameDay case .pre: return .preGame case .live, .crit: return .liveGame case .over, .final_: return .everyMinute case .official: return .idle } } }