
    (i                        S r SSKrSSKrSSKrSSKrSSKJrJrJr  SSKJ	r	  \R                  " S5      r\	R                  =(       d    \R                  " SS5      rSr0 S	S
_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS _S!S _S"S#_S$S%_S&S'_S(S(S)S)S*S*S+S,S-.ErS.S/S0S1S2S3.S.S4S0S1S5S3.S.S6S7S1S8S3.S9S:S;S<S=S3.S9S>S?S<S@S3.S9SASBS<SCS3.SDSESFS<SGS3.SDSHSIS<SJS3.SK.r0 SLSMSNS1SO._SPSMSQS1SO._SRSMSSS1SO._STSMSUS1SO._SVSMSWS1SO._SXSMSYS1SO._SZSMS[S1SO._S\SMS]S1SO._S^SMS_S1SO._S`SMSaS1SO._SbSMScS1SO._SdSMSeS1SO._SfSMSgS1SO._ShSMSiS1SO._SjSMSkS1SO._SlSmSnS<SO._SoSmSpS<SO._SmSqS<SO.SmSrS<SO.SmSsS<SO.SmStS<SO.SmSuS<SO.SmSvS<SO.SmSwS<SO.SmSxS<SO.SmSyS<SO.SmSzS<SO.SmSuS<SO.SmS{S<SO.SmS|S<SO.SmS}S<SO.SmS~S<SO.S.ErS0SBSS.SSS.S.rSSSS.r0 SS_SS_SS_SS_SS_SS_SSl_SSl_SSl_SS^_SS^_SS_SS_SS_SSo_SSo_SS_0 SS_SSV_SSV_SSh_SSh_SS_SS_SS_SS_SS_SS_SSL_SSL_SS`_SSX_SSP_SSP_E0 SS_SS_SST_SST_SS_SSR_SSR_SS_SS_SS_SS_SS_SSf_SSf_SS_SS_SSj_E0 SS_SS\_SSb_SSb_SSZ_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_E0 SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_GS GS_GSGS_GSGS_E0 GSGS_GSGS_GS	GS
_GSGS_GSGS_GSGS_GSGS_GSGS_GSGS_GSGS_GSGS_GSGS_GSGS_GSGS_GSGS_GSGS_GS GS!_E0 GS"GS!_GS#GS$_GS%GS$_GS&GS'_GS(GS)_GS*GS)_GS+GS,_GS-GS,_GS.GS/_GS0GS1_GS2GS3_GS4GS3_GS5GS6_GS7GS8_GS9GS8_GS:GS;_GS<GS=_EGS>GS?GS@.Er " GSA GSB5      rSqGSC rg(D  u  
Sports Betting Module for Luke.

Bill's Distilled Betting Strategy — "Predictable Tempo" Philosophy
==================================================================
We bet on predictable tempo and structure, NOT outcomes.
Find the most controlled game environments and bet the scoring
range that matches the most common scorelines.

Core Process:
  1. Eliminate chaotic games (high-variance leagues, high-offense matchups)
  2. Find controlled games (defensive teams, low-creation matchups)
  3. Predict the scoring range (goal bands, not exact scores)
  4. Build matching bets (totals, spreads, correlated parlays)

Bill's Profile:
  - Platform: Bet365
  - Sports: NHL, NFL, EPL, Serie A, Ligue 1, La Liga, Liga Portugal, MLS
  - Style: Low-risk parlays, correlated boosts, profit boost optimization
  - Sweet spot: +120 to +220 boost range

Uses The Odds API (free tier: 500 requests/month).
Get a free key at: https://the-odds-api.com
    N)datetimedate	timedelta)Configzsports-bettingODDS_API_KEY zhttps://api.the-odds-api.com/v4nhlicehockey_nhlnflamericanfootball_nflepl
