
    iFi:                     t   d 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mZm	Z	m
Z
 ej                  j                  dej                  j                  ej                  j                  ej                  j                  e            d             ddlmZmZ dhZdefd	Z	 	 	 d4d
edededee   dee   defdZ	 	 	 	 	 	 	 	 	 d5dedededededededee	e      dee   defdZ	 	 d6dededededed ed!ed"ee   d#ee   d$ee   d
ed%edefd&Z	 	 	 	 d7dededed ed!ed"ee   d#ee   d$ee   d'ee   d(ed
ed)ee   defd*Zd+ededefd,Zd+edede	e   fd-Z 	 d8dededed.ee   ddf
d/Z!	 d8dedededed.ee   dee   fd0Z"	 	 	 d9dedededed1e	eee
f      d.ee   d
ed2edeeef   fd3Z#	 ddl$Zy# e%$ r Y yw xY w):z
Unified Odds Ingestion Helper

This module provides functions to write odds data to the new unified schema
(BookmakerOdds, OddsHistoryV2, OddsIngestion tables).

Used by existing cron scripts to ensure data flows to both legacy and unified tables.
    N)datetimetimezone)OptionalDictListAnyz..)ABBREV_TO_FULLnormalize_to_fullnbadb_urlc                 ,    t        j                  |       S )z$Create database connection from URL.)psycopg2connect)r   s    ?/var/www/html/eventheodds/scripts/lib/unified_odds_ingestion.pyget_db_connectionr      s    F##    sourceleaguerun_type
start_dateend_datereturnc                     | j                         }|j                  d|||||f       |j                         d   }| j                          |j	                          |S )zN
    Log the start of an ingestion run.
    Returns the ingestion run ID.
    z
        INSERT INTO "OddsIngestion" (
            source, league, "runType", "startDate", "endDate",
            "startedAt", status
        ) VALUES (%s, %s, %s, %s, %s, NOW(), 'running')
        RETURNING id
    r   )cursorexecutefetchonecommitclose)connr   r   r   r   r   curingestion_ids           r   log_ingestion_startr"      sZ     ++-CKK  &(J	9; <<>!$LKKMIIKr   r!   games_processedbookmakers_seenodds_createdodds_updatedsnapshots_createderrors_counterrorsmetadatastatusc                     | j                         }|j                  d|||||||rt        j                  j	                  |      nd|	rt        j                  j	                  |	      nd|
|f
       | j                          |j                          y)z'Log the completion of an ingestion run.a  
        UPDATE "OddsIngestion"
        SET "completedAt" = NOW(),
            "durationMs" = EXTRACT(EPOCH FROM (NOW() - "startedAt")) * 1000,
            "gamesProcessed" = %s,
            "bookmakersSeen" = %s,
            "oddsCreated" = %s,
            "oddsUpdated" = %s,
            "snapshotsCreated" = %s,
            "errorsCount" = %s,
            errors = %s::jsonb,
            metadata = %s::jsonb,
            status = %s
        WHERE id = %s
    N)r   r   r   extrasJsonr   r   )r   r!   r#   r$   r%   r&   r'   r(   r)   r*   r+   r    s               r   log_ingestion_completer/   6   sz     ++-CKK  	,<(.V$D*2X&
* 	KKMIIKr   game_id	game_date	home_team	away_team	bookmakermarket
line_value	home_odds	away_odds
is_openingc                     | j                         }||nd}|j                  d||||f       |j                         }|r^|\  }}}d}|||t        |      z
  }d}|	||	|z
  }|j                  d|	|
||||f       | j	                          |j                          y|j                  d|||||||||	|
||	|
t        j                  t        j                        |f       | j	                          |j                          y)zU
    Upsert a bookmaker odds record.
    Returns (created: bool, updated: bool).
    Ng        z
        SELECT id, "openingLineValue", "openingHomeOdds"
        FROM "BookmakerOdds"
        WHERE "gameId" = %s AND bookmaker = %s AND market = %s AND COALESCE("lineValue", 0) = %s
    a  
            UPDATE "BookmakerOdds"
            SET "homeOdds" = COALESCE(%s, "homeOdds"),
                "awayOdds" = COALESCE(%s, "awayOdds"),
                "lineValue" = COALESCE(%s, "lineValue"),
                "lineMovement" = %s,
                "oddsMovement" = %s,
                "fetchedAt" = NOW(),
                "updatedAt" = NOW()
            WHERE id = %s
        )FTa  
            INSERT INTO "BookmakerOdds" (
                "gameId", league, "gameDate", "homeTeam", "awayTeam",
                bookmaker, market, "lineValue", "homeOdds", "awayOdds",
                "openingLineValue", "openingHomeOdds", "openingAwayOdds", "openingAt",
                source, "fetchedAt"
            ) VALUES (
                %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
                %s, %s, %s, %s, %s, NOW()
            )
        )TF)
