
    Ni|s                        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
 ddlmZ ddlmZmZmZmZmZ ddlZej(                  j+                  dej(                  j-                  ej(                  j/                  e                   ddlmZ  ee      j6                  j6                  dz  Zej;                         r ee      5 ZeD ]  Z e jC                         se jE                  d      r&d	e v s+e jC                         jG                  d	d
      \  Z$Z%ejL                  jO                  e$e%jC                  d      jC                  d              	 ddd       ejL                  jQ                  dd      Z)ejL                  jQ                  d      Z*ejL                  jQ                  dd      Z+e*s e,d        ejZ                  d
       i ddddddddddddddddd dddd!d"d#d$dd%d&d'd
dd(d)d*ddd+d,d
d-dd.d,d
d-dd/d0d'd*dd1d2d'd*dd3d4d'd*dd5d6d'd*dd7d8d'd*dd9d:dddd;d<dd-dZ.g d=Z/ G d> d?      Z0d@ee1   fdAZ2d@ee3   fdBZ4dCed@efdDZ5dCed@eee1   ee1   f   fdEZ6dCed@ee   fdFZ7dG Z8dHee   dIe9d@ee1e1f   fdJZ:dKee   d@e1fdLZ;dMee   dIe9d@e1fdNZ<dHee   dIe9d@e1fdOZ=dIe9dPe9d@ee9e9f   fdQZ>dR Z?e@dSk(  r e?        yy# 1 sw Y   xY w)Ta  
SportsGameOdds API - Historical Data Backfill Script

Backfills historical games, odds, scores, and player stats from SportsGameOdds API.
Supports date ranges for 2024, 2025, and 2026 seasons.

Usage:
    python scripts/backfill_sportsGameOdds.py [league] [--start YYYY-MM-DD] [--end YYYY-MM-DD]
    python scripts/backfill_sportsGameOdds.py --all-leagues --year 2025
    python scripts/backfill_sportsGameOdds.py nba --season 2024-25

Examples:
    python scripts/backfill_sportsGameOdds.py nba --start 2025-01-01 --end 2025-12-31
    python scripts/backfill_sportsGameOdds.py --all-leagues --year 2025
    python scripts/backfill_sportsGameOdds.py nfl --season 2025-26
    N)datetimetimezone	timedelta)Path)DictListAnyOptionalTuple)normalize_to_fullz.env#=   "'SPORTSGAMEODDS_BASE_URLz!https://api.sportsgameodds.com/v2SPORTSGAMEODDS_API_KEYSPORTS_DATABASE_URL z4ERROR: SPORTSGAMEODDS_API_KEY not set in environmentnbaNBA
      )idseason_start
season_endnflNFL	      mlbMLB   nhlNHLncaabNCAAB      ncaafNCAAF   wnbaWNBA   mmaUFC   ufceplEPLlaligaLALIGAserieaSERIEA
bundesliga
BUNDESLIGAligue1LIGUE1uclUEFA_CHAMPIONS_LEAGUEmlsMLS)r   r   r!   r$   r&   r*   r0   r4   r6   r8   r:   r<   c                   v    e Zd ZdZefdedefdZddededefd	Z	 dd
ededede	de
e   f
dZd
ede
e   fdZy)SportsGameOddsBackfiller0Backfill historical data from SportsGameOdds APIapi_keybase_urlc                     || _         || _        t        j                         | _        | j                  j
                  j                  |dd       d| _        d| _        d| _	        y )Nzapplication/json)z	x-api-keyzContent-Typer   )
rE   rF   requestsSessionsessionheadersupdaterequests_madeevents_fetchedplayers_fetched)selfrE   rF   s      "scripts/backfill_sportsGameOdds.py__init__z!SportsGameOddsBackfiller.__init__S   s]     '')## .%
 	      Nendpointparamsreturnc                 l   | j                    d| }d}t        |      D ]  }	 | j                  j                  ||d      }| xj                  dz  c_        |j
                  dk(  r7t        d|dz   dz        }t        d| d	       t        j                  |       }|j
                  d