soccer_eplncaafamericanfootball_ncaafnbabasketball_nbamlbbaseball_mlbmlssoccer_usa_mlscflamericanfootball_cflserieasoccer_italy_serie_aserie_aligue1soccer_france_ligue_oneligue_1laligasoccer_spain_la_ligala_liga
bundesligasoccer_germany_bundesligaliga_portugalsoccer_portugal_primeira_liga
eredivisiesoccer_netherlands_eredivisiesoccer_uefa_champs_leaguesoccer_uefa_europa_league$soccer_uefa_europa_conference_leaguesoccer_fa_cupsoccer_spain_copa_del_rey)uclchampions_leagueeuropaeuropa_league
conferenceconference_leaguefa_cupcopa_del_rey   zSerie Ag      @Tz4Most tactically disciplined. Best league for unders.)tierlabel	avg_goals
under_biasnotezLigue 1z6Low-creation outside PSG. Treat PSG games as outliers.zLiga Portugal333333@z<Very predictable. Strong for Under 2.5 in mid-table clashes.   zLa Liga@Fz2Top 3 inflate goals. Mid-table matchups are solid.EPLgffffff@zKMost variance. Only target 'boring' matchups (e.g., Everton/Palace/Wolves).MLSg      @z/Use Under 3.0 or 3.5 only. No Under 2.5 in MLS.   
Bundesligag	@z:AVOID unders. High-pressing league, goals come in bunches.
Eredivisiegffffff
@z9AVOID. Open, end-to-end play. Not suited to Bill's style.)r   r   r$   r   r   r   r"   r&   zCarolina Hurricaneslowzelite defense)tempor7   under_targetzMinnesota Wildz
grind teamzNashville Predatorszdefensive structurezDallas Starszlow-event hockeyzWinnipeg Jetszstructured playzNew York Islanderszdefensive identityzColumbus Blue Jacketszlow-scoringzLos Angeles Kingszstructured westzBoston Bruinszdefensive systemzNew Jersey Devilsztight structurezVegas Golden Knightszcontrolled pacezSt Louis Blueszgrinder identityzSeattle Krakenzlow-event expansionzVancouver Canuckszdefensive buildzAnaheim Duckszrebuild/low-eventzToronto Maple Leafshighzhigh-offensezEdmonton Oilerszhigh-firepowerzexplosive offensez
high-eventzoffensive upsidezyoung/chaoticzchaotic/rebuildingzinconsistent/leakyzskill-driven offenseztransition offensezoffensive veteranszaggressive forecheckzrebuild/leakyz
young/fastzrebuild/high-eventztransition team)Colorado AvalancheFlorida PanthersTampa Bay LightningOttawa SenatorsBuffalo SabresDetroit Red WingsPittsburgh PenguinsNew York RangersWashington CapitalsCalgary FlameszPhiladelphia FlyersChicago BlackhawksMontreal CanadiensSan Jose SharksUtah Hockey Clubg      @)primaryr   safeg      @g      @)rU   tight)soccer_under	nhl_underx      z7Sweet spot +120 to +220. Only on legs you'd bet anyway.)min_oddsmax_oddsr:   habsrR   	canadiensmontrealsensrJ   senatorsottawaleafszmaple leafstorontobruinsbostonrangersrN   penguinsrM   pensoilersedmontonflamesrP   calgaryjetswinnipegcanucks	vancouver	lightningrI   tampapanthersrH   floridacapitalsrO   caps
hurricanescarolinadevils	islanderswild	minnesota	avalancherG   avsstarsdallasblueszSt. Louis Blues	predatorspreds
blackhawksrQ   z	red wingsrL   wingssabresrK   buffalokrakenseattlecoyotesrT   utahduckssharksrS   kingszgolden knightsvegaszblue jacketschiefszKansas City ChiefsbillszBuffalo BillseagleszPhiladelphia EaglesphillycowboyszDallas Cowboys49erszSan Francisco 49ersninersravenszBaltimore RavensbengalszCincinnati BengalsdolphinszMiami DolphinsmiamilionszDetroit LionsdetroitpackerszGreen Bay PackersbearszChicago BearsvikingszMinnesota VikingssteelerszPittsburgh Steelers
pittsburghchargerszLos Angeles ChargersbroncoszDenver BroncosraiderszLas Vegas RaiderstexanszHouston TexansjaguarszJacksonville JaguarscoltszIndianapolis ColtstitanszTennessee Titans
commanderszWashington CommandersgiantszNew York GiantssaintszNew Orleans SaintsfalconszAtlanta Falcons
buccaneerszTampa Bay BuccaneersbucsseahawkszSeattle Seahawks	cardinalszArizona CardinalsramszLos Angeles RamsarsenalArsenalgunners	liverpool	Liverpoolredszman cityzManchester Citycityz
man unitedzManchester UnitedunitedchelseaChelsea	tottenhamzTottenham Hotspurspurs	newcastlezNewcastle Unitedmagpieszaston villazAston VillavillabrightonzBrighton and Hove Albionzwest hamzWest Ham Unitedhammerszcrystal palacezCrystal Palacepalace	brentford	BrentfordfulhamFulhamwolveszWolverhampton WandererswolverhamptonbournemouthzAFC Bournemouth
nottinghamzNottingham ForestforestevertonEverton	leicesterzLeicester CityzIpswich TownSouthampton)ipswichsouthamptonc                       \ rS rSrSrS r\S 5       rS rS r	S r
S r0 rS	rS
r\" 5       rSS jrS rS rSS jrSS jrS rS rS rSS jrSS jrS rSrg)SportsBettingAnalyst   uK   Luke's sports betting brain — built on Bill's Predictable Tempo strategy.c                     S U l         g N)
_availableselfs    5/Users/bsyrros/clawd/whatsapp-agent/sports_betting.py__init__SportsBettingAnalyst.__init__   s	        c                     U R                   c[  [        [        5      U l         U R                   (       a!  [        R	                  S5        U R                   $ [        R	                  S5        U R                   $ )z$Check if the Odds API is configured.zSports betting module: ACTIVEz:Sports betting module: INACTIVE (set ODDS_API_KEY in .env))r   boolr   loggerinfor   s    r   	availableSportsBettingAnalyst.available   sS     ??""<0DO;<  XYr   c                     [         R                  U0 5      n[         R                  U0 5      nUR                  SS5      nUR                  SS5      nUS:X  a  US:X  a  gUS:X  a  US:X  a  gUS:X  d  US:X  a  gg)zP
Classify an NHL matchup by tempo.
Returns: 'controlled', 'chaotic', or 'mixed'
rD   mediumrC   
controlledrF   chaoticmixedNHL_TEAM_PROFILESget)r   homeawayhome_profileaway_profile
home_tempo
away_tempos          r   classify_nhl_matchup)SportsBettingAnalyst.classify_nhl_matchup  s    
 ),,T26(,,T26!%%gx8
!%%gx8
:#66!jF&:5 J%$7r   c                 r  ^ UR                  SS5      m[        R                  TS5      nU(       d'  [        R                  5        H  u  p4UT;   d  M  Un  O   U(       d  SSSSSSS.nTU;   a  SUT   S	S
S
SS.$ U(       d  SSSSS.$ [        U5      n[	        U4S jS 5       5      (       a
  S
US'   SUS'   U$ )zq
Classify a soccer matchup by league tier and expected tempo.
Returns dict with tier, recommendation, and notes.
sportr   NzEuropa LeaguezConference LeaguezChampions League)r/   r0   r1   r2   r-   r.   r5   r;   TzOCUP KNOCKOUT: Teams protect leads, first legs are cagey. Prime under territory.)r6   r7   r8   r9   is_cupr:   r<   zUnknown Leaguecautionu(   Unknown league — apply Tier 2 caution.)r6   r7   recommendationr:   c              3   ,   >#    U  H	  oT;   v   M     g 7fr    ).0cup	sport_keys     r   	<genexpr>?SportsBettingAnalyst.classify_soccer_matchup.<locals>.<genexpr>A  s     ;?Ci?   )r   copar   zwCUP GAME: Unders hit more in knockout rounds (teams protect leads). Group stages are less predictable. Check the stage.r:   )r   SOCCER_LEAGUE_TIERSitemsdictany)r   gameleague_infokeyr   
cup_labelsresultr   s          @r   classify_soccer_matchup,SportsBettingAnalyst.classify_soccer_matchup  s    
 HHWb)	)--i>0668	)#"&K 9 )!01%8)$6J J&'	2!$"&"m  (8IFH H k" ;?;;;#F8F 6N
 r   c                 R    [         R                  U0 5      nUR                  SS5      $ )z$Get the tempo label for an NHL team.r7   	unlabeledr   )r   	team_nameprofiles      r   get_nhl_team_label'SportsBettingAnalyst.get_nhl_team_labelJ  s%    #''	26{{7K00r   c                 H    [         S   Us=:*  =(       a    [         S   :*  $ s  $ )zBCheck if a profit boost falls in Bill's sweet spot (+120 to +220).r\   r]   )BOOST_STRATEGY)r   
