game_manager_lib\services/
playtime.rs

1//! Estimador de tempo de jogo baseado em heurísticas.
2//!
3//! Aplica multiplicadores baseados em Gênero e Tags sobre a mediana do SteamSpy
4//! para corrigir a distorção causada por jogadores que abandonam o jogo cedo.
5
6use crate::models::GameTag;
7
8/// Estima o tempo de jogo baseado em horas base, gêneros e tags.
9pub fn estimate_playtime(
10    base_hours: Option<u32>, // Recebe horas (u32)
11    genres: &[String],
12    tags: &[GameTag],
13) -> Option<i32> {
14    let hours = base_hours?; // Se for None, retorna None
15
16    if hours == 0 {
17        return None;
18    }
19
20    let base = hours as f32;
21
22    // Fatores de multiplicação baseados em gênero
23    let mut multiplier = 2.5; // Base default (Adventure/General)
24
25    // Helper para verificar presença de termo (case insensitive)
26    let has_term = |term: &str| -> bool {
27        genres.iter().any(|g| g.to_lowercase().contains(term))
28            || tags.iter().any(|t| t.slug.contains(term))
29    };
30
31    // 1. Aplica a heurística de Gênero/Tag
32    if has_term("rpg") || has_term("role-playing") {
33        multiplier = 3.5;
34    } else if has_term("open-world") || has_term("sandbox") {
35        multiplier = 3.2;
36    } else if has_term("strategy") || has_term("rts") || has_term("grand-strategy") {
37        multiplier = 3.0;
38    } else if has_term("action") || has_term("shooter") || has_term("fps") {
39        multiplier = 2.8;
40    } else if has_term("adventure") {
41        multiplier = 2.5;
42    } else if has_term("indie") && (has_term("narrative") || has_term("story")) {
43        multiplier = 2.2;
44    } else if has_term("linear") || has_term("short") {
45        multiplier = 1.8;
46    }
47
48    // 2. Correção para jogos com mediana muito baixa (provável abandono alto)
49    if base < 2.0 {
50        multiplier += 1.0;
51    } else if base < 5.0 {
52        multiplier += 0.5;
53    }
54
55    let estimated = base * multiplier;
56
57    Some(estimated.round() as i32)
58}