r   r   r   floatr   r   r   nowr   utc)r   r0   r   r1   r2   r3   r4   r5   r6   r7   r8   r   r9   r    line_value_normexistingexisting_idexisting_opening_lineexisting_opening_oddsline_movementodds_movements                        r   upsert_bookmaker_oddsrE   ^   s8   & ++-C %/$:jO KK  9fo	6	8 ||~HDLA*,A !&;&G&/D)EEM %:%F%(==M 	 
 J}kZ
	\ 			 	 
 VY	9vz9i	9hll8<<.H
	" 			r   hours_to_gamesnapshot_typebookmaker_odds_idc                    | j                         }|	g|ret        j                  t        j                        }|j
                   |j                  t        j                        }||z
  j                         dz  }		 |j                  d||||||||nd|||	|
|f       | j                          |j                          y# t        j                  $ r# | j                          |j                          Y yw xY w)z\
    Insert an odds history snapshot.
    Returns True if inserted, False if duplicate.
    )tzinfoi  a{  
            INSERT INTO "OddsHistoryV2" (
                "bookmakerOddsId", "gameId", league, "gameDate",
                bookmaker, market, "lineValue", "homeOdds", "awayOdds",
                "snapshotAt", "hoursToGame", "snapshotType", source
            ) VALUES (
                %s, %s, %s, %s, %s, %s, %s, %s, %s,
                NOW(), %s, %s, %s
            )
        r   TF)r   r   r<   r   r=   rJ   replacetotal_secondsr   r   r   r   IntegrityErrorrollback)r   r0   r   r1   r4   r5   r6   r7   r8   rF   rG   r   rH   r    r<   s                  r   insert_odds_historyrO      s    & ++-C ll8<<(#!)))>I"S779D@ 	 w	vZ-Czy=&	
	 			"" 		s   ;AB> >3C43C4	team_namec                     t        | |      xs | }|t        vr|S t        j                  |i       }|j	                         D ]  \  }}||k(  s|c S  |S )zDConvert incoming team text to the canonical SportsGame storage form.)r
   SPORTSGAME_CODE_LEAGUESr	   getitems)rP   r   	full_name
league_mapabbrevmapped_fulls         r   _to_sportsgame_team_valuerY      sf    !)V4A	I,,##FB/J)//1 )#M r   c                     g }| s|S | j                         }t        ||      xs |}t        ||      }|||fD ]  }|s||vs|j                  |        |S )z
    Build lookup candidates that can match both legacy full-name rows and the
    corrected canonical storage form for the league.
    )stripr
   rY   append)rP   r   
candidatesrawrU   stored_valuevalues          r   _sportsgame_lookup_candidatesra      sq    
 J
//
C!#v.5#I,S&9Ly,/ %U*,e$% r   external_game_idc           
          | j                         }|j                  d|||||||f       |j                  r| j                          |j	                          y)z
    Normalize an existing SportsGame row in place when we match it through a
    legacy identity (full names, missing externalGameId, etc.).
    a  
        UPDATE "SportsGame"
        SET "homeTeam" = %s,
            "awayTeam" = %s,
            "externalGameId" = COALESCE("SportsGame"."externalGameId", %s),
            "updatedAt" = NOW()
        WHERE id = %s
          AND (
            COALESCE("homeTeam", '') <> %s OR
            COALESCE("awayTeam", '') <> %s OR
            (%s IS NOT NULL AND "externalGameId" IS NULL)
          )
        N)r   r   rowcountr   r   )r   r0   r2   r3   rb   r    s         r   _refresh_sports_game_identityre     sW     ++-CKK	 	
0 ||IIKr   c           
         |j                         }t        ||      }t        ||      }t        ||      }t        ||      }| j                         }|rL|j	                  d|f       |j                         }	|	r't        | |	d   |||       |j                          |	d   S |j                  dddd      }
