a
    õ6“jÂ'  ã                   @   sn  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Z	ddl
m
Z
mZ ddlmZ ejjddd� edƒZh d	£Zd
ZdZdeiZedƒZedƒ�Ze e¡ZW d  ƒ n1 sÀ0    Y  dd„ e ¡ D ƒZdd„ Zddddddddddddddd d!d"d#œZd$d%„ Zd&d'„ Zd(d)„ Z d*d+„ Z!d,d-„ Z"d.d/„ Z#e$ƒ Z%d0d1„ Z&d2d3„ Z'd4d5„ Z(e)d6k�rje(ƒ  dS )7uF  
Resolve match results in live_data CSVs using data already in the file.
Finds FT/AET/PEN rows, extracts the final score, and backfills
ftr / result_home / result_away for all rows of that game.

Runs nightly at 12:05 AM via Task Scheduler.
Safe to re-run â€” skips already-resolved games.

Usage: python resolve_live_data.py
é    N)ÚdatetimeÚdate)ÚPathúutf-8Úreplace)ÚencodingÚerrorszE:\soccer\live_data>   ZAETZFTZPENZ 81b487be73030f5dec980d2a1ef2c406z!https://v3.football.api-sports.iozx-apisports-keyz!E:\soccer\data\_result_cache.jsonzE:\soccer\data\league_map.jsonc                 C   s$   i | ]\}}|  d ¡r|d  |“qS )Zapi_football_id)Úget©Ú.0ÚkÚv© r   úmain/resolve_live_data.pyÚ
<dictcomp>   ó    r   c                 C   s   t  d| ¡ dd¡ ¡ S )NZNFDÚasciiÚignore)ÚunicodedataZ	normalizeÚencodeÚdecode)Úsr   r   r   Ú_strip_accents   s    r   ZwolvesZathleticzatletico madridzsaint louis cityzseattle sounderszvancouver whitecapszsan jose earthquakesz	fc dallaszcolorado rapidszparis saint-germainZnurnbergZlarisaZpanetolikosZkocaelisporzgenclerbirligi s.k.zgil vicente)ZwolverhamptonZbilbaoZatleticozsaint louisZseattleZ	vancouverzsan joseZdallasZcoloradoZpsgZ	nurembergZlarissaÚpanaitolikosr   ZkocaeliZgenclerbirligizvicente barcelosc                   C   s*   t  ¡ r&zt tt ƒ¡W S    Y n0 i S ©N)ÚCACHE_FÚexistsÚjsonÚloadÚopenr   r   r   r   Ú
load_cache5   s    r    c                    sX   t  ¡  ¡ ‰ ttdƒ�.}t ‡ fdd„|  ¡ D ƒ|¡ W d  ƒ n1 sJ0    Y  dS )a5  Persist the result cache, MINUS today.

    Today must stay cached in memory -- one run resolves ~100 same-day games and
    without it each would re-fetch, which is ~200 API calls per dashboard
    refresh on a plan that already ran out today.

    It must NOT reach disk, though: a snapshot written at 3pm contains only the
    games finished by 3pm, and api_results_for_date returns any non-empty cache
    entry without re-fetching, so the evening's games would be missing from it
    permanently. Dropping today keeps the in-run saving and loses the trap.
    Úwc                    s   i | ]\}}|ˆ kr||“qS r   r   r
   ©Útodayr   r   r   I   r   zsave_cache.<locals>.<dictcomp>N)r   r#   Ú	isoformatr   r   r   ÚdumpÚitems)ÚcacheÚfr   r"   r   Ú
save_cache;   s    r)   c              
   C   sp  | |v r||  r||  S i }�zt jt› d�td| idd�}| ¡  dg ¡D ]Î}|d d tvrbqL|d d	 d
 tvrxqL|d }|d d u rŽqLt|d ƒt|d ƒ }}||kr´dn||k rÀdnd}t|d d d ƒ 	¡  