k(  rdddc S |j                          |j                         c S  dddS # t        j                  j                  $ r<}||dz
  k  rt        j                  d       Y d}~dt        |      dcY d}~c S d}~ww xY w)z!Make API request with retry logic/r#   <   )rU   timeoutr   i  r   z  Rate limited, waiting zs...i  FzInvalid API key)successerrorr/   NzMax retries exceeded)rF   rangerJ   getrM   status_codeminprinttimesleepraise_for_statusjsonrH   
exceptionsRequestExceptionstr)	rP   rT   rU   urlmax_retriesattemptrespwaites	            rQ   _requestz!SportsGameOddsBackfiller._request_   s+   q
+[) 	;G;||''FB'G""a'"##s*rGaK2#56D4TF$?@JJt$##s*',7HII%%'yy{"	;, !+ABB &&77 ;[1_,JJqM#(3q6::	;s0   A8CC2CD37D.D.&D3.D3	league_id
start_dateend_dateinclude_completedc           
         g }d}d}|| d| ddd}|sd|d<   	 |d
z  }|r||d<   | j                  d|      }	|	j                  dd	      rd|	v r!t        d|	j                  dd              	 |S |	j                  dg       }
|
s	 |S |j                  |
       | xj                  t        |
      z  c_        t        d| dt        |
       dt        |       d       |	j                  d      }|s	 |S t        j                  d       )z0Fetch all events in a date range with paginationNr   z
T00:00:00Zz
T23:59:59Zd   )leagueIDstartsAfterstartsBeforelimittrueoddsAvailableTr   cursoreventsr[   r\   z    Error: zUnknown errordataz
    Batch : z events (total: )
nextCursorg333333?)ro   r^   ra   extendrN   lenrb   rc   )rP   rp   rq   rr   rs   
all_eventsr|   batchrU   resultr}   s              rQ   fetch_events_in_rangez.SportsGameOddsBackfiller.fetch_events_in_range|   sD    
 "(\4'j
3	
 !&,F?#QJE#)x ]]8V4F::i.'V2CFJJw$H#IJK$ ! ZZ+F  f%3v;.JugRF}4DS_DUUVWXZZ-F
  JJsO3 rS   c                 V   g }d}	 |dd}|r||d<   | j                  d|      }|j                  dd      s	 |S |j                  dg       }|s	 |S |j                  |       | xj                  t	        |      z  c_        |j                  d	      }|s	 |S t        j                  d
       )zFetch all players for a leagueNTi  )rv   ry   r|   playersr[   r~   r   g?)ro   r^   r   rO   r   rb   rc   )rP   rp   all_playersr|   rU   r   r   s          rQ   fetch_playersz&SportsGameOddsBackfiller.fetch_players   s    "+c:F#)x ]]9f5F::i.  jj,G  w'  CL0 ZZ-F  JJsO+ rS   )N)T)__name__
__module____qualname____doc__SGO_BASE_URLrh   rR   r   ro   boolr   r   r    rS   rQ   rC   rC   P   s    :5A 
! 
!s 
!C Cd Cd C< 9=-s - -s -15-AEd-^s tDz rS   rC   rV   c                     | yt        | t        t        f      rt        |       S t        | t              r	 t        | j	                  dd            S y# t
        $ r Y yw xY w)zParse odds string to integerN+r   )
