55#
66# Key format in JSON: "Azir_16" => 0.582
77# where the suffix is the major integer of the patch (e.g. "16.08" -> "16").
8+ #
9+ # When patch is nil, the lookup falls back to the latest patch major version
10+ # available in the data file so callers always receive a value when data exists.
811class ChampionWinrateService
912 PRIMARY_FILE = Rails . root . join ( 'data' , 'champion_patch_winrate.json' ) . freeze
1013 FALLBACK_FILE = Pathname . new ( '/home/bullet/PROJETOS/prostaff-ml/data/champion_patch_winrate.json' ) . freeze
1114 CACHE_KEY = 'champion_winrates'
15+ LATEST_PATCH_CACHE_KEY = 'champion_winrates_latest_patch'
1216 CACHE_TTL = 24 . hours
1317
14- # Returns the win rate (Float) for a given champion on a given patch,
15- # or nil if no data is available.
18+ # Returns the win rate (Float) for a given champion on a given patch.
19+ # When patch is nil, falls back to the latest patch available in the data.
20+ # Returns nil only when champion is blank or no data exists at all.
1621 #
1722 # @param champion [String] e.g. "Azir"
18- # @param patch [String] e.g. "16.08" or Integer 16
23+ # @param patch [String, Integer, nil ] e.g. "16.08", 16, or nil
1924 # @return [Float, nil]
2025 def self . win_rate_for ( champion :, patch :)
21- return nil if champion . blank? || patch . nil?
26+ return nil if champion . blank?
27+
28+ effective_patch = patch . presence || latest_patch
29+ return nil if effective_patch . nil?
2230
23- key = "#{ champion } _#{ patch . to_s . split ( '.' ) . first } "
31+ key = "#{ champion } _#{ effective_patch . to_s . split ( '.' ) . first } "
2432 data [ key ]
2533 end
2634
2735 # Returns a hash mapping each champion name to its win rate (or nil).
2836 #
2937 # @param champions [Array<String>]
30- # @param patch [String]
38+ # @param patch [String, nil ]
3139 # @return [Hash{String => Float, nil}]
3240 def self . bulk_lookup ( champions , patch )
3341 Array ( champions ) . to_h { |c | [ c , win_rate_for ( champion : c , patch : patch ) ] }
3442 end
3543
44+ # Returns the highest patch major version present in the data, or nil if
45+ # the data hash is empty.
46+ #
47+ # @return [String, nil]
48+ def self . latest_patch
49+ Rails . cache . fetch ( LATEST_PATCH_CACHE_KEY , expires_in : CACHE_TTL ) do
50+ majors = data . keys . filter_map { |k | k . split ( '_' ) . last . to_i if k . match? ( /\A .+_\d +\z / ) }
51+ majors . max &.to_s
52+ end
53+ end
54+
3655 # Loads (and caches) the win-rate JSON. Returns {} on any error.
3756 #
3857 # @return [Hash{String => Float}]
@@ -42,11 +61,11 @@ def self.data
4261 if file_path
4362 JSON . parse ( File . read ( file_path ) )
4463 else
45- Rails . logger . warn 'ChampionWinrateService: champion_patch_winrate.json not found in any known path'
64+ Rails . logger . warn '[WINRATE] ChampionWinrateService: champion_patch_winrate.json not found in any known path'
4665 { }
4766 end
4867 rescue StandardError => e
49- Rails . logger . warn "ChampionWinrateService: failed to load win-rate data — #{ e . message } "
68+ Rails . logger . warn "[WINRATE] ChampionWinrateService: failed to load win-rate data — #{ e . message } "
5069 { }
5170 end
5271 end
0 commit comments