
    NiJ                      z   d Z ddlZddlZddlZddlZddlZddlZddlZddl	m	Z	m
Z
mZ ej                  j                  dej                  j                  ej                  j                  e                   ddlmZ dZdZdeiZdd	d
ddddddddddddZdddddZd Zd Zd Zd Zd  Zd! Zed"k(  r e        yy)#a  
Backfill 2 weeks of historical data from TheSportsDB v2.
Fetches full season schedules for priority leagues and filters to last 14 days.
Also fetches event details (lineups, stats, timelines, highlights) for all finished games.

Run once manually, then the cron jobs take over.
    N)datetimetimezone	timedelta)normalize_to_full428892z'https://www.thesportsdb.com/api/v2/jsonz	X-API-KEY)nbaNBA	2025-2026)nflNFL2025)nhlNHLr
   )mlbMLBr   )ncaabNCAABr
   )ncaafNCAAFr   )eplzEnglish Premier Leaguer
   )laligazSpanish La Ligar
   )
bundesligazGerman Bundesligar
   )serieazItalian Serie Ar
   )ligue1zFrench Ligue 1r
   )mlszAmerican MLS2026)uclzUEFA Champions Leaguer
   )ufcUFCr   )43874391438044244607447943284335433143324334434644804443zlookup/event_lineupzlookup/event_statszlookup/event_timelinezlookup/event_highlights)lineupstatstimeline
highlightsc                     t        dd      5 } | D ]b  }|j                  d      s|j                  dd      d   j                         j                  d      j                  d      d   c cd d d        S  	 d d d        y	# 1 sw Y   y	xY w)
Nz/var/www/html/eventheodds/.envrzSPORTS_DATABASE_URL==   "?r    )open
startswithsplitstrip)flines     scripts/backfill_tsdb_2weeks.pyload_db_urlr@   1   s    	.	4 N 	ND56zz#q)!,224::3?EEcJ1MMN N	NN 	N s   A?AA?4A??Bc                     t        j                  t        j                  | d      j	                               j                         S )NT)	sort_keys)hashlibsha256jsondumpsencode	hexdigest)datas    r?   rD   rD   9   s.    >>$**TT:AACDNNPP    c                 J    | y 	 t        |       S # t        t        f$ r Y y w xY w)N)int
ValueError	TypeError)vs    r?   _intrP   =   s/    y1v	" s   
 ""c                    t          d|  d| }	 t        j                  |t        d      }|j                  dk7  r t        d|j                   d|  d|        g S |j                         }|j                  d      xs( |j                  d	      xs |j                  d
      xs g S # t        $ r}t        d|        g cY d }~S d }~ww xY w)Nz/schedule/league//   headerstimeout   z	    HTTP z for scheduleeventstablez    Error: )BASErequestsgetHEADERSstatus_codeprintrE   	Exception)	league_idseasonurlresprI   es         r?   fetch_seasonrg   F   s    F#I;ax
8C	||C"=s"Id../uYKqIJIyy{xx
#Ttxx'9TTXXg=NTRTT A3 	s%   A
B& A
B& &	C	/C>C	C	c                    t          d|  d| }	 t        j                  |t        d      }|j                  dk7  ry |j                         }|D ])  }||   s	t        ||   t              r||   c S ||   gc S  y # t        $ r Y y w xY w)NrR      rT   rW   )	r[   r\   r]   r^   r_   rE   
isinstancelistra   )endpointevent_idrd   re   rI   keys         r?   fetch_detailro   T   s    F!H:Qxj
)C
||C"=s"yy{ 	QCCy$.tCy$$?tCyPd3i[P	Q  s(   +A; A; A; 1A; 9A; ;	BBc                  	   t               } | st        d       y t        j                  |       }|j	                         }t        j                  t        j                        }|t        d      z
  }|j                  d      }d}d}d}g }	t        d| d       t        d       t        j                         D ]^  \  }