|
j                  ddd      }|j	                  d||||
|||f       |j                         }	|	r't        | |	d   |||       |j                          |	d   S |j                  }	 |j	                  d||||||f       |j                         d   }| j                          |j                          |S # t        j                  $ ru | j                          |j                          | j                         }|j	                  d	||||
|f       |j                         }	|j                          |	r|	d   cY S d
cY S w xY w)z
    Find or create a SportsGame record.
    Returns the game ID.
    Uses the league's canonical SportsGame storage format.
    zY
            SELECT id FROM "SportsGame"
            WHERE "externalGameId" = %s
        r   )hourminutesecondmicrosecond   ;   )rg   rh   ri   ab  
        SELECT id FROM "SportsGame"
        WHERE league = %s
          AND "homeTeam" = ANY(%s)
          AND "awayTeam" = ANY(%s)
          AND "gameDate" BETWEEN %s AND %s
        ORDER BY
          CASE WHEN "homeTeam" = %s AND "awayTeam" = %s THEN 0 ELSE 1 END,
          CASE WHEN "externalGameId" IS NULL THEN 1 ELSE 0 END,
          id DESC
    a  
            INSERT INTO "SportsGame" (
                league, season, "gameDate", "homeTeam", "awayTeam", "externalGameId",
                "createdAt", "updatedAt"
            ) VALUES (%s, %s, %s, %s, %s, %s, NOW(), NOW())
            ON CONFLICT (league, season, "gameDate", "homeTeam", "awayTeam") DO UPDATE SET
                "externalGameId" = COALESCE("SportsGame"."externalGameId", EXCLUDED."externalGameId"),
                "updatedAt" = NOW()
            RETURNING id
        z
            SELECT id FROM "SportsGame"
            WHERE league = %s
              AND "homeTeam" = %s
              AND "awayTeam" = %s
              AND "gameDate" BETWEEN %s AND %s
        N)lowerra   rY   r   r   r   re   r   rK   yearr   r   rM   rN   )r   r   r1   r2   r3   rb   home_lookupaway_lookupr    result	day_startday_endseasonr0   s                 r   get_or_create_sports_gameru   0  s	    \\^F/	6BK/	6BK))V<I))V<I
++-C    	" )$q	9iQabIIK!9 !!q1!!LIR2>GKK 
 +{Iw	9	U
W \\^F%dF1Iy)M]^		ay ^^F- 	 fiI?OP		R ,,.#		"" -		kkm  iIw?	A 		"vay,,-s   'AE4 4BG<7G<;G<bookmaker_oddscreate_snapshotsc	                    dddd}	t        | |||||      }
|
s|	S |D ]  }|j                  dd      }|j                  di       }|j                         D ]  \  }}|dk(  rd}n|dk(  rd	}n
|d
k(  rd}n|}|j                  d      }|j                  d      }|j                  d      }||Xt        | |
||||||||||      \  }}|r|	dxx   dz  cc<   |r|	dxx   dz  cc<   |st	        | |
||||||||
      s|	dxx   dz  cc<     |	S )aD  
    Process all bookmaker odds for a single game.

    bookmaker_odds should be a list of dicts with:
    - bookmaker: str
    - markets: dict with keys like 'h2h', 'spreads', 'totals'
      each containing 'home_odds', 'away_odds', 'line' (for spreads/totals)

    Returns dict with 'created', 'updated', 'snapshots'.
    r   )createdupdated	snapshotsr4   unknownmarketsh2h	moneylinespreadsspreadtotalstotalliner7   r8   ry      rz   )r   r{   )ru   rS   rT   rE   rO   )r   r   r1   r2   r3   rv   rb   r   rw   statsr0   	book_datar4   r}   
market_keymarket_datar5   r6   r7   r8   ry   rz   s                         r   process_odds_for_gamer     su   * aa8E (fiI7GG # ),	MM+y9	--	2.'.}} %	,#JU"$y(!x' #$0J#4I#4I  Y%6  5gvy)Y6:y)V GW
 i A% i A%   &'69vz9i!
 +&!+&K%	,	),V Lr   )	scheduledNN)	r   r   r   r   r   r   NN	completed)the-odds-apiF)Nperiodicr   N)N)Nr   T)&__doc__ossysr   r   r   typingr   r   r   r   pathinsertjoindirnameabspath__file__
team_namesr	   r
   rR   strr   intr"   r/   r;   booltuplerE   rO   rY   ra   re   ru   r   psycopg2.extrasImportError r   r   <module>r      s   
 
  ' , , 277<<0I JDQ R 8
 !' $c $  %)#'  	
 " x  	: "&#%% % 	%
 % % % % T#Y% tn% %h !QQ Q 	Q
 Q Q Q Q Q }Q }Q Q Q Q| &*# '+22 2 	2
 2 2 2 }2 }2 E?2 2 2  }2 
2j
 
c 
c 
S # $s) 0 '+&& & 	&
 sm& 
&^ '+W-W- W- 	W-
 W- smW- c]W-B '+ !II I 	I
 I c3h(I smI I I 
#s(^IZ	 		s   *F/ /F76F7