// // PlayByPlayModel.swift // IceGlass // // Copyright 2026 Rouslan Zenetl. All Rights Reserved. // import Foundation struct PlayByPlay: Codable { let awayTeam: Team let homeTeam: Team let plays: [Play] let rosterSpots: [RosterSpot] struct Team: Codable { let id: Int let abbrev: String } struct Play: Codable { let typeDescKey: String let situationCode: String? let details: Details? struct Details: Codable { let scoringPlayerId: Int? let eventOwnerTeamId: Int? let awayScore: Int? let homeScore: Int? } } struct RosterSpot: Codable { let teamId: Int let playerId: Int let firstName: LocalizedString let lastName: LocalizedString let sweaterNumber: Int struct LocalizedString: Codable { let `default`: String } } /// Find the goal play whose trailing score matches the given totals exactly. /// Returns nil if play-by-play hasn't caught up with the scoreboard yet — /// safer than guessing, since a stale fallback could name the previous scorer. func goal(matchingAwayScore awayScore: Int, homeScore: Int) -> Play? { plays.last { play in play.typeDescKey == "goal" && play.details?.awayScore == awayScore && play.details?.homeScore == homeScore } } func player(id: Int) -> RosterSpot? { rosterSpots.first { $0.playerId == id } } /// Derived strength tag for a goal ("PPG", "SHG", "EN"), or nil for even-strength. /// `situationCode` is 4 digits: awayGoalie, awaySkaters, homeSkaters, homeGoalie. static func strengthTag(situationCode: String?, scoringTeamIsAway: Bool) -> String? { guard let code = situationCode, code.count == 4 else { return nil } let digits = code.compactMap { $0.wholeNumberValue } guard digits.count == 4 else { return nil } let awayGoalie = digits[0] let awaySkaters = digits[1] let homeSkaters = digits[2] let homeGoalie = digits[3] let scoringSkaters = scoringTeamIsAway ? awaySkaters : homeSkaters let opposingSkaters = scoringTeamIsAway ? homeSkaters : awaySkaters let opposingGoalie = scoringTeamIsAway ? homeGoalie : awayGoalie if opposingGoalie == 0 { return "EN" } if scoringSkaters > opposingSkaters { return "PPG" } if scoringSkaters < opposingSkaters { return "SHG" } return nil } } struct GoalScorer { let name: String let sweaterNumber: Int let strength: String? /// "#14 J. Eriksson Ek (PPG)" — strength suffix omitted for even-strength goals. var displayLine: String { let head = "#\(sweaterNumber) \(name)" if let strength = strength { return "\(head) (\(strength))" } return head } }