a
    cÑAj  ã                   @   sú   d 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 ddl	m
Z
 dZdeiZdZd	Zed
ƒZedddgdddd�edddgdddd�dœZdd„ ZedƒZdd„ Zd-dd„Zdd „ Zd!d"„ Zh d#£Zd$d%d&d'd(d)œZd*d+„ Zed,kröeƒ  dS ).uÐ  
Odds-coverage watcher for candidate leagues (Liga MX, Peru Liga 1).

Both are real on Kalshi + Poly but we could NOT confirm API-Football Pinnacle
coverage on 2026-06-28 because their next fixtures were outside the ~7-day odds
window (odds only populate near kickoff). The "0 books on FINISHED fixtures"
test is INVALID (proven: finished EPL fixtures also return 0 books â€” AF purges
odds weeks after a game). So the only reliable probe is an UPCOMING fixture
INSIDE the window.

This script checks each candidate league's upcoming fixtures, classifies odds
coverage, and emails a verdict when it becomes DEFINITIVE (ready-to-wire or
genuinely-uncovered) â€” or a one-time "still pending" reminder. Dedupes on a
small state file so a daily schedule won't spam. Read-only against APIs; the
only thing it writes is its own state file and an email. It does NOT wire
anything â€” wiring stays a manual decision.

Run manually any time:  python research/check_new_league_odds.py
é    N)ÚdatetimeÚtimezone)ÚPath)ÚMIMETextZ 81b487be73030f5dec980d2a1ef2c406zx-apisports-keyz!https://v3.football.api-sports.ioé   z3E:\soccer\research\check_new_league_odds_state.jsoni  iê  ié  zLiga MXZKXLIGAMXGAMEzliga-mx)ÚafÚseasonsÚnameÚkalshiZpolyi  zPeru Liga 1ZKXPERLIGA1GAMEzperu-liga-1)ZMX1ZPE1c                 C   sl   i }zPt | ƒD ]B}| ¡ }|r| d¡sd|v r| dd¡\}}| ¡ || ¡ < qW n tyf   Y n0 |S )Nú#ú=é   )ÚopenÚstripÚ
startswithÚsplitÚ	Exception)ÚpathÚenvÚlineÚkÚv© r   ú+E:\soccer\research\check_new_league_odds.pyÚ	_load_env'   s    r   zE:\soccer\.envc                 C   s˜   t |dƒ}| |d< t dd¡|d< t dd¡|d< t dd	¡�F}| t dd¡t d
d¡¡ | |d |d | ¡ ¡ W d   ƒ n1 sŠ0    Y  d S )NZplainZSubjectZEMAIL_SENDERÚ ZFromZEMAIL_RECIPIENTZTozsmtp.gmail.comiÑ  ZEMAIL_APP_PASSWORD)r   Ú_envÚgetÚsmtplibZSMTP_SSLZloginZsendmailZ	as_string)ZsubjectÚbodyÚmsgZsrvr   r   r   Ú
send_email5   s    
r!   é   c              	   C   s€   i }|D ]b}zJt jt› d�t| ||dœdd�}| ¡  dg ¡D ]}|||d d < q>W q tyh   Y q0 qt| ¡ dd	„ d
�S )zGDe-duped upcoming fixtures across the given seasons, sorted by kickoff.z	/fixtures)ZleagueZseasonÚnexté   ©ZheadersÚparamsZtimeoutÚresponseÚfixtureÚidc                 S   s   | d d S )Nr(   Údater   )Úfr   r   r   Ú<lambda>I   ó    z_upcoming.<locals>.<lambda>)Úkey)Úrequestsr   ÚAF_BASEÚHEADERSÚjsonr   ÚsortedÚvalues)r   r   ÚnÚseenÚsÚrr+   r   r   r   Ú	_upcoming>   s    ÿr9   c                 C   sn   zRt jt› d�td| idd�}| ¡  dg ¡}|s8g W S dd„ |d  d	g ¡D ƒW S  tyh   g  Y S 0 d S )
Nz/oddsr(   r$   r%   r'   c                 S   s   g | ]}|d  ‘qS )r	   r   ©Ú.0Úbr   r   r   Ú
<listcomp>R   r-   z_books.<locals>.<listcomp>r   Z
bookmakers)r/   r   r0   r1   r2   r   )Zfidr8   Zrespr   r   r   Ú_booksK   s    ÿr>   c                 C   s¦  t  tj¡}t| d | d ƒ}|s,ddgfS g }g }|D ]F}t  |d d  dd¡¡}||  ¡ d	 }|tkr8| 	|||f¡ q8|d
 }|d d dd… }	|s¸dd|	› dt› d�gfS d }
}|D ]¼\}}}t
|d d ƒ}tdd„ |D ƒƒ}|
pö|}
|�pt|ƒ}| 	d|d d dd… › d|d›d|d d d dd… d›d|d d d dd… d›dt|ƒ› d |�rvd!nd"› �¡ qÄ|
�r�d#|fS |�ržd$|fS d%|fS )&zmReturn (verdict, detail_lines). verdict in:
       READY | NO_PINNACLE | NO_COVERAGE | PENDING | NO_FIXTURES.r   r   ÚNO_FIXTURESz'  no upcoming fixtures scheduled at allr(   r*   ÚZz+00:00g     õ@r   Né   ÚPENDINGz  next fixture z (>u6   d out, outside odds window â€” recheck closer to then)Fr)   c                 s   s   | ]}d |v V  qdS )ZPinnacleNr   r:   r   r   r   Ú	<genexpr>l   r-   zclassify.<locals>.<genexpr>z  ú (z.1fzd) ZteamsÚhomer	   Z16sz v Zawayz books=ú ZPINNACLEr   ÚREADYÚNO_PINNACLEÚNO_COVERAGE)r   Únowr   Zutcr9   ZfromisoformatÚreplaceZtotal_secondsÚWINDOW_DAYSÚappendr>   ÚanyÚboolÚlen)ÚcfgrJ   ZfxÚlinesZ	in_windowr+   ZdtZdaysZnxtZnxt_dtZany_pinZany_bookZbmsZpinr   r   r   ÚclassifyV   sF    
