import { Injectable, Logger } from "@nestjs/common"; import axios from "axios"; /** * Spor Toto API response types * Source: https://sportotov2.iddaa.com/SporToto */ export interface SporTotoApiEvent { eventNo: number; eventName: string; // "Blackpool-Burton Albion" competitionName: string; // "İN1" eventDate: string; // "2026-03-28T18:00:00" result: string | null; winner: string | null; } export interface SporTotoApiDividend { winnerCount15?: number; dividend15?: number; winnerCount14?: number; dividend14?: number; winnerCount13?: number; dividend13?: number; winnerCount12?: number; dividend12?: number; } export interface SporTotoApiResponse { isSuccess: boolean; data: { payinBeginDate: string; payinEndDate: string; gameCycleNo: number; dividends: SporTotoApiDividend | null; events: SporTotoApiEvent[]; programName: string; nextDrawExpectedWins: number | null; } | null; message: string; error: string | null; info: string | null; dateTime: string | null; } @Injectable() export class TotoFetcherService { private readonly logger = new Logger(TotoFetcherService.name); private readonly apiUrl = "https://sportotov2.iddaa.com/SporToto"; /** * Fetch current bulletin from Spor Toto API */ async fetchCurrentBulletin(): Promise { try { this.logger.log("Fetching current Spor Toto bulletin..."); const response = await axios.get(this.apiUrl, { timeout: 10000, headers: { Accept: "application/json", "User-Agent": "SuggestBet/1.0", }, }); if (!response.data?.isSuccess || !response.data?.data) { this.logger.warn( "Spor Toto API returned unsuccessful response", response.data?.message, ); return null; } this.logger.log( `Fetched bulletin: Cycle ${response.data.data.gameCycleNo} — ${response.data.data.programName} (${response.data.data.events.length} events)`, ); return response.data; } catch (error) { if (axios.isAxiosError(error)) { this.logger.error( `Spor Toto API error: ${error.message}`, error.response?.status, ); } else { this.logger.error("Spor Toto fetch failed", error); } return null; } } /** * Parse "Blackpool-Burton Albion" → { home: "Blackpool", away: "Burton Albion" } */ parseEventName(eventName: string): { homeTeam: string; awayTeam: string; } { const parts = eventName.split("-"); if (parts.length >= 2) { return { homeTeam: parts[0].trim(), awayTeam: parts.slice(1).join("-").trim(), }; } return { homeTeam: eventName, awayTeam: "" }; } /** * Map API result/winner to TotoMatchResult enum value * API returns: "1" (HOME), "0" (DRAW), "2" (AWAY) */ mapResultToEnum(winner: string | null): "HOME" | "DRAW" | "AWAY" | null { if (!winner) return null; switch (winner) { case "1": return "HOME"; case "0": case "X": return "DRAW"; case "2": return "AWAY"; default: return null; } } }