¡ }	t|d d d ƒ 	¡  
¡ }
|	› d|
› �}|||dœ||< qL||| < t d¡ W n: t�yj } z td| › d|› �ƒ W Y d }~n
d }~0 0 |S )Nz	/fixturesr   é   )ZheadersÚparamsZtimeoutZresponseZleagueÚidZfixtureÚstatusZshortÚgoalsÚhomeÚawayÚHÚAÚDZteamsÚnameú|©ÚftrÚresult_homeÚresult_awayg333333Ó?z  API error for z: )Úrequestsr	   ÚAF_BASEÚHEADERSr   Ú
LEAGUE_IDSÚTERMINALÚintr   ÚlowerÚstripÚtimeÚsleepÚ	ExceptionÚprint)Úgd_strr'   ÚresultsÚrZfixr.   ÚhÚar7   ÚhnÚanÚkeyÚer   r   r   Úapi_results_for_dateK   s*    *rO   c                 C   s`   z| d   t¡ ¡ rW dS W n ty.   Y n0 zt| d  ¡ ƒdkW S  tyZ   Y dS 0 dS )a  Has this same-day game actually ended?

    Only matters because live_monitor's clock-based fallback writes status=FT
    with NO GOALS when it cannot get a score -- which is exactly the case that
    needs the API. So a terminal status counts as 'ended' even with no score
    attached, and 115+ minutes on the clock counts as well for a game whose
    status never advanced at all.

    The point of the original 'skip today' rule was not to ask about a game
    still in play. This keeps that, without waiting until tomorrow.
    r-   TÚelapsedés   FN)Úisinr>   ÚanyrD   ÚfloatÚmax)Úgrpr   r   r   Ú_finished_todayc   s    
rW   c                 C   s   t | ƒ ¡  ¡ }t ||¡S )zYApply known team name aliases before matching. Always works on accent-stripped lowercase.)r   r@   rA   ÚTEAM_ALIASESr	   )r4   Únr   r   r   Ú_resolve_aliasz   s    rZ   c                 C   s^   ddl m} tt| |ƒƒ}z,t | ¡|dd�  ¡ }| t||ƒ¡ W n tyX   Y n0 |S )zZFetch results for gd_str and gd_str+1 day (catches late games stored under next UTC date).r   ©Ú	timedeltaé   ©Zdays)	r   r\   ÚdictrO   r   Úfromisoformatr$   ÚupdaterD   )rF   r'   r\   rG   Znext_dayr   r   r   Úapi_results_for_date_combined   s    rb   c                    sT  t ||ƒ}t| ƒ ¡  ¡ }t|ƒ ¡  ¡ }|› d|› �}||vr¬|tvr¬t |¡ | |d ¡ z0ddlm} | t	 
|¡|dd�  ¡ d ¡ W n ty    Y n0 t ||ƒ}||v r¼|| S t| ƒt|ƒ }	}
|	› d|
› �}||v rì|| S h d£‰ ‡ fdd„‰‡fd	d
„}| ¡ D ]:\}}| dd¡\}}|| |ƒ�r|||ƒ�r|  S �qd S )Nr5   r   r[   r]   r^   >
   ÚrealZunitedZafZcityZscZtownZacZfcZsportingZroyalc                    s&   ‡ fdd„t | ƒ ¡  dd¡ ¡ D ƒS )Nc                    s$   g | ]}t |ƒd kr|ˆ vr|‘qS )é   )Úlen©r   r!   ©Úskipr   r   Ú