odds_values     r   is_boost_worthy$SportsBettingAnalyst.is_boost_worthyO  s%    j)ZUU>*;UUUUUr   i  r   Nc                    U R                   (       d  gUc  0 nXR                  ;   a  gUnU R                  R                  U5      nU(       aT  [        R
                  " 5       US   -
  R                  5       U R                  :  a  [        R                  SU 35        US   $ SSK
nUR                  5       U R                  -
  nUS:  a  UR                  SU-
  5        UR                  5       U l        [        US'    [         U 3n[        R                  SU 35        [         R                  " XrS	S
9nUR"                  S:X  a  UR$                  R                  SS5      n	UR'                  5       n
[        R                  S[)        U
5       SU	 S35        U
(       a%  U
[        R
                  " 5       S.U R                  U'   U
$ UR"                  S:X  a5  U R                  R+                  U5        [        R                  SU S35        gUR"                  S:X  a&  [        R-                  SUR.                  SS  35        gUR"                  S:X  a  [        R-                  S5        g[        R-                  SUR"                   SUR.                  SS  35        g! [0         a"  n[        R-                  SU 35         SnAgSnAff = f)z>Make a request to The Odds API with caching and rate limiting.N	timestampzOdds API cache hit: datar   r<   apiKeyzOdds API calling:    )paramstimeout   zx-requests-remaining?u   Odds API OK — z
 results, z requests remaining)r  r  i  z
Odds API: u+    not available on current plan — skippingi  u#   Odds API invalid request (422) — i  u3   Odds API rate limited — will use cache next cyclezOdds API error:     — zOdds API request failed: )r   _unavailable_sports
_api_cacher   r   utcnowtotal_seconds_api_cache_ttlr   debugtime_last_api_callsleepr   ODDS_BASE_URLr   requestsstatus_codeheadersjsonlenaddwarningtext	Exception)r   endpointr   	cache_keycachedr+  elapsedurlresp	remainingr  es               r   _api_getSportsBettingAnalyst._api_getZ  sa   ~~>F /// 	$$Y/x(6++>>MMORVReReeLL/z:;&>! 	))+ 3 33Q;JJq7{#"iik'x	"OH:.CKK,XJ78<<B?D3& LL,,-CSI	yy{.s4ykI;Nabc:>X__M^1_DOOI.!!S(((,,X6j
2]^_!!S(!DTYYtPS_DUVW!!S(!TV!1$2B2B1C5SWTWHYZ[ 	NN6qc:;	s2   :CJ  AJ 5J ;%J !2J 
K J;;K c                     UR                  5       R                  5       nU[        ;   a	  [        U   $ [        R                  5        H  u  p4X2;   d  X#;   d  M  Us  $    g)z(Resolve a team name from a casual query.N)lowerstripTEAM_ALIASESr  )r   queryqalias	full_names        r   resolve_team!SportsBettingAnalyst.resolve_team  sR    KKM!?" , 2 2 4EzQZ   !5 r   c                 z  ^^ UR                  5       m[        U4S jS 5       5      (       a  g[        U4S jS 5       5      (       a  g[        U4S jS 5       5      (       a  g	[        U4S
 jS 5       5      (       a  gU R                  T5      nU(       a  [        R	                  5        VV^s/ s H$  u  nm[        U4S jS 5       5      (       d  M"  TPM&     nnnX%;   a  g[        R	                  5        VV^s/ s H$  u  nm[        U4S jS 5       5      (       d  M"  TPM&     nnnX&;   a  gg	gs  snnf s  snnf )z$Detect which sport a query is about.c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   r   wrG  s     r   r  4SportsBettingAnalyst.detect_sport.<locals>.<genexpr>  s     87!Av7r  )r	   hockeyicer	   c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   rN  s     r   r  rP    s     @?!Av?r  )r   football	touchdownr   c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   rN  s     r   r  rP    s     ON!AvNr  )r   zpremier leaguesoccerrT  r   c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   rN  s     r   r  rP    s     54!Av4r  )r   
basketballr   c              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   r   tvs     r   r  rP    s      C!W1Q !Wr  )	CanadiensSenatorszMaple LeafsBruinsRangersPenguinsOilersFlamesJetsCanucks	LightningPanthersCapitals
HurricanesDevils	IslandersWild	AvalancheStarsBlues	Predators
Blackhawksz	Red WingsSabresKrakenzHockey ClubDucksSharksKingszGolden KnightszBlue Jacketsc              3   ,   >#    U  H	  oT;   v   M     g 7fr   r   r[  s     r   r  rP    s      C!f1Q !fr  )ChiefsBillsEaglesCowboysr   RavensBengalsDolphinsLionsPackersBearsVikingsSteelersChargersBroncosRaidersTexansJaguarsColtsTitans
CommandersGiantsSaintsFalcons
BuccaneersSeahawks	CardinalsRamsN)rC  r  rJ  rE  r  )r   rF  teamkr]  	nhl_teams	nfl_teamsrG  s       `  @r   detect_sport!SportsBettingAnalyst.detect_sport  s   KKM87888@?@@@ONOOO54555   #'3'9'9'; ';tq!s C!WC @';I   '3'9'9'; ';tq!s C!fC @';I   /s   /!D1D1;!D7 D7c                    [         R                  U5      nU(       d  [        R                  SU 35        / $ U R	                  SU S3SSSSS.S	9nU(       d  [        R                  S
U SU S35        / $ [        R                  " 5       nU[        US9-   n/ nSnU Hr  n	 [        R                  " U	S   R                  SS5      5      R                  SS9n
X:  a  US-  nMF  X::  a"  UR                  U R                  X5      5        Mm  US-  nMt     [        R                  U S[!        U5       SU S35        U$ ! [        [        4 a#  n[        R                  SU 35         SnAM  SnAff = f)z)Get upcoming games with odds for a sport.zUnknown sport key: /sports/z/odds/zus,us2,uk,euzh2h,spreads,totalsamericaniso)regionsmarkets
oddsFormat
dateFormatr   zNo data returned for z ()daysr   commence_timeZ+00:00Ntzinfor5   zSkipped game parse error: : z upcoming games within window, z# skipped (started or beyond cutoff))
SPORT_KEYSr   r   r5  r@  r   r   r'  r   fromisoformatreplaceappend_parse_gameKeyError
ValueErrorr*  r3  )r   r   
days_aheadr   r  nowcutoffgamesskippedr	  	game_timer?  s               r   get_upcoming_games'SportsBettingAnalyst.get_upcoming_games  sy   NN5)	NN089I}}x	{&9%+$	C
}  KK/wb1EFI ooyj11D$2243H3P3PQTV^3_`hhpthu	?qLG&LL!1!1$!>?qLG  	ugRE
|+J7)Svwx j) 9!=>s%    A D;"%D;	D;;E.E))E.c                 |   U R                  U5      nU(       d  SSU S34$ U(       d  U R                  U5      nU(       d|  S Hn  nU R                  USS9nU HU  nUR                  5       US   R                  5       ;   d'  UR                  5       US   R                  5       ;   d  MO  US4s  s  $    Mp     SS	U S
34$ U R                  USS9nU HS  nUR                  5       US   R                  5       ;   d'  UR                  5       US   R                  5       ;   d  MO  US4s  $    SSUR	                  5        SU S34$ )z*Find an upcoming game for a specific team.NzI don't recognize 'z' as a team. Try the full name?)r	   r   r      r  	home_team	away_teamzNo upcoming game found for .zNo upcoming z game found for z in the next 7 days.)rJ  r  r  rC  upper)r   
team_queryr   r  sr  gs          r   get_game_for_team&SportsBettingAnalyst.get_game_for_team  sJ   %%j1	.zl:YZZZ%%j1E*//a/@A (AkN,@,@,BBiooFW[\]h[i[o[o[qFq $w  +
 6ykCCC''!'<A AkN$8$8$::ioo>OSTU`SaSgSgSi>i$w  |EKKM?2B9+Mabbbr   c                 |   UR                  S5      UUR                  SS5      UR                  SS5      UR                  SS5      / S.n [        R                  " US   R                  SS5      5      nU[	        S	S
9-
  nUR                  S5      US'   UR                  S5      US'   / SQnU Hk  nUR                  S/ 5       HR  nUS   U:X  d  M  US   0 S.n	UR                  S/ 5       H  n
U
S   U	S   U
S   '   M     US   R                  U	5          Mi     Mm     U$ ! [        [        4 a    SUS'   SUS'    Nf = f)z/Parse raw API game data into a clean structure.idr  r   r  r  r  r   r  r  r  
bookmakersr  r     hours
%A, %B %-d	game_date%-I:%M %p ETr  )bet365
draftkingsfanduelbovadabetmgmr  r  title)namer  r  outcomes)	r   r   r  r  r   strftimer  r  r  )r   rawr   r	  cteasternpreferred_books	book_namebm	book_datamarkets              r   r   SportsBettingAnalyst._parse_game  s[    ''$-b1b1 WW_b9
	#''O(<(D(DS((STB91--G ' 0 0 >D ' 0 0 @D R(IgglB/e9	))+G DI"$&&B"7>DZ>P	),VE]; #8&--i8 0 )  H% 	# "D "D	#s   
AD D;:D;c                   ^ U R                   (       d  gU R                  U5      u  p#U(       a  U$ US   mUS    SUS    3/nUR                  US    SUS    35        TS	:X  a  U R                  US   US   5      nU R	                  US   5      nU R	                  US   5      nUR                  S
UR                  5        35        US:w  a  UR                  SUS    SU 35        US:w  a  UR                  SUS    SU 35        OT[        ;   d  [        U4S jS 5       5      (       a  U R                  U5      nUR                  SUR                  STR                  5       5       SUS    S35        UR                  S5      (       a  UR                  S5        US   S:X  a  UR                  SUS    35        UR                  S5         SSK
Jn	Jn
  U	" US   US   T5      nU
" XS   US   5      nU(       a"  UR                  U5        UR                  S5        UR                  S5        UR                  S5        U R!                  U5      nU H  nUR                  SU 35        M      SS KJnJn  U" US   US   T5      nS!U0nU" U5      nU(       a"  UR                  S5        UR                  U5        UR                  S5        UR                  S$5        S%R+                  U5      $ ! [         a"  n[        R                  SU 35         SnANSnAff = f! [(         a    [        R                  S"5         N[         a"  n[        R                  S#U 35         SnANSnAff = f)&u   
Generate a strategy-driven pre-game analysis using Bill's
Predictable Tempo philosophy.

No odds displayed — just game environment classification,
pre-game chatter, and recommended legs that fit the matchup.
n   Sports betting not configured. Add ODDS_API_KEY to your .env file. Get a free key at the-odds-api.com — Luker   r   @ r  r  u    • r  r	   zTempo: r    r  c              3   F   >#    U  H  nTR                  U5      v   M     g 7fr   )
startswith)r   r  r   s     r   r  9SportsBettingAnalyst.generate_analysis.<locals>.<genexpr>H  s!     0{Nz1A1A!1D1DNzs   !)r   serieliguer   liga_zLeague: r7   z (Tier r6   r  r   u3     CUP GAME — knockout round unders hit more oftenr@   z  CAUTION: r:   r   r   get_pregame_chatterformat_chatter_for_whatsappz%Chatter fetch failed (non-critical): NzSUGGESTED LEGS:)validate_pickformat_validation_for_whatsapp
validationu7   pregame_validator not available — skipping validationz*Pregame validation failed (non-critical): u   — Luke
)r   r  r  r   r  r  r  r  r  r   pregame_chatterr  r  r7  r   r*  _generate_suggestionspregame_validatorr  r  ImportErrorjoin)r   r  r	  errorlinesrD   
home_label
away_labelleague_classr  r  chatterchatter_textr?  suggestionsr  r  r  r  pick_with_validationvalidation_textr   s                        @r   generate_analysis&SportsBettingAnalyst.generate_analysis+  sb    ~~ D,,Z8LW%&c${*;)<=>[)*%[0A/BCD E>--d;.?kARSE00k1BCJ00k1BCJLL75;;=/23[(r${"3!4BzlCD[(r${"3!4BzlCD))S0{Nz0{-{-{77=LLL8L$4$4Wekkm$L#MWUabhUiTjjklm))RTF#q({<+?*@ABR	FX)${*;T+=NPUVG6w[@QSWXcSdeL\*R 
 	&'R006ALL2aS" 	KW&tK'8${:KUSJ$0*#= <=QROR _- 	RZ yy9  	FLL@DEE	F(  	TLLRS 	KLLEaSIJJ	Ks8   AK0 0AL 0
L:LLM+ 	M+	M&&M+c                    / nUS   nSnSnUS   (       a  US   S   nUS   R                  S/ 5      nUS   R                  S/ 5      nU(       a  [        US S	9n	U	S
   nU(       a  [        S U 5       S5      OSn
U
(       a  U
R                  SS5      OSnUS:X  Gax  U R                  US   US   5      nUS:X  a  UR	                  S5        UR	                  S5        UR	                  S5        UR	                  S5        UR	                  S5        UR	                  S5        U(       an  UR	                  SU S35        UR	                  S5        UR	                  S5        UR	                  SU S35        UR	                  S5        UR	                  S5        GOoUS:X  ah  UR	                  S5        UR	                  S5        UR	                  S5        UR	                  S 5        UR	                  S!5        UR	                  S"5        GO[
        R                  US   0 5      n[
        R                  US   0 5      nUR                  S#5      S$:X  a  US   OUS   nUR	                  S%5        UR	                  U S&35        UR	                  S5        UR	                  S5        UR	                  S'5        U(       a]  UR	                  SU S(35        UR	                  S5        UR	                  S5        UR	                  SU S35        UR	                  S)5        GOUS*;   d   S+[        UR                  S,S5      5      ;   Gam  U R                  U5      nUR                  S-S.5      nUS/:X  a  UR	                  US0    S135        UR	                  UR                  S2S5      5        UR	                  S5        UR	                  S5        UR	                  S35        UR	                  S45        U(       a]  UR	                  SU S535        UR	                  S5        UR	                  S5        UR	                  SU S635        UR	                  S75        GOUS.:X  Gaa  UR	                  US0    S835        UR	                  UR                  S2S5      5        UR	                  S5        US9:X  a?  UR	                  S5        UR	                  S:5        U(       a  UR	                  SU S535        OUS;:X  aP  UR	                  S<5        UR	                  S35        U(       a  UR	                  SU S535        UR	                  S=5        O>UR	                  S>5        UR	                  S35        U(       a  UR	                  SU S535        U(       a7  UR	                  S5        UR	                  S5        UR	                  SU S635        OUS?:X  a  UR	                  US0    S@35        UR	                  UR                  S2S5      5        UR	                  S5        UR	                  SA5        U(       a&  UR	                  SBU SC35        UR	                  SD5        UR                  SE5      (       aU  UR	                  S5        UR	                  SF5        UR	                  SG5        UR	                  SH5        UR	                  SI5        GO_USJ:X  Ga  UR	                  S5        USK:  a8  UR	                  SL5        UR	                  S5        UR	                  SMU SN35        OuUSO::  a8  UR	                  SP5        UR	                  S5        UR	                  SMU SQ35        O7UR	                  SR5        UR	                  S5        UR	                  SSU ST35        U(       aN  UR	                  SU SU35        UR	                  S5        UR	                  S5        UR	                  SU SVU 35        O>U(       a  UR	                  SU S535        UR	                  SW5        UR	                  SX5        U(       aB  [        U5      S.:  a3  UR	                  S5        UR	                  SY5        UR	                  SZ5        U(       d  UR	                  S[5        U$ )\u  
Generate leg recommendations based on Bill's Predictable Tempo strategy.

No odds or prices — just the legs that fit the game environment.
Uses the API data internally to detect the favorite and total line,
then recommends legs purely on matchup structure.
r   Nr   r  r  h2htotalsc                     U S   $ Npricer   xs    r   <lambda><SportsBettingAnalyst._generate_suggestions.<locals>.<lambda>  s    QwZr   r  r  c              3   :   #    U  H  oS    S:X  d  M  Uv   M     g7f)r  OverNr   )r   r\  s     r   r  =SportsBettingAnalyst._generate_suggestions.<locals>.<genexpr>  s     BFqi6.AFs   	pointr	   r  r  r   u    CONTROLLED GAME — prime targetz(Two low-event teams = predictable tempo.r   zLegs that fit:z  Under 6.5 goalsz.  5-6 goal band is most likely scoreline ranger  z ML (tight win expected)zPARLAY IDEA:z ML + Under 6.5z*  Favorite wins a tight, low-scoring game.z$  Good candidate for a profit boost.r   u$   CHAOTIC MATCHUP — skip or go lightz0Both teams can score. Hard to predict the range.zIf you must play:z#  Over 6.5 goals (goals are coming)z  Avoid unders in this matchup.rD   rC   u)   MIXED TEMPO — one team anchors the pacez controls the tempo here.z0  Under 6.5 goals (defensive team dictates pace)z MLz$  The defensive team keeps it tight.)r   r   r   r   r   r   r!   r$   r   r"   r&   rW  r  r6   r<   r5   r7   u    — TIER 1 (best for unders)r:   z  Under 2.5 goalsz#  Most common scoreline: 1-0 or 1-1z to winz ML + Under 2.5 goalsz0  Favorite wins 1-0 or 2-1, controls possession.u    — TIER 2 (filter needed)r   z4  Under 3.0 or Under 3.5 goals (no Under 2.5 in MLS)r   z*Only play if both teams are mid/low-table:z#  Skip if top-6 teams are involved.z(Legs that fit (mid-table matchups only):r@   u    — TIER 3 (AVOID)z)Strategy says skip unders in this league.zIf you must play: z	 ML only.u    No totals — too unpredictable.r   zCUP PATTERN:z5  Knockout rounds favor unders (teams protect leads).u0     First legs especially — both teams cautious.z7  Under 2.5 is playable even in higher-scoring leagues.r   0   u)   HIGH TOTAL — contrarian under territoryz  Under z# (shootout lines tend to overshoot))   u%   LOW TOTAL — defensive game expectedz (both defenses are legit)u/   STANDARD TOTAL — need to dig into the matchupz  Lean Under z if defenses travel wellz ML or spreadz ML + Under z2  No specific strategy profile for this sport yet.z$  Check Bet365 for what looks right.9Check Bet365 for profit boosts in the +120 to +220 range.z+Only use boosts on legs you'd already play.z7Not enough data to suggest legs. Check Bet365 directly.)	r   minnextr   r  r   strr  r3  )r   r	  r   r   favorite_name
total_linebookr  r  favoverrD   home_paway_panchorr  r6   s                    r   r  *SportsBettingAnalyst._generate_suggestionsw  s    W 
%a(Dy/%%eR0C)_((26F##78 #FMS4BFBDIY]D15'1-1J E>--d;.?kARSE$""#EF""#MN""2&""#34""#67""#ST &&M?:R'ST&&r*&&~6&&M?/'JK&&'ST&&'MN)#""#IJ""#UV""2&""#67""#HI""#DE +..tK/@"E*..tK/@"E.4jj.AU.Jk*PTU`Pa""#NO""fX-F#GH""2&""#34""#UV &&M?#'>?&&r*&&~6&&M?/'JK&&'MN  K KNVZ]^b^f^fgkmo^pZqNq77=L##FA.Dqy""l7&;%<<Y#Z[""<#3#3FB#?@""2&""#34""#67""#HI &&M?''BC&&r*&&~6&&M?:O'PQ&&'YZ""l7&;%<<W#XY""<#3#3FB#?@""2&E>&&'78&&']^$#**Rg+FGe^&&'ST&&':;$#**Rg+FG&&'LM&&'QR&&':;$#**Rg+FG &&r*&&~6&&M?:O'PQ""l7&;%<<O#PQ""<#3#3FB#?@""2&""#NO &&);M?)'TU&&'IJ ))""2&"">2""#Z[""#UV""#\] e^r"R""#NO""#34""Xj\9\#]^r!""#JK""#34""Xj\9S#TU""#TU""#34""]:,>V#WX""Rm#DE""2&"">2""Rl:,#OP ""Rg#>?STEF S-1r"Z[LMXYr   c           	         [         R                  U5      nU(       d  / $ U R                  SU S3SS0S9nU(       d  / $ [        R                  " 5       nU[        US9-   n/ nU H  n [        R                  " US   R                  SS	5      5      R                  S
S9n	X:  a  MA  X::  a  UR                  S5      UUR                  SS5      UR                  SS5      UR                  SS5      / S.n
U	[        SS9-
  nUR                  S5      U
S'   UR                  S5      U
S'   UR                  U
5        M  M     [        R                  U S[        U5       S35        U$ ! [        [        4 a     GM  f = f)z
Fallback: get upcoming events (games) without requiring odds.
The Odds API /events endpoint returns scheduled games even if
no bookmaker has posted odds yet.
r  z/events/r  r  r  r  r  r  r  Nr  r  r  r   r  r  r  r  r  r  r  r  z events fallback: z games found)r  r   r@  r   r'  r   r  r  r  r  r  r  r   r   r3  )r   r   r  r   r  r  r  r  eventr  r	  r  s               r   get_upcoming_events(SportsBettingAnalyst.get_upcoming_events"  s    NN5)	I}}x	{(;%E
}  Iooyj11E$2253I3Q3QRUW_3`aiiquiv	?&#iio!&%*YY{B%?%*YY{B%?).?B)G&(D ()!*<<G(/(8(8(FD%(/(8(8(HD%LL& ' , 	ug/E
|<HI	 j) s   ';E"$BE""E76E7c                 2   U(       a  U/O/ SQn/ nU HD  nU R                  USS9nU(       d  U R                  USS9nU H  nUR                  U5        M     MF     U(       d  U R                  (       d  ggSS/n0 nU H$  nUS   nXH;  a  / X'   X   R                  U5        M&     UR	                  5        H  u  pU	R                  5       n
U	[        ;   a  [        U	   S	   n
UR                  S
U
 S35        U H  nSnU	S:X  a-  U R                  US   US   5      nUS:X  a  SnO3US:X  a  SnO*SnO'U	[        ;   a  [        U	   S   nUS:X  a  SnOUS:X  a  SnUR                  US    SUS    35        UR                  SUS    U 35        UR                  S5        M     M      SSKJ	n  U(       a  [        UR                  5       5      S   OSnU" USS9nU(       aY  UR                  S5        U H1  nUR                  SUS    35        UR                  S US!    35        M3     UR                  S5        UR                  S$5        UR                  S%5        S&R                  U5      $ ! [         a"  n[        R                  S"U 35         S#nANZS#nAff = f)'z
Get today's full slate with tempo classification.
Games are tagged as CONTROLLED / MIXED / CHAOTIC to help
Bill quickly identify the best betting targets.

r	   r   r   r   r   r$   r/   r1   r-   r   r5   r  r  u   Odds API returned no games right now. Could be early — bookmakers may not have posted yet. Check back in a bit or try 'what's good tonight'. — Lukeu   TODAY'S SLATE — Luker   r   r7   u   ── u    ──r	   r  r  r   u    ★ CONTROLLEDr   u    ⚡ CHAOTICz ~ MIXEDr6   u    ★ TIER 1r@   u
    ⚠ AVOIDr  r  r  r   )get_general_sport_headlines)	max_itemszTOP HEADLINES:r  u       — sourcez'Headlines fetch failed (non-critical): Nu$   ★ = best targets for your strategyz)Reply 'odds [team]' for a full breakdown.r  )r  r%  r  r   r  r  r  r   r  r)  listkeysr7  r   r*  r  )r   r   sports	all_gamesr  r  r  r  by_sportr   sport_label	tempo_tagrD   r6   r)  primary_sport	headlineshr?  s                      r   get_todays_slate%SportsBettingAnalyst.get_todays_slateO  s    "%  (K	A++A!+<E00q0A  #   >> H m)2. A'
A  Kq!	  !) 0I#//+K//1)<WELL7;-w78	 % 55ananUE,$5	)+$2	$.	"55.y9&ADqy$1	$0	+/s1[>2BCDr!K.!1)=>R +  !1<	HC8@D1!4eM3MQOI-."ALL2aj\!23LL8AhK=!9: # R  	;<@Ayy  	HLLB1#FGG	Hs   %BI* *
J4JJc           	      t	   U R                   (       d  g/ SQn/ nU GHP  nU R                  USS9nU(       d  U R                  USS9nU GH  nUS:X  a  U R                  US   US   5      nUS:X  a  UR	                  XSS	45        M=  US
:X  aj  [
        R                  US   0 5      n[
        R                  US   0 5      nUR                  S5      S:X  a  US   OUS   n	UR	                  XSSU	 S345        M  M  U R                  U5      n
U
R                  SS5      nUS:X  a  UR	                  XSSU
S    S345        M  US:X  d  M  US;  d  GM  UR	                  XSU
S    S345        GM!     GMS     U(       d  gSS/nUR	                  [        U5       S[        U5      S:w  a  SOS S35        UR	                  S5        U GHG  u  p]nSnUS   (       a2  US   S   S   R                  S / 5      nU(       a  [        US! S"9nUS#   nUR	                  US    S$US    35        UR	                  S%US&    S'U 35        US:X  aM  S(U;   a/  U(       a  UR	                  S)U S*35        OUR	                  S+5        OS,U;   a  UR	                  S-5        OU R                  U5      n
U
R                  SS5      nU
R                  S.S/5      nU
R                  S0S15      nUS:X  aZ  U(       a  U(       a	  U S2U S33nO.S4nO+US5::  a  U(       a	  U S6U S73nOS8nOU(       a	  U S9U S33nOS:nUR	                  S;U 35        O-US:X  a'  U(       a	  U S2U S33nOS<nUR	                  S;U S=35         SS>K
Jn  U" US   US   W5      nUR                  S?S5      nUR                  S@S5      nUSA:X  a  UR	                  SBUSSC  35        O;USD:X  a  UR	                  SEUSSC  35        OUSF:X  a  UR	                  SGUSSC  35        UR	                  S5        GMJ      SSHKJnJn  US   u  nnnU" US   US   U5      nU" UUS   US   5      nU(       a"  UR	                  U5        UR	                  S5        UR	                  SI5        UR	                  SJ5        SKR!                  U5      $ ! [         a     Nf = f! [         a     NOf = f)Lu8  
'What's good today/tonight' — only returns games that pass
Bill's strategy filter. No noise, just the plays.

Filter rules:
  NHL: controlled or mixed tempo only (skip chaotic)
  Soccer: Tier 1 leagues only + Tier 2 with caution note
  NFL: games with total <= 44 (defensive matchups)
  Everything else: skip
r  r(  r5   r  r	   r  r  r   u   ★ CONTROLLED — prime targetr   rD   rC   u
   MIXED — z anchors the pacer6   r<   u   ★ r7   z	 (Tier 1))r"   r&   u    (Tier 2 — filter)u:   Nothing jumps out today. Strategy says sit tight. — Lukeu   WHAT'S GOOD TODAY — Luker   z gamer  z passed the filter:Nr  r   r  r  c                     U S   $ r	  r   r  s    r   r  7SportsBettingAnalyst.get_best_targets.<locals>.<lambda>  s    7r   r  r  r  r  r  r$  
CONTROLLEDz  Legs: U6.5 + z +1.5 PL + opponent U2.5 TTz/  Legs: U6.5 + U3.5 first two periods + 1P U1.5MIXEDz/  Legs: U6.5 + non-anchor U3.5 TT + fav +1.5 PLr   Fr8   r=   z DC + Range 1-4 + z O3 cornerszU2.5 + Range 0-2 + Corners U9.5gffffff@z DC + opponent Not 2-3 range + z O2 cornerszRange 1-4 + U2.5 + Corners O5z DC + O1 goals + z!Range 1-5 + O1 goals + Corners O6z  Legs: zU2.5 + Range 0-3 + Corners U9.5u    (caution — Tier 2))r  verdictreason	VALIDATEDu     ★ PREGAME: VALIDATED — <   CAUTIONu     ⚠️ PREGAME: CAUTION — DROPPEDu     ❌ PREGAME: DROPPED — r  r  z/Reply 'odds [team]' to dive deeper on any game.r  )r   r  r%  r   r  r   r   r  r3  r  r  r  r7  r  r  r  r  ) r   r.  targetsr  r  r  rD   r  r   r!  r  r6   r  r   tagr  r  r  r   r8   legsr  r]  r=  r>  r  r  top_game	top_sport_r  r  s                                    r   get_best_targets%SportsBettingAnalyst.get_best_targets  s    ~~ DtA++A!+<E00q0A: 55ananUE,.O'PQ')!2!6!6q~r!J!2!6!6q~r!J39::g3F%3O;UVWbUc
6(BS.T'UV * $(#?#?#BL'++FA6Dqy\'5J4K9.U'VWq0L'Lg1F0GG[.\']^% 	 0 O-r2G~U#g,!2C3*LL_`aR$MAc Moa(377rBc';<C$'KMLLAkN+3q~.>?@LL2an-U3%89 ~3&$}oE`%ab'VX^LL#RT#;;A>#''2%))(E:(,,[#>	19(&3_4F}oU`#aD#DD"c)(&3_4STaSbbm#nD#BD(&3_4Em_T_#`D#FDLL8D6!23QY$"/0B=/Q\]@LL8D61F!GH;!!K.!K.!D%%	2.x,k)LL#@!NO	)LL#A&"+!OP	)LL#>vcr{m!LM LLC %H		X%,QZ"Hi)(;*?+AVXabG6w@UW_`kWlmL\*R  	PQFGyy'    		s2   #AR;RRAR* 
R'&R'*
R76R7)r   r,  r   )r	   r<   )r	   r5   )__name__
__module____qualname____firstlineno____doc__r   propertyr   r   r  r  r  r&  r)  r,  setr%  r@  rJ  r  r  r  r  r  r  r%  r6  rI  __static_attributes__r   r   r   r   r      s    U  &1f1
V
 JNN%6p
(T&Pc0!FJ XiV+ZN `A r   r   c                  0    [         c
  [        5       q [         $ )z'Get the singleton SportsBettingAnalyst.)_analystr   r   r   r   get_analystrU  '  s     ')Or   )rO  osr2  loggingr/  r   r   r   configr   	getLoggerr   r   getenvr.  r  r  r   
GOAL_BANDSr  rE  r   rT  rU  r   r   r   <module>r\     sc  2 
    . . 			+	, ""Cbii&C1	?	! 
< %	
 
 
> 
 
! $ % ' ( $ %  -!" 4#$ 1%( '3)08?/7
F 93dMO93dOQ/[_\^ 93eKMCuacCuEG |#UZWY|#UZVX% .#U_VZ[# dS# U5J\`a	#
 e.@RVW# u/@RVW# E4HZ^_# u}VZ[# 53DVZ[# u/ASWX# 53DVZ[# e6GY]^# 0BTXY# 0EW[\# 53DVZ[#  u/BTXY!#$ VnV[\%#& 2BTYZ'#( %+5HZ_`"(<QVW%+6HZ_`!'/SXY &1EW\]#)4HZ_`%+6L^cd"(3GY^_%+6J\ab &1GY^_%+6J\ab$*_V[\$*\SXY!'2FX]^"(3DV[\E# P  

 ES
 S"-/CSEOQeS S  *+<S ?GHYS "	S %23H	S KTUj	S
 oS
  (S !S %S (./DS S ",->S S !*+;S OS (S "S %01DS &S )01FS "S %./AS %S (./DS 'S *45JS  !!S" %#S$ %S$ *+;%S& %'S& (-.B'S( ^)S( &~)S* +S, &-S, )01F-S. &/S0 $1S0 './B1S2 3S2 !*+;3S4 5S4 !*+;5S6 !7S6 $*+=7S8 _9S: ;S<  =S> ,?S> /67M?S@ +ASD "ESF _GSH #ISH &./DISJ KSL "MSL %-.CMSN  OSP #QSR  SSR #*+;SST _UST (USV "WSX _YSZ "[S\ %]S\ (45J]S^ &_S` aSb "cSd eSf %gSh !iSj  kSl )mSn oSp "qSr  sSt (uSt +12HuSv "wSx $ySz {S~ yS~ $YS@ AS@ %kASB !CSB $*+<CSD %ESD (01DESF yGSH $ISH './BISJ #KSJ &/0BKSL =MSL #*=MSN *OSP !QSP $-.?QSR &SSR )12BSST USV hWSX 'YSX *9:SYSZ $[S\ %]S\ (01D]S^ y_S` !aSb  eSlo  o f r   