\  }}}t        d	| d
| d       t        |
|      }|st        d       7|D cg c]  }|j                  d      xs d|k\  s| }}t        dt        |       dt        |       d       |D ]  }|j                  dd      }|sd| }|j                  dd      }|j                  d      xs |j                  d      xs d}|rt        |      dk\  r
| d|d d  n| d}t!        |j                  d      xs |j                  dd      |      }t!        |j                  d      xs d|      }t#        |j                  d             }t#        |j                  d!            }||d"nd#}	 t%        |j'                  d$      d         }|j/                  d%|||||||||t1        j2                  |      ||f       |d&z  }t5        |      }|j/                  d'||||t1        j2                  |      |f       ||j6                  z  }|d"k(  s|	j9                  |        |j;                          t=        j>                  d(       a t        d)d        t        d*|        t        d+|        t        d,t        |	              t        d-       t@        j                         D ]  \  }}t        d.| d/       tC        |	      D ]  \  } }!tE        ||!      }"|"rb|"D ]]  }#tG        |#tH              s|!|#d<   t5        |#      }$	 |j/                  d0||$|t1        j2                  |#      |f       ||j6                  z  }_ | d&z   d1z  dk(  s|j;                          t        d2| d&z    d3t        |	       d4       t=        j>                  d5        |j;                           |jO                          t        d6| d7| d8| d9       y c c}w # t(        t*        f$ r |j,                  }Y `w xY w# tJ        $ r |jM                          Y ,w xY w):NzERROR: No SPORTS_DATABASE_URL   )daysz%Y-%m-%dr   zBackfilling events from z	 to todayz<============================================================z
--- z (z) ---z  No events found	dateEventr8   z  z total events, z in last 14 daysidEventtsdb_strTimestrTimeLocalz00:00:00       z	 00:00:00strHomeTeamstrEventUnknownstrAwayTeamTBDintHomeScoreintAwayScorefinal	scheduled-ag  
                INSERT INTO "SportsGame" (
                    league, season, "gameDate", "homeTeam", "awayTeam",
                    "externalGameId", "homeScore", "awayScore", status, raw,
                    "createdAt", "updatedAt"
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                ON CONFLICT (league, "externalGameId") DO UPDATE SET
                    "homeScore" = COALESCE(EXCLUDED."homeScore", "SportsGame"."homeScore"),
                    "awayScore" = COALESCE(EXCLUDED."awayScore", "SportsGame"."awayScore"),
                    status = CASE WHEN EXCLUDED.status = 'final' THEN 'final' ELSE "SportsGame".status END,
                    raw = EXCLUDED.raw,
                    "updatedAt" = EXCLUDED."updatedAt"
                WHERE EXCLUDED."homeScore" IS NOT NULL OR "SportsGame"."homeScore" IS NULL
            r5   a)  
                INSERT INTO "ExternalFeedRecord"
                    (source, kind, league, season, "contentHash", "fetchedAt", raw, "createdAt")
                VALUES ('thesportsdb', 'schedule', %s, %s, %s, %s, %s, %s)
                ON CONFLICT (source, "contentHash") DO NOTHING
            g      ?
zGames upserted: zFeed records: zFinished events to enrich: z
Fetching event details...z
  --- z ---aa  
                            INSERT INTO "ExternalFeedRecord"
                                (source, kind, league, season, "contentHash", "fetchedAt", raw, "createdAt")
                            VALUES ('thesportsdb', %s, NULL, NULL, %s, %s, %s, %s)
                            ON CONFLICT (source, "contentHash") DO NOTHING
                           z    rR   z
 processedg333333?z
BACKFILL COMPLETE: z games, z feed records, z detail records)(r@   r`   psycopg2connectcursorr   nowr   utcr   strftimePRIORITY_LEAGUESitemsrg   r]   lenr   rP   rL   r;   rM   
IndexErroryearexecuterE   rF   rD   rowcountappendcommit_timesleepDETAIL_ENDPOINTS	enumeratero   rj   dictra   rollbackclose)%db_urlconncurr   cutoff
cutoff_strtotal_games
total_feedtotal_detailsfinished_event_idsrb   codenamerc   rY   rf   recentevrm   ext_iddate_strtime_str	game_datehomeaway
home_score
away_scorestatusseason_yearcontent_hashkindrl   ieidrecordsrecchs%                                        r?   mainr   c   s   ]F-.F#D
++-C
,,x||
$C9"%%F,JKJM	$ZL	
:;	(O+;+A+A+C C'	'D$tfBvhe,-i0%' $Pk(:(@bZ'O!PP3v;-s6{m;KLM 5	4Bvvi,HXJ'Fvvk2.Hvvi(PBFF>,BPjH8@S]VWEW8*Ahrl^4`h_iir]sI$RVVM%:%[bffZQZ>[]abD$RVVM%:%CeTJDbff^45Jbff^45J * 6:;QWWbF'!&,,s"3A"67
 KK  k9dD
J

2S$ 1K "":LKK 
 c4::b>3GI #,,&J "))(3k5	4n 	CGCJ 
Bxj/	[M
*+	N:,
'(	',>(?'@
AB 
')*002 hd#$ 23 	!FAs"8S1G" (C%c40 %(C	NB	( %
 #BTZZ_cBD &5(  A|q QqSE3'9#:";:FGC -	!0 	58 	JJL	!+hzl/R_Q``o
pqC Q* 
+ '!hh'B % ((s0   2RR>R9R?R<;R<?S	S	__main__)__doc__ossysrE   rC   r\   r   timer   r   r   r   pathinsertdirnameabspath__file__
team_namesr   API_KEYr[   r^   r   r   r@   rD   rP   rg   ro   r   __name__ rJ   r?   <module>r      s    
 
      2 2 277??277??8#<= > (
0
  ("'"+&:6<65+9" $ $!'+	 Q}r@ zF rJ   