game_manager_lib\services/
gamerpower.rs

1//! Integração com GamerPower API para buscar jogos grátis.
2//!
3//! Fornece funcionalidades para obter ofertas ativas de jogos gratuitos para PC.
4//! A GamerPower é uma plataforma que agrega ofertas de jogos gratuitos de várias fontes.
5
6use crate::database::AppState;
7use crate::services::cache;
8use crate::utils::http_client::HTTP_CLIENT;
9use serde::{Deserialize, Serialize};
10use tauri::{AppHandle, Manager};
11
12#[derive(Debug, Serialize, Deserialize, Clone)]
13pub struct Giveaway {
14    pub id: u32,
15    pub title: String,
16    pub worth: String,     // ex: "$29.99" or "N/A"
17    pub thumbnail: String, // Imagem pequena
18    pub image: String,     // Imagem grande (Landscape) - Usaremos essa no card estilo Epic
19    pub description: String,
20    pub instructions: String,
21    #[serde(rename = "open_giveaway_url")]
22    pub open_giveaway_url: String,
23    #[serde(rename = "published_date")]
24    pub published_date: String,
25    #[serde(rename = "type")]
26    pub type_prop: String, // "Game", "DLC"
27    pub platforms: String, // "PC, Steam, Epic Games Store"
28    #[serde(rename = "end_date")]
29    pub end_date: Option<String>,
30    pub status: String, // "Active"
31}
32
33/// Busca ofertas ativas para PC
34pub async fn fetch_giveaways(app: &AppHandle) -> Result<Vec<Giveaway>, String> {
35    let cache_key = "gamerpower_list_active";
36    let url = "https://www.gamerpower.com/api/giveaways?platform=pc&type=game&sort-by=popularity";
37
38    // 1. Tenta buscar ONLINE
39    match HTTP_CLIENT.get(url).send().await {
40        Ok(res) => {
41            if res.status().is_success() {
42                let giveaways: Vec<Giveaway> = res.json().await.map_err(|e| e.to_string())?;
43
44                // Filtra apenas ativos
45                let active_ones: Vec<Giveaway> = giveaways
46                    .into_iter()
47                    .filter(|g| g.status == "Active")
48                    .collect();
49
50                // Sucesso: Salva a lista filtrada no Cache
51                if let Ok(conn) = app.state::<AppState>().metadata_db.lock() {
52                    if let Ok(json) = serde_json::to_string(&active_ones) {
53                        // Usamos "gamerpower" como source
54                        let _ = cache::save_cached_api_data(&conn, "gamerpower", cache_key, &json);
55                    }
56                }
57
58                return Ok(active_ones);
59            }
60        }
61        Err(_) => {} // Fallback
62    }
63
64    // 2. FALLBACK: Cache Offline
65    if let Ok(conn) = app.state::<AppState>().metadata_db.lock() {
66        if let Some(payload) = cache::get_stale_api_data(&conn, "gamerpower", cache_key) {
67            if let Ok(cached_giveaways) = serde_json::from_str::<Vec<Giveaway>>(&payload) {
68                return Ok(cached_giveaways);
69            }
70        }
71    }
72
73    Err("Não foi possível carregar jogos grátis (sem conexão e sem cache).".to_string())
74}