o
     ã²i/A  ã                   @   sÆ   d Z ddlZddlZddlZddlZddlmZ ddlmZ ddlm	Z	 e 
d¡ZdZdZd	Zd
ddœZi Zdd„ Zdd„ Zdd„ Zdd„ Zd!dd„Zdd„ Zd!dd„Zd!dd„Zdd„ Zdd „ ZdS )"u  
Pre-Game Validator Module for Luke.

Validates betting picks against pregame intelligence before they reach
Bill's dashboard or WhatsApp.

Validation Pipeline:
  1. Tempo filter produces a pick with 3 legs and a rating (existing flow)
  2. Validator enhances with Claude API (primary) + web scraping (supplementary)
  3. Each pick gets a confidence tag:
     â˜… VALIDATED  â€” pregame intel confirms the tempo read
     âš  CAUTION   â€” mixed signals, proceed with care
     âŒ DROPPED   â€” pregame intel contradicts the tempo read
  4. VALIDATED and CAUTION show prominently; DROPPED are collapsed

Architecture:
  BASELINE:  Tempo classification data already computed (always available)
  PRIMARY:   Claude API (Haiku) â€” fast, cheap, knows team histories
  SECONDARY: Web scraping (Forebet, Sports Mole) â€” live injuries & form
  FALLBACK:  Heuristic rules using baseline tempo data if Claude is down
é    N)Údatetime)Úquote)ÚConfigzpregame-validatori   é   é   zuMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36ztext/html,application/xhtml+xml)z
User-AgentÚAcceptc                 C   s   |   ¡  ¡ › d|  ¡  ¡ › S )NÚ_)ÚlowerÚstrip)ÚhomeÚaway© r   úL/sessions/festive-kind-sagan/mnt/clawd/whatsapp-agent/./pregame_validator.pyÚ
_cache_key3   s   r   c                 C   s<   t | |ƒ}t |¡}|rt ¡ |d   ¡ tk r|d S d S )NÚ	timestampÚdata)r   Ú_validation_cacheÚgetr   ÚnowÚtotal_secondsÚCACHE_TTL_SECONDS)r   r   ÚkeyÚentryr   r   r   Ú_get_cached7   s
   

r   c                 C   s    t | |ƒ}|t ¡ dœt|< d S )N)r   r   )r   r   r   r   )r   r   r   r   r   r   r   Ú_set_cached?   s   
r   c                 C   sR   dD ]}|   |¡r| t|ƒd … } qdD ]}|  |¡r$| d t|ƒ … } q|  ¡ S )N)zFC zAC zAS zSS zSSC zAFC )z FCz SCz CF)Ú
startswithÚlenÚendswithr
   )ÚnameÚprefixÚsuffixr   r   r   Ú_team_shortF   s   
€
€r!   c                 C   s¼  zddl m}m}m} |ƒ }W n
 ty   Y dS w |dkr„| | |¡}| | i ¡}	| |i ¡}
|	 dd¡}|
 dd¡}|dkrPdd	d
|› d|› dddddœS |dkr{|	 d¡dkr]| n|}| |i ¡ dd¡}dd|› d|› d|› ddddœS dddddddœS d|i}| |¡}| dd¡}| d| ¡ ¡}| d d¡}|d!krÂ|› d"}|r±|› d#}dd	|d$|r¹d%nd&› d'dddœS |dkrÒdd|› d(d)dddœS dd|› d*d+dddœS ),z‚
    Generate a baseline validation using the tempo classification
    that sports_betting.py already computed for this game.
    r   )ÚNHL_TEAM_PROFILESÚSOCCER_LEAGUE_TIERSÚSportsBettingAnalystNÚnhlÚlabelÚunknownÚ
controlledÚ	VALIDATEDé   zBoth teams are low-event (z + ú)zControlled tempo matchupÚlowT©ÚverdictÚ
confidenceÚreasonÚ
key_factorÚinjury_impactÚform_supports_underÚmixedÚtempoÚ	defensiveÚCAUTIONr   ú (z0) anchors the pace, but risk from the other sidez controls tempoÚDROPPEDé   u-   Both teams are high-event â€” chaotic matchupzHigh-offense tempo profileFÚsportÚtierÚis_cupé   u    â€” prime under territoryu!    knockout â€” teams protect leadszTier 1 ÚcupÚleaguez environmentu.    â€” usable with filtering, check team qualityz-Tier 2 league needs careful matchup selectionu&    â€” high-scoring league, avoid undersz$Tier 3 league, goals come in bunches)	Úsports_bettingr"   r#   r$   ÚImportErrorÚclassify_nhl_matchupr   Úclassify_soccer_matchupÚupper)r   r   r;   Ú	pick_datar"   r#   r$   Úanalystr5   Úhome_pÚaway_pÚ
home_labelÚ
away_labelÚanchorÚanchor_labelÚgameÚleague_classr<   r&   r=   r0   r   r   r   Ú_baseline_from_tempoT   sˆ   
ÿúú
ú