$ÿþýý
rS   >   rI   rH   rG   u=   ODDS CONFIRMED â€” ready to wire (Pinnacle present in-window)uF   Other books but NO Pinnacle â€” softer fair only; decide before wiringuK   No bookmaker odds in-window â€” genuinely uncovered (like USC); do NOT wireu4   Still outside the odds window â€” will keep checkingzNo fixtures scheduled yet)rG   rH   rI   rB   r?   c                  C   s¼  dd„ t  ¡ D ƒ} i }t ¡ rHzt t ¡ ¡}W n tyF   i }Y n0 g d¢}d}|  ¡ D ]¢\}\}}t | }| |¡}| 	d|d › d|› d|d	 › d
|d › d�	¡ | 	d|› dt
| › �¡ ||7 }| 	d¡ |tv rê||krêd}|d u röd}|||< q\t tj|dd�¡ d |¡}	t|	ƒ |�r°dd„ |  ¡ D ƒ}
|
�rVdd
 |
¡ d nd}ztd|› �|	ƒ tdƒ W n6 t�y¬ } ztd|› d�ƒ W Y d }~n
d }~0 0 ntdƒ d S )Nc                 S   s   i | ]\}}|t |ƒ“qS r   )rS   )r;   ÚcoderQ   r   r   r   Ú
<dictcomp>„   r-   zmain.<locals>.<dictcomp>)z6Odds-coverage watch for candidate Kalshi+Poly leagues.uJ   (Wiring is still manual â€” this only tells you WHEN it's safe to decide.)r   Fz== r	   rD   z, AF r   z, r
   z) ==z   VERDICT: u    â€” r   Té   )ÚindentÚ
c                 S   s(   g | ] \}\}}|d krt | d ‘qS )rG   r	   )Ú
CANDIDATES)r;   Úcr   Ú_r   r   r   r=       r-   zmain.<locals>.<listcomp>z READYzLeague odds watchz

[emailed]z
[email FAILED: ú]u)   
[no email â€” no new definitive verdict])rY   ÚitemsÚSTATEÚexistsr2   ÚloadsÚ	read_textr   r   rM   Ú_ACTIONÚ_DEFINITIVEZ
write_textÚdumpsÚjoinÚprintr!   )ZresultsÚstater   Zemail_worthyrT   ZverdictrR   rQ   ÚprevZreportZreadyÚtagÚer   r   r   Úmainƒ   s>    
0


(rk   Ú__main__)r"   )Ú__doc__Úosr2   r   r/   r   r   Úpathlibr   Zemail.mime.textr   ZAPI_KEYr1   r0   rL   r^   ÚdictrY   r   r   r!   r9   r>   rS   rc   rb   rk   Ú__name__r   r   r   r   Ú<module>   s@    ÿÿý	
$û'