
    .Kiy&              	       `   d Z ddlZddlZddlZddlmZmZ ddlmZmZm	Z	m
Z
 ddlZddlZ G d d      ZdadefdZed	k(  r ed
        ed        ed
        e       Zej'                         Z ed ee       d       ej-                  dd      Z ed ee              edd D ]/  Z edej3                  d       dej3                  d       d       1 ej5                  d      Zer- edej3                  d       dej3                  d       d        ed        ed       yy)z
TheSportsDB Data Fetcher
Fetches historical game data from TheSportsDB Premium API

Premium API Key: 428892
Docs: https://www.thesportsdb.com/api.php
    N)datetime	timedelta)DictListAnyOptionalc                   d   e Zd ZdZdZde ZdZdZdddd	d
dddddddddddZd0de	fdZ
d1de	dede	fdZde	dee   fdZde	deddfd Zd2de	ded!edefd"Zdee   fd#Zd3d$ed%edee   fd&Zd4d$ed%edee   fd'Zd(e	dee   fd)Zd$ed*e	dee   fd+Zd,edefd-Zd1d.ee	   dee	ee   f   fd/Zy)5TheSportsDBFetcherzf
    Fetches sports data from TheSportsDB API.
    Includes caching to avoid redundant API calls.
    428892z(https://www.thesportsdb.com/api/v1/json/z'https://www.thesportsdb.com/api/v2/jsoni '   i  i  i  i  i  i  i'  i#  i  iH  i  i  i[  i]  )epllaliga
bundesligaseriealigue1mlsuclnflnbanhlmlbncaafncaabufcboxing	cache_dirc                 @    || _         t        j                  |d       y)z{
        Initialize the fetcher.
        
        Args:
            cache_dir: Directory to store cached responses
        T)exist_okN)r   osmakedirs)selfr   s     8/var/www/html/eventheodds/scripts/thesportsdb_fetcher.py__init__zTheSportsDBFetcher.__init__:   s     #
I-    Nendpointparamsreturnc                     t        j                  |xs i d      }d| d| }t        j                  |j	                               j                         S )z+Generate a unique cache key for the requestT)	sort_keyszthesportsdb::)jsondumpshashlibmd5encode	hexdigest)r!   r%   r&   	param_strkey_strs        r"   _get_cache_keyz!TheSportsDBFetcher._get_cache_keyD   sG    JJv|t<	 
!I;7{{7>>+,6688r$   	cache_keyc                    t         j                  j                  | j                  | d      }t         j                  j	                  |      rt	 t        |d      5 }t        j                  |      }ddd       j                  dd      }t        j                         |z
  | j                  k  r|j                  d      S 	 yy# 1 sw Y   SxY w# t        j                  t        f$ r Y yw xY w)zGet cached response if valid.jsonrN	cached_atr   data)r   pathjoinr   existsopenr+   loadgettimeCACHE_DURATIONJSONDecodeErrorIOError)r!   r4   
cache_filefcachedr8   s         r"   _get_from_cachez"TheSportsDBFetcher._get_from_cacheJ   s    WW\\$..YKu2EF
77>>*%*c* *a!YYq\F* #JJ{A6	99;*T-@-@@!::f-- A
 * * (('2 s+   C C0AC CC C*)C*r9   c                    t         j                  j                  | j                  | d      }	 t	        |d      5 }t        j                  t        j                         |d|       ddd       y# 1 sw Y   yxY w# t        $ r Y yw xY w)zSave response to cacher6   w)r8   r9   N)	r   r:   r;   r   r=   r+   dumpr@   rC   )r!   r4   r9   rD   rE   s        r"   _save_to_cachez!TheSportsDBFetcher._save_to_cache[   s|    WW\\$..YKu2EF
	j#& !		!%    
  		s.   A< ,A0'A< 0A95A< 9A< <	BB	use_cachec                 |   |xs i }|r'| j                  ||      }| j                  |      }||S | j                   d| }	 t        j                  ||d      }|j                          |j                         }|r| j                  |       |S # t        j                  $ r}	t        d|	        Y d}	~	yd}	~	ww xY w)a  
        Fetch data from TheSportsDB API.
        
        Args:
            endpoint: API endpoint (e.g., 'all_leagues.php')
            params: Query parameters
            use_cache: Whether to use cache
            
        Returns:
            API response data
        N/   )r&   timeoutz"[TheSportsDB] API request failed: )
r3   rG   BASE_URL_V1requestsr?   raise_for_statusr+   rK   RequestExceptionprint)
r!   r%   r&   rL   r4   rF   urlresponser9   es
             r"   
_fetch_apizTheSportsDBFetcher._fetch_apih   s     2 ++Hf=I)))4F! !!"!H:.	||CCH%%'==?D ##It4K(( 	6qc:;	s   AB B;#B66B;c                 P    | j                  d      }|r|j                  dg       S g S )zGet all available leagueszall_leagues.phpleaguesrY   r?   )r!   r9   s     r"   get_all_leaguesz"TheSportsDBFetcher.get_all_leagues   s)    01*.txx	2&6B6r$   	league_idlimitc                 h    | j                  dd|i      }|r|j                  dg       ng }|r|d| S g S )a  
        Get past events for a league.
        
        Args:
            league_id: TheSportsDB league ID
            limit: Number of events to fetch (max varies by league)
            
        Returns:
            List of past event dictionaries
        zeventspastleague.phpideventsNr\   r!   r^   r_   r9   rb   s        r"   get_past_eventsz"TheSportsDBFetcher.get_past_events   sA     5i7HI+/(B'R!'vfu~/R/r$   c                 h    | j                  dd|i      }|r|j                  dg       ng }|r|d| S g S )z Get upcoming events for a leaguezeventsnextleague.phpra   rb   Nr\   rc   s        r"   get_next_eventsz"TheSportsDBFetcher.get_next_events   s?    5i7HI+/(B'R!'vfu~/R/r$   	team_namec                 h    | j                  dd|i      }|r|j                  dg       ng }|r|d   S dS )zSearch for a team by namezsearchteams.phptteamsr   Nr\   )r!   rg   r9   rj   s       r"   search_teamzTheSportsDBFetcher.search_team   s=    03	2BC)-"%2 uQx*d*r$   seasonc                 X    | j                  d||d      }|r|j                  dg       S g S )a   
        Get all events for a league in a specific season.
        
        Args:
            league_id: TheSportsDB league ID
            season: Season string (e.g., '2024-2025' or '2024')
            
        Returns:
            List of events
        zeventsseason.php)ra   srb   r\   )r!   r^   rl   r9   s       r"   get_events_by_seasonz'TheSportsDBFetcher.get_events_by_season   s2     1)&3QR)-txx"%525r$   eventc                 :   |j                  d      }|j                  d      }d}|+|)	 t        |      }t        |      }||kD  rd}n
||kD  rd}nd}|j                  d      |j                  d      |j                  d	      |j                  d
      |j                  d      |j                  d      |j                  d      |j                  d      ||||j                  d      |j                  d      |j                  d      dS # t        t        f$ r Y w xY w)z
        Normalize event data to a common format for backtesting.
        
        Args:
            event: Raw event from API
            
        Returns:
            Normalized event dictionary
        intHomeScoreintAwayScorependinghome_winaway_windrawidEvent	dateEventstrTime	strLeagueidLeague	strSeasonstrHomeTeamstrAwayTeamstrVenue	strStatusstrSport)event_iddater@   leaguer^   rl   	home_team	away_team
home_score
away_scoreresultvenuestatussport)r?   int
ValueError	TypeError)r!   rp   r   r   r   has          r"   normalize_eventz"TheSportsDBFetcher.normalize_event   s    YY~.
YY~.
 !j&<

O
Oq5'FU'F#F
 		),IIk*IIi(ii,:.ii,=1=1$$YYz*ii,YYz*
 	
 	* s   (D DDseasonsc           
      b   |ddg}i }| j                   j                         D ]  \  }}t        d| d| d       g }|D ]a  }| j                  ||      }|s|D cg c]  }| j	                  |       }	}|j                  |	       t        d| dt        |       d       c |||<    |S c c}w )	a  
        Fetch events for all priority leagues.
        
        Args:
            seasons: List of seasons to fetch (e.g., ['2024-2025', '2023-2024'])
            
        Returns:
            Dictionary mapping league key to list of normalized events
        z	2024-2025z	2023-2024z[TheSportsDB] Fetching z (ID: z)...  - z: z events)PRIORITY_LEAGUESitemsrU   ro   r   extendlen)
r!   r   
all_eventskeyr^   league_eventsrl   rb   rX   
normalizeds
             r"   fetch_priority_leaguesz)TheSportsDBFetcher.fetch_priority_leagues   s     ?"K0G
"3399; 	,NC+C5ykFGM! A229fECI!Ja$"6"6q"9!JJ!J!((4D3v;-w?@A ,JsO	,  "Ks   B,)z./data/cache/thesportsdb)N)NT)2   )   )__name__
__module____qualname____doc__API_KEYrQ   BASE_URL_V2rA   r   strr#   r   r3   r   r   rG   rK   boolrY   r   r]   r   rd   rf   rk   ro   r   r    r$   r"   r
   r
      s   
 G<WIFK;K 'N
    -2.# .9s 9D 9C 9 # " 3 4 $3 $ $ $X[ $L7d 7
0 0S 0$t* 00 0S 0$t* 0+S +Xd^ +6c 63 64: 6+
T +
d +
Zd3i 4TRVZCX r$   r
   r'   c                  .    t         
t               a t         S )z,Get or create the singleton fetcher instance)_fetcher_instancer
   r   r$   r"   get_fetcherr     s      .0r$   __main__z<============================================================zTheSportsDB Fetcher Testu   
✓ Found z leaguesr      )r_   u   
✓ EPL past events:    r   strEventz (ry   )Arsenalu   
✓ Found team: strTeamr{   z=
============================================================u(   ✅ TheSportsDB Fetcher tests completed!)r   r   r+   rR   r   r   typingr   r   r   r   r-   r@   r
   r   r   r   rU   fetcherr]   r[   r   rd   
epl_eventsrX   r?   rk   teamr   r$   r"   <module>r      sY   
   ( , ,  r rl  '  z	(O	
$%	(OmG %%'G	LWh
/0 ((Q(7J	#C
O#4
56^ AQUU:&'r!%%*<)=Q?@A y)D"488I#6"7r$((;:O9PPQRS	/	
451 r$   