úú
úrP   c           	      C   sô   i }zmt | ƒ› dt |ƒ› }dt|ƒ› }tj|ttd}|jdkrj|j}t 	d|tj
¡}|rN| d¡› d| d¡› |d	< t| d¡ƒt| d¡ƒ |d
< t 	d|tj¡}|rat| d¡ƒ|d< |rmd|d< W |S W |S W |S  tyy   Y |S w )zEQuick scrape attempt. Returns dict (may be empty). Never blocks long.ú z"https://www.forebet.com/en/search/)ÚheadersÚtimeoutéÈ   u3   class="[^"]*rcnt[^"]*"[^>]*>.*?(\d)\s*[-â€“]\s*(\d)r>   ú-r:   Úpredicted_scoreÚpredicted_totalzUnder\s*2\.5[^%]*?([\d.]+)\s*%Úunder25_probÚForebetÚ_source)r!   r   Úrequestsr   ÚHEADERSÚSCRAPE_TIMEOUTÚstatus_codeÚtextÚreÚsearchÚDOTALLÚgroupÚintÚIÚfloatÚ	Exception)	r   r   r   ÚqueryÚurlÚrespÚhtmlÚmÚm2r   r   r   Ú_try_scrape±   s2   
 
óüþþrn   c                 C   s^  t j}|sdS |dkrdnd}|dkrdnd}ddd	d
dddddddœ
}| || ¡ ¡}	d}
|rXg }d|v r@| d|d › ¡ d|v rO| d|d › d¡ |rXdd |¡ }
t ¡  d¡}d|› d|› d| › d|	› d|› d| d d!¡› d| d"d¡› d#|
› d$}zt	j
d%|d&d'd(œd)d*d+|d,œgd-œtd.}|jd*kr| ¡ d/ d0 d1  ¡ }zt |¡}W n, tjyÝ   t d2|tj¡}|rËt | ¡ ¡}nt d3|dd4… › ¡ Y W dS Y nw d |v rd5|v rt d6|› d7| › d8|d  › d|d5 › d9	¡ |W S W dS W dS t d:|j› ¡ W dS  ty. } zt d;|› ¡ W Y d}~dS d}~ww )<z›
    Use Claude Haiku to enhance the baseline validation with deeper analysis.
    Returns enhanced validation dict, or None if Claude is unavailable.
    Nr%   ÚNHLÚsoccerzUnder 6.5 goalszUnder 2.5 goalszSerie AzLigue 1zLiga PortugalÚEPLzLa LigaÚMLSzEuropa LeaguezChampions LeaguezConference League)
ÚserieaÚligue1Úliga_portugalÚeplÚlaligaÚmlsÚeuropaÚuclÚ
conferencer%   Ú rV   zForebet predicted score: rX   zForebet Under 2.5 probability: ú%z

LIVE DATA:
Ú
z	%B %d, %Yz1You are a sharp sports betting analyst. Today is z.

MATCHUP: ú @ r8   z)
BET: uv   
STRATEGY: "Predictable Tempo" â€” we bet on controlled, low-scoring game environments.

Our tempo filter rated this: r.   ÚUNKNOWNr0   uº   )

Using your knowledge of these teams' 2025-26 season â€” their form, style, defensive records, key players, injuries, and head-to-head patterns â€” validate or override the tempo read.a  