<listcomp>ª   s   ÿz-api_lookup.<locals>.words.<locals>.<listcomp>ú-ú )r   r@   r   Úsplit)rY   rg   r   r   Úwords©   s    zapi_lookup.<locals>.wordsc                    sR   t t ˆˆƒˆtˆƒƒ ¡ƒ}ˆˆ ƒ}t‡ fdd„|D ƒƒpPt‡fdd„|D ƒƒS )Nc                 3   s   | ]}|ˆ v V  qd S r   r   rf   )Ú
cache_namer   r   Ú	<genexpr>¯   r   z.api_lookup.<locals>.matches.<locals>.<genexpr>c                 3   s*   | ]"}|t ˆ ƒ ¡ v p |tˆ ƒv V  qd S r   )r   r@   rZ   rf   )Úour_namer   r   ro   °   r   )Úlistr_   ÚfromkeysrZ   rS   )rp   rn   ZowZcw)rm   )rn   rp   r   Úmatches¬   s
    ÿzapi_lookup.<locals>.matches)rb   r   r@   rA   Ú_refetched_datesÚaddÚpopr   r\   r   r`   r$   rD   rZ   r&   rl   )r/   r0   rF   r'   rG   rK   rL   rM   r\   ZahZaaZ	alias_keyrs   r   r   ZkhZkar   )rh   rm   r   Ú
api_lookupŒ   s6    

$
rw   c                 C   sZ  t j| dd�}dD ]}||jvrd ||< qt j|d dd�|d< t j|d dd�|d< z| j}t |¡}W n ty„   d }d }Y n0 |d uo˜|t ¡ k }|t ¡ k}d}| 	d	d
g¡D �]„\\}	}
}|j
|jdf  ¡  ¡ ràq¸||d  t¡|d  ¡ @  }|j�s¤|jd }t|d ƒ}t|d ƒ}||k�r6dn||k �rDdnd}||j
|jdf< ||j
|jdf< ||j
|jdf< d}td|	› d|
› d|› d|› d|› �
ƒ q¸|�sº|r¸t|ƒ�sºq¸t|	|
||ƒ}|r¸|d |j
|jdf< |d |j
|jdf< |d |j
|jdf< d}td|	› d|
› d|d › d|d › d|d › �
ƒ q¸|�rV|j| ddd� |S )Nr   )r   r6   Z
home_goalsZcoerce)r   Z
away_goalsFr/   r0   r7   r-   éÿÿÿÿr1   r2   r3   r8   r9   Tz  [csv] z vs z -> rk   rj   z  [api] )Úindexr   )ÚpdZread_csvÚcolumnsZ
to_numericZstemr   r`   rD   r#   ÚgroupbyZlocry   ZnotnarS   rR   r>   ÚemptyZilocr?   rE   rW   rw   Zto_csv)Úpathr'   ZdfÚcolrF   ÚgdZapi_eligibleZis_todayZchangedr/   r0   rV   ZterminalZlastrI   rJ   r7   Úresultr   r   r   Úresolve_file¸   sT    



 &4r‚   c                  C   s’   t dt ¡  d¡› d�ƒ tt ttd ƒ¡ƒ} tƒ }d}| D ]6}t	j
 |¡}t d|› d�ƒ tt|ƒ|ƒr>|d7 }q>t|ƒ t d	|› d
�ƒ d S )Nu   
=== Resolve Live Data â€” z%Y-%m-%d %H:%Mz ===z*.csvr   z
[ú]r]   u
   
Done â€” z files updated.)rE   r   ZnowÚstrftimeÚsortedÚglobÚstrÚDATA_DIRr    Úosr~   Úbasenamer‚   r   r)   )Úfilesr'   Úupdatedr(   Úfnamer   r   r   Úmainö   s    
rŽ   Ú__main__)*Ú__doc__r†   r‰   Úsysr   rB   r:   r   Zpandasrz   r   r   Úpathlibr   ÚstdoutÚreconfigurerˆ   r>   ZAPI_KEYr;   r<   r   r   r(   r   Z_lmr&   r=   r   rX   r    r)   rO   rW   rZ   rb   Úsetrt   rw   r‚   rŽ   Ú__name__r   r   r   r   Ú<module>   sZ   
8
(ï,>