isinstanceintfloatrh   replace
ValueErrorvalues    rQ   parse_odds_valuer      s`    }%#u&5z%	u}}S"-..   		s   A 	AAc                     | yt        | t        t        f      rt        |       S t        | t              r	 t        |       S y# t        $ r Y yw xY w)zParse line value to floatN)r   r   r   rh   r   r   s    rQ   parse_line_valuer      sT    }%#u&U|%	<   		s   
A 	AAeventc           	      L   | j                  di       }|j                  di       }|j                  di       }t        |j                  d      xs |j                  d            }t        |j                  d      xs |j                  d            }|j                  di       }t        |j                  d      xs |j                  d            }|j                  d	i       }t        |j                  d
      xs |j                  d            }	t        |j                  d      xs |j                  d            }
t        |j                  d      xs |j                  d            }t        |j                  d      xs |j                  d            }||||r| nd|	|
||dS )zExtract odds data from eventoddszpoints-home-game-ml-homezpoints-away-game-ml-awaybookOddsfairOddszpoints-home-game-sp-home
bookSpread
fairSpreadzpoints-all-game-ou-overbookOverUnderfairOverUnderopenBookOddsopenFairOddsopenBookSpreadopenFairSpreadopenBookOverUnderopenFairOverUnderN)moneylineHomemoneylineAway
spreadHome
spreadAwaytotalopenMoneylineHomeopenSpreadHome	openTotal)r^   r   r   )r   	odds_dataml_homeml_awayhome_mlaway_mlsp_homespread_homeou_overr   open_home_mlopen_spread
open_totals                rQ   extract_oddsr      ss   		&"%I mm6;Gmm6;Gw{{:6Q'++j:QRGw{{:6Q'++j:QRG mm6;G"7;;|#<#YL@YZK mm5r:GW[[9YW[[=YZE $GKK$?$^7;;~C^_L"7;;/?#@#aGKKP`DabK!'++.A"B"fgkkReFfgJ ! !&1{lt)%	 	rS   c                    | j                  di       }|j                  di       }|j                  di       j                  d      }|j                  di       j                  d      }|T| j                  di       }|j                  di       j                  d      }|j                  di       j                  d      }||fS )zExtract final scores from eventresultsgamehomepointsawayteamsscorer^   )r   r   game_results
home_score
away_scorer   s         rQ   extract_scoresr   	  s    ii	2&G;;vr*L!!&"-11(;J!!&"-11(;J 		'2&YYvr*..w7
YYvr*..w7
z!!rS   c                     g }| j                  d      }| j                  d      }| j                  di       }|j                  d      }|rPt        j                  |j                  dd            }|j                  dk\  r|j
                  n|j
                  dz
  }n|S | j                  d	i       }| j                  d
i       }	| j                  di       }
|
j                  di       j                  di       j                  dd      }|
j                  di       j                  di       j                  dd      }|j                  di       }dD ]  }|j                  |i       }|dk(  r|n|}|dk(  r|n|}|j                  d
i       }|j                         D ]c  \  }}t        |t              s|	j                  |i       }|j                  d|      }|j                  d      }|j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d       |j                  d!      d"}|j                         D ]1  \  }}|	|j                  ||d#| |||||||t        |      d$       3 f  |S )%z,Extract player game stats from event resultseventIDrv   statusstartsAtZ+00:00   r   r   r   r   r   namesshortUNKr   r   )r   r   namepositionr   reboundsassistsstealsblocks	turnoversminutesfieldGoalsMadefieldGoalsAttemptedthreePointersMadethreePointersAttemptedfreeThrowsMadefreeThrowsAttempted)r   r   r   r   r   r   r   r   r   r   r   r   r   zg:)leagueseasongameKeygameDateplayerExternalId
playerNamer   teamopponentstatKeyr   )r^   r   fromisoformatr   monthyearitemsr   dictappendr   )r   statsevent_idr   r   
start_time	game_dater   r   players_datar   	home_team	away_teamr   team_keyteam_results	team_namer   players_in_team	player_idplayer_statsplayer_infoplayer_namer   stat_mappingsstat_keyr   s                              rQ   extract_player_statsr    s   Eyy#HYYz"FYYx$FJ'J**:+=+=c8+LM	#,??a#7Y^^a=Oii	2&G99Y+L IIgr"E		&"%))'26::7EJI		&"%))'26::7EJI ;;vr*L$ /#''"5!)V!3I	 (F 29	 '**9b9'6'<'<'> '	#I|lD1&**9b9K%//&)<K"z2H '**84(,,Z8'++I6&**84&**84)--k:'++I6"."2"23C"D'3'7'78M'N%1%5%56I%J*6*:*:;S*T"."2"23C"D'3'7'78M'NM  $1#6#6#8 %$LL"("(%'z?$-,5&1$, )$,#+!&u" 3'	/b LrS   c                     t         sy	 t         j                  dd      } d| v r| j                  d      d   } | j                  d      \  }}|j                  d      \  }}|j                  d      \  }}d|v r|j                  d      \  }}n|d	}}t        j                  |t        |      |||
      }	|	S # t        $ r}
t        d|
        Y d}
~
yd}
~
ww xY w)zGet PostgreSQL connectionNzpostgresql://r   ?r   @:rX   5432)hostportdatabaseuserpasswordzDatabase connection error: )SPORTS_DB_URLr   splitpsycopg2connectr   	Exceptionra   )ri   	user_passhost_dbr  r  	host_portr  r  r  connrn   s              rQ   get_db_connectionr  g  s    ##OR8#:))C.#C YYs^	7"-h%mmC0	8)"-JD$"F$DT
  +A3/0s   B+B5 5	C>CCr}   r   c                    | r|sy| j                         }d}d}|D ]  }	 |j                  d      }|j                  di       }t        |j                  di       j                  di       j                  dd      xs2 |j                  di       j                  di       j                  d	d
      |      }	t        |j                  di       j                  di       j                  dd      xs2 |j                  di       j                  di       j                  d	d
      |      }
|j                  di       }|j                  d      }|j                  d      rd}n*|j                  d      rd}n|j                  d      rd}nd}t        |      \  }}t	        |      }|rPt        j                  |j                  dd            }|j                  dk\  r|j                  n|j                  dz
  }n|j                  d||j                         f       |j                         }|r@|j                  d||||d   |d   |d   |d   |d   d||j                         f       |dz  }nC|j                  d|j                         |||	|
|||||d   |d   |d   |d   |d   df       |dz  } | j                          |j                          ||fS # t        $ r}Y d }~d }~ww xY w)!z Upsert games to SportsGame table)r   r   r   r   r   r   r   longr   r   r   r   r   r   	completedfinallive	cancelled	scheduledr   r   r   r   zu
                SELECT id FROM "SportsGame"
                WHERE "externalGameId" = %s AND league = %s
            a  
                    UPDATE "SportsGame" SET
                        "homeScore" = COALESCE(%s, "homeScore"),
                        "awayScore" = COALESCE(%s, "awayScore"),
                        status = %s,
                        "moneylineHome" = COALESCE(%s, "moneylineHome"),
                        "moneylineAway" = COALESCE(%s, "moneylineAway"),
                        "spreadHome" = COALESCE(%s, "spreadHome"),
                        "spreadAway" = COALESCE(%s, "spreadAway"),
                        total = COALESCE(%s, total),
                        "oddsSource" = %s,
                        "oddsUpdatedAt" = NOW(),
                        "updatedAt" = NOW()
                    WHERE "externalGameId" = %s AND league = %s
                r   r   r   r   r   sportsgameodds-backfilla  
                    INSERT INTO "SportsGame" (
                        league, season, "gameDate", "homeTeam", "awayTeam",
                        "externalGameId", "homeScore", "awayScore", status,
                        "moneylineHome", "moneylineAway", "spreadHome", "spreadAway",
                        total, "oddsSource", "oddsUpdatedAt", "createdAt", "updatedAt"
                    ) VALUES (
                        %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW(), NOW()
                    )
                    ON CONFLICT (league, season, "gameDate", "homeTeam", "awayTeam") DO UPDATE SET
                        "homeScore" = COALESCE(EXCLUDED."homeScore", "SportsGame"."homeScore"),
                        "awayScore" = COALESCE(EXCLUDED."awayScore", "SportsGame"."awayScore"),
                        status = EXCLUDED.status,
                        "moneylineHome" = COALESCE(EXCLUDED."moneylineHome", "SportsGame"."moneylineHome"),
                        "moneylineAway" = COALESCE(EXCLUDED."moneylineAway", "SportsGame"."moneylineAway"),
                        "spreadHome" = COALESCE(EXCLUDED."spreadHome", "SportsGame"."spreadHome"),
                        "spreadAway" = COALESCE(EXCLUDED."spreadAway", "SportsGame"."spreadAway"),
                        total = COALESCE(EXCLUDED.total, "SportsGame".total),
                        "oddsSource" = EXCLUDED."oddsSource",
                        "oddsUpdatedAt" = NOW(),
                        "updatedAt" = NOW()
                N)r|   r^   r   r   r   r   r   r   r   r   executelowerfetchoner  commitclose)r  r}   r   r|   insertedupdatedr   r   r   r   r   status_datar   r   r   r   r   r   r   existingrn   s                        rQ   upsert_gamesr-    sR   v[[]FHG [Z	yy+HIIgr*E)%))FB*?*C*CGR*P*T*TU[]_*`  +_didmdmntvxdyd}d}  F  HJ  eK  eO  eO  PW  Y^  e_  ag  hI)%))FB*?*C*CGR*P*T*TU[]_*`  +_didmdmntvxdyd}d}  F  HJ  eK  eO  eO  PW  Y^  e_  ag  hI))Hb1K$4J{+ (-$$%3E%:"J
&D$22:3E3Ec83TU	+4??a+?Y^^VWEW NN  FLLN+-
 (H   
F)4+@&\(:DM-x	( 1  , LLNFIy)j*f)4+@&\(:DM-+8 Aq[z 	KKM
LLNW  		s   GK2B7K	K$K$r   c                    | r|sy| j                         }d}|D ]  }	 |j                  d|d   |d   |d   |d   |d   |j                  d      |j                  d	      |j                  d
      |j                  d      |d   |d   f       |j                  dkD  r|dz  } | j                          |j                          |S # t        $ r
}Y d}~d}~ww xY w)zUpsert player game metricsr   a  
                INSERT INTO "PlayerGameMetric" (
                    league, season, "gameKey", "gameDate",
                    "playerExternalId", "playerName", position, team, opponent,
                    "statKey", value, "createdAt"
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())
                ON CONFLICT (league, season, "gameKey", "playerExternalId", "statKey")
                DO UPDATE SET value = EXCLUDED.value
            r   r   r   r   r   r   r   r   r   r   r   r   N)r|   r$  r^   rowcountr  r'  r(  )r  r   r|   r)  statrn   s         rQ   upsert_player_statsr1    s    u[[]FH 	NN  XXYjAQ'($((<*@$((:BV $((:"6Yg	 "A#* 	KKM
LLNO  		s   BC	CCr   c                    | r|sy| j                         }d}|D ]  }	 |j                  d|j                         |j                  d      |j                  d      |j                  d      |j                  d      t	        j
                  |      f       |j                  dkD  r|dz  } | j                          |j                          |S # t        $ r
}Y d}~d}~ww xY w)	zUpsert player recordsr   a  
                INSERT INTO "Player" (
                    league, "externalPlayerId", name, position, team, raw, "createdAt", "updatedAt"
                ) VALUES (%s, %s, %s, %s, %s, %s, NOW(), NOW())
                ON CONFLICT (league, "externalPlayerId") DO UPDATE SET
                    name = EXCLUDED.name,
                    position = COALESCE(EXCLUDED.position, "Player".position),
                    team = COALESCE(EXCLUDED.team, "Player".team),
                    "updatedAt" = NOW()
            playerIDr   r   teamIDr   N)
r|   r$  upperr^   re   dumpsr/  r  r'  r(  )r  r   r   r|   r)  playerrn   s          rQ   upsert_playersr8    s    w[[]FH 	NN 	 

:&

6"

:&

8$

6"" "A)0 	KKM
LLNO  		s   B	C	CCc           	         | r|sy| j                         }d}|D ]  }	 t        j                  |t              }t	        j
                  |j                               j                         }|j                  ddd|j                         ||f       |j                  dkD  r|dz  } | j                          |j                          |S # t        $ r Y w xY w)z%Save raw events to ExternalFeedRecordr   )defaulta  
                INSERT INTO "ExternalFeedRecord" (
                    source, kind, league, "contentHash", raw, "fetchedAt", "createdAt"
                ) VALUES (%s, %s, %s, %s, %s, NOW(), NOW())
                ON CONFLICT (source, "contentHash") DO NOTHING
            r#  
historicalr   )r|   re   r6  rh   hashlibmd5encode	hexdigestr$  r5  r/  r  r'  r(  )r  r}   r   r|   r)  r   raw_jsoncontent_hashs           rQ   save_external_feedrB  9  s    v[[]FH 	zz%5H";;x'89CCELNN 
 ,\6<<><Yabd "A" 	KKM
LLNO  		s   BC	CCr   c                 j   t         j                  | i       }|j                  dd      }|j                  dd      }d|v r#t        |j                  d      d         }|dz   }nt        |      }||kD  r|dz
  }|}n|}|}| d|dd}|dk(  r	| d	}	||	fS |d
v rd}
n
|dk(  rd}
nd}
| d|dd|
 }	||	fS )z=Get start and end dates for a season like '2024-25' or '2025'r   r   r   r2   -r   02dz-01-12-31)r   r#   r/   r   r,   r      r          )LEAGUESr^   r   r  )r   r   league_infoseason_start_monthseason_end_month
start_yearend_yearr   rq   rr   last_days              rQ   get_season_datesrQ  W  s   ++fb)K$;"|R8
f}c*1-.
> 6{ 00JHJH<q!3C 8<J 2Zv& x 22H"HHZq!1# 6azBxrS   c                  .   t        j                  d      } | j                  dddd       | j                  dt        d	
       | j                  dt        d
       | j                  dt        d
       | j                  dt        d
       | j                  ddd       | j                  ddd       | j                  ddd       | j                         }t        d       t        d       t        d       t        t              }|j                  d      }|j                  d      r|d   j                  di       }t        d|d   j                  dd               t        d!|j                  d"i       j                  d#d$       d%|j                  d"i       j                  d&d'              t        d(|j                  d"i       j                  d)d$       d%|j                  d"i       j                  d*d'              |j                  rt        }n|j                  j                         g}|j                  r%|j                   r|j                  }|j                   }n|j"                  r|j"                   d+}|j"                   d,}nd|j$                  rd }d }nSt'        j(                         j+                  d-      }t'        j(                         t-        d./      z
  j+                  d-      }|j.                  rd n	t1               }|rt        d0       n|j.                  st        d1       d$}	d$}
d$}d$}d$}|D ]?  }t2        j                  |      }|st        d2|        *|d3   }|j$                  rt5        ||j$                        \  }}t        d4d5        t        d6|        t        d7| d8|        t        d5        |j7                  |||      }|st        d9|        t9        d: |D              }t9        d; |D              }t9        d< |D              }t        d=t;        |              t        d>|        t        d?|        t        d@|        |	t;        |      z  }	|rt=        |||      \  }}t        dA| dB| dC       |
|z  }
||z  }t?        |||      }t        dD|        g }|D ]@  }|j                  dEi       j                  dF      s%tA        |      }|jC                  |       B |rtE        ||      }t        dG|        ||z  }|jF                  r@t        dH       |jI                  |      }|r"|r tK        |||      }t        dI|        ||z  }|s7t        dJ       |d dK D ]  }|j                  dLi       }|j                  dMi       j                  dNi       j                  dOd      }|j                  dPi       j                  dNi       j                  dOd      } |j                  dEi       j                  dQd      d dR }!tM        |      \  }"}#|j                  dEi       j                  dF      rdSndT}$|"r|# dU|" ndV}%t        dW|! dX|  dY| dZ|% d[|$ d\        B t        d]       t        d^       t        d       t        d_|	        t        d`|
        t        da|        t        db|        t        dc|        t        dd|jN                          |j                  d      }&|&j                  d      rf|&d   j                  di       }t        de|j                  d"i       j                  d&d'       df|j                  d"i       j                  d#d$              |r|jQ                          y y )gNrD   )descriptionr   r	  r   zLeague to backfill)nargsr:  helpz--startzStart date (YYYY-MM-DD))typerU  z--endzEnd date (YYYY-MM-DD)z--yearzYear to backfill (e.g., 2025)z--seasonz"Season to backfill (e.g., 2024-25)z--all-leagues
store_truezBackfill all major leagues)actionrU  z--include-playersz Also fetch and store player dataz	--dry-runzDon't save to databasezF======================================================================z"SPORTSGAMEODDS HISTORICAL BACKFILLzaccount/usager~   
rateLimitsz
API Tier: tierunknownzDaily requests: zper-dayzcurrent-requestsr   z / zmax-requests	unlimitedzDaily entities: zcurrent-entitieszmax-entitiesz-01-01rF  z%Y-%m-%dZ   )daysz Connected to PostgreSQL databasez&WARNING: Could not connect to databasez
Unknown league: r   
z<============================================================zBACKFILLING: zDate range: z to z  No events found for c              3   d   K   | ](  }|j                  d i       j                  d      s%d * yw)r   r  r   Nr   .0rn   s     rQ   	<genexpr>zmain.<locals>.<genexpr>  s(     RaQUU8R-@-D-D[-QRs   &00c              3   D   K   | ]  }|j                  d       sd  yw)r   r   Nr   ra  s     rQ   rc  zmain.<locals>.<genexpr>  s     ;aQUU6];s     c              3   >   K   | ]  }t        |      d    d  yw)r   Nr   )r   ra  s     rQ   rc  zmain.<locals>.<genexpr>  s     P~a/@/C/O!Ps   z  Total events: z  Completed games: z  With odds: z  With scores: z  Database: z inserted, z updatedz  External feed records: r   r  z  Player stats: z  Fetching players...z  Players: z
  Sample events:r#   r   r   r   mediumr   r   r   Final	ScheduledrD  TBDz    r   z @ z (z) []zG