Respond in EXACT JSON only (no markdown, no commentary):
{"verdict":"VALIDATED" or "CAUTION" or "DROPPED","confidence":1-10,"reason":"Max 80 chars","key_factor":"Max 60 chars","injury_impact":"low" or "medium" or "high","form_supports_under":true or false}z%https://api.anthropic.com/v1/messagesz
2023-06-01zapplication/json)z	x-api-keyzanthropic-versionzcontent-typezclaude-haiku-4-5-20251001rT   Úuser)ÚroleÚcontent)ÚmodelÚ
max_tokensÚmessages)rR   ÚjsonrS   rƒ   r   r_   z	\{[^}]+\}zClaude non-JSON: éd   r/   zClaude: ú@u    â†’ ú/10)zClaude API zClaude error: )r   ÚCLAUDE_API_KEYr   rE   ÚappendÚjoinr   r   Ústrftimer[   ÚpostÚCLAUDE_TIMEOUTr^   r‡   r
   ÚloadsÚJSONDecodeErrorr`   ra   rb   rc   ÚloggerÚwarningÚinforg   )r   r   r;   ÚbaselineÚscrape_dataÚapi_keyÚsport_labelÚ
under_lineÚ
league_mapr@   ÚsuppÚpartsÚtodayÚpromptrj   rƒ   Úresultrl   Úer   r   r   Ú_validate_with_claudeÊ   s–   üþþþý
ú
úøý
ýôýý,þ	÷	ûý€ýr¢   c              	   C   s|  t | |ƒ}|r	|S t d|› d| › d|› d¡ g }t| |||ƒ}|s,ddddd	d
dœ}| d¡ t| |ƒ}| d¡rB| |d ¡ t| ||||pJd
ƒ}|rV|}	| d¡ n\|}	|r²| d¡}
| d¡}|
d
urŸ|dkr„|
dkr„td|	d d ƒ|	d< d|
› d|	d< n|dkrŸ|
dkrŸtd|	d d ƒ|	d< d|
› d|	d< |d
ur²|dkr²td|	d d ƒ|	d< ||	d< t	| ||	ƒ |	S )a,  
    Full validation pipeline. Always returns a meaningful result.

    1. Check cache
    2. Generate baseline from tempo classification (always works)
    3. Try web scraping (best-effort, 5s timeout)
    4. Try Claude API enhancement (primary, 15s timeout)
    5. Return best available result
    zValidating: r   r8   r+   r7   r   z-Tempo profile supports controlled environmentzPassed tempo filterr'   Nr-   úTempo ProfilerZ   z	Claude AIrW   rX   r%   é	   r/   r>   z
Predicted u    total goals â€” strong underr0   r:   é7   Úsources)
r   r“   r•   rP   rŒ   rn   r   r¢   Úminr   )r   r   r;   rF   Úcachedr¦   r–   r—   Úclaude_resultÚanalysisÚptÚprobr   r   r   Úvalidate_pick"  sL   

ú




r­   c                    sä  | D ]µ}|  dd¡}|dkrddddg dœ|d	< q|  d
d¡}|  dd¡}|  dd¡ ¡ }ddddddddddddœ}|  ||¡}zLt||||ƒ}||d	< |d dkrk|dv rkd|d< d|  dd¡dd… › |d < n!|d d!krŒ|d"krŒ|  d#d¡d$krŒd%|d< d&|  d d¡› |d < W q ty· }	 zt d'|› d(|› d)|	› ¡ d*d+d,d-gd.œ|d	< W Y d}	~	qd}	~	ww dd/d0d1d2œ‰ | j‡ fd3d4„d5 td6d7„ | D ƒƒ}
td8d7„ | D ƒƒ}t d9|
› d:|› d;t	| ƒ|
 | › d<¡ | S )=zM
    Validate a batch of picks. Adds 'validation' key to each pick dict.
    ÚratingÚneutralÚavoidr9   r   zTempo filter flagged as avoidzChaotic tempo)r.   r/   r0   r1   r¦   Ú
validationr   r|   r   r;   r%   rv   rs   rt   rw   ru   rx   Ú
bundesligary   r{   rz   )r%   rv   zserie azligue 1zla ligazliga portugalrx   r²   zeuropa leaguezconference leaguezchampions leaguer.   )ÚprimeÚplayableu   âŒ DROPPED â€” r0   Né2   Útagr)   r´   r/   r*   r³   u   â˜… VALIDATED â€” zValidation error z vs z: r7   r   z Tempo profile supports this pickr£   )r.   r/   r0   r¦   r>   r:   é   )r³   r´   r¯   r°   c                    s   ˆ   |   dd¡d¡S )Nr®   r¯   r:   ©r   )Úp©Úrating_orderr   r   Ú<lambda>•  s    z&validate_picks_batch.<locals>.<lambda>)r   c                 s   ó*    | ]}|  d i ¡  d¡dkrdV  qdS )r±   r.   r)   r>   Nr¸   ©Ú.0r¹   r   r   r   Ú	<genexpr>—  ó   €( z'validate_picks_batch.<locals>.<genexpr>c                 s   r½   )r±   r.   r9   r>   Nr¸   r¾   r   r   r   rÀ   ˜  rÁ   zValidated: u    â˜…, u    âŒ, u    âš )
r   r	   r­   rg   r“   r”   ÚsortÚsumr•   r   )ÚpicksÚpickr®   r   r   r;   Úsport_key_mapÚ	sport_keyr±   r¡   Úv_countÚd_countr   rº   r   Úvalidate_picks_batcha  s^   
ûú €ü€þ	*rÊ   c           	      C   s¦   |   di ¡}|  dd¡}|  dd¡}|  dd¡}|  dg ¡}d	d
ddœ}|  |d¡}d|› d|› }|r;|d|› 7 }|rG|dd |¡› 7 }|rQ|d|› d7 }|S )Nr±   r.   r€   r0   r|   r/   r   r¦   u   â˜…u   âš ï¸u   âŒ)r)   r7   r9   ú?z  z
 PREGAME: u    â€” z
    Sources: z, r8   rŠ   )r   r   )	rÅ   Úvr.   r0   r/   r¦   ÚiconsÚiconÚliner   r   r   Úformat_validation_for_whatsapp   s   rÐ   )N)Ú__doc__r`   r‡   Úloggingr[   r   Úurllib.parser   Úconfigr   Ú	getLoggerr“   r   r]   r   r\   r   r   r   r   r!   rP   rn   r¢   r­   rÊ   rÐ   r   r   r   r   Ú<module>   s4    
ü	
]

X??