======================================================================zBACKFILL SUMMARYzTotal events fetched: zDatabase inserts: zDatabase updates: zPlayer stats saved: zPlayers saved: zAPI requests made: z
Remaining daily requests: z - ))argparseArgumentParseradd_argumentrh   r   
parse_argsra   rC   SGO_API_KEYro   r^   all_leaguesALL_LEAGUESr   r%  startendr   r   r   nowstrftimer   dry_runr  rJ  rQ  r   sumr   r-  rB  r  r   r1  include_playersr   r8  r   rM   r(  )'parserargs
backfillerusagerate_limitsleaguesrq   rr   r  total_gamestotal_insertedtotal_updatedtotal_player_statstotal_playersr   rK  rp   r}   r  	with_oddswith_scoresr)  r*  
feed_count	all_statsr   r   stats_insertedr   players_insertedr   r   r   rr  r   r   r   	score_strfinal_usages'                                          rQ   mainr  ~  s   $$1cdF
UAUV
	2KL
c0GH
s1PQ

3WX
C_`
+LGij
L?WXD	(O	
./	(O)+6J 0EyyFm''b9
5=,,VY?@AB B!?!C!CDVXY!Z [[^_j_n_noxz|_}  `B  `B  CQ  S^  `_  _`  a  	b B!?!C!CDVXY!Z [[^_j_n_noxz|_}  `B  `B  CQ  S^  `_  _`  a  	b ;;$$&' zzdhhZZ
88			{&)
ii['	
 <<>**:6llnyb'99CCJO
 <<4%6%8D01\\67KNMM OPkk&)&vh/0%	 ;;#3FDKK#H J6(mi[)*ZLXJ78 11)ZR*9+67 R6RR	;6;;	PVPP V./#I;/0i[)*}-.s6{"  ,T66 BHgL
+gYhGHh&NW$M ,D&&AJ-j\:; I ,99Xr*..{;07E$$U+,
 !4T9!E((89:"n4" )+ ..y9G4#1$#H $4#567!11 &' P		'2.yy,00"=AA(CPyy,00"=AA(CP		(B/33JDSbI)7)>&
J$)IIh$;$?$?$LR]<Fzl!J<8E	UG2dV3tfBykVHANOPOOPd 
/	
	(O	";-
01	~.
/0	}o
./	 !3 4
56	OM?
+,	
 8 89
:; %%o6Kv!&)--lB?,[__Y-K-O-OP^`k-l,mmpq|  rA  rA  BK  MO  rP  rT  rT  Ug  ij  rk  ql  m  	n

 rS   __main__)Ar   ossysre   rb   r<  rk  r  r   r   r   pathlibr   typingr   r   r	   r
   r   rH   pathinsertdirnameabspath__file__
team_namesr   parentENV_FILEexistsopenflinestrip
startswithr  keyvalenviron
setdefaultr^   r   ro  r  ra   exitrJ  rq  rC   r   r   r   r   r   r   r  r  rh   r-  r1  r8  rB  rQ  r  r   r   rS   rQ   <module>r     s  " 
 
      2 2  3 3  277??277??8#<= > ( >  ''&0??	h F1 	FDzz|DOOC$8SD[::<--c15S

%%c399S>+?+?+DE	FF zz~~79\]jjnn56

4b9	
@ACHHQK	%1= 
%!< 
%"=	
 
%1= GRqA GQa@ 61B? 
%"= 
%"= 
%!<  XqB!" XqB#$ qJ%& XqB'( 
)1AN)* 
%"=+2 ww wtx} x      F"$ "5#)E#F ""J Jd JZ@htDz h3 h5c? hVT$Z C D"$t* "c "c "JT$Z   <$ S $ # $ %S/ $ N`F zF {F Fs   K##K#5K#:AK##K-