
    iG                    h   S r SSKJr  SSKrSSKrSSKJr  SSKJrJ	r	  SSK
Jr  SSKrSSKJr  SSKJrJrJrJrJr  SS	KJr  SS
KJrJr  SSKJr  SSKJr  SSKJr  \" 5         \" \ 5      r!\" 5       r"S<S jr# S=       S>S jjr$\ " S S5      5       r%\ " S S5      5       r&\RN                  " SSSSS9r(\RN                  " SSSSS9r)\RN                  " SS\RT                  " / SQSS 9S!S"9r+\RN                  " S#SSS$S%9r,\RZ                  " 5       S& 5       r.\.R_                  5       \(\)\+\,\RN                  " S'S\R`                  " SS(5      SS)S*9\RN                  " S+\RT                  " S,S-/SS 9S,SS.S/9            S?S0 j5       5       5       5       5       5       5       r1\.R_                  5       \(\)\,\RN                  " S1SSS2S%9\RN                  " S3SSS4S%9          S@S5 j5       5       5       5       5       5       r2\.R_                  5       \(\)\+\,\RN                  " S+\RT                  " S,S-/SS 9S,SS6S/9\RN                  " S1SSS2S%9\RN                  " S3SSS4S%9              SAS7 j5       5       5       5       5       5       5       5       r3SBS8 jr4SCS9 jr5          SDS: jr6\ S;:X  a  \." 5         gg)EzBatch backfill CLI for historical TAB data ingestion and recomputation.

Backfills data in monthly chunks with progress logging and error handling.
Supports ingest-only, recompute-only, and full (ingest + recompute) modes.
    )annotationsN)
monthrange)	dataclassfield)date)Console)	BarColumnProgressSpinnerColumn
TextColumnTimeElapsedColumn)Table)
get_loggersetup_logging)get_settings)get_session)IngestionServicec                    U R                  SS9n[        U R                  U R                  5      S   nU R                  US9nX4$ )z;Return (first_day, last_day) of the month containing *ref*.   day)replacer   yearmonth)reffirstlast_daylasts       ;/root/tipsharks/tipsharks-elo-api/scripts/batch_backfill.py_month_boundsr    #   sC    KKAKE#((CII.q1H;;8;$D;    r   	date_fromdate_toc                   / nU R                  SS9nXA::  a  UR                  S-
  U-   nUR                  US-  -   nUS-  S-   n[        Xe5      S   n[	        XeU5      nUn	[        X5      nX::  a  UR                  X45        UR                  n
UR                  nU
S:X  a  Sn
US-  nOU
S-  n
[	        XS5      nXA::  a  M  U$ )z}Split [date_from, date_to] into monthly (or multi-month) chunks.

Each chunk is a (start, end) tuple inclusive on both ends.
r   r      )r   r   r   r   r   minappend)r"   r#   chunk_monthschunkscursorchunk_end_monthchunk_end_yearr   	chunk_endchunk_start
next_month	next_years               r   _iter_month_chunksr1   +   s     ')F1%F

 ,,*\9"'<<)B.2n>qA(C		+	!MM;23 __
NN	JNI!OJiQ/- 
0 Mr!   c                      \ rS rSr% SrS\S'   S\S'   SrS\S'   S	rS
\S'   S	rS
\S'   S	r	S
\S'   S	r
S
\S'   SrS\S'   Srg)ChunkResultO   z,Result of processing a single monthly chunk.r   r.   r-   Fboolsuccessr   intmeetingsracesstarterserrors strerror_message N)__name__
__module____qualname____firstlineno____doc____annotations__r6   r8   r9   r:   r;   r>   __static_attributes__r?   r!   r   r3   r3   O   sJ    6OGTHcE3NHcFCOM3r!   r3   c                      \ rS rSr% SrS\S'   S\S'   S\S'   S\S'   S	\S
'   SrS\S'   SrS\S'   SrS\S'   Sr	S\S'   Sr
S\S'   SrS\S'   SrS\S'   SrS\S'   \" \S9rS\S'   SS jrSrg)BackfillSummary]   z%Aggregated summary of a backfill run.r=   commandr   r"   r#   categoryr5   dry_runr   r7   total_chunkssuccessful_chunksfailed_chunkstotal_meetingstotal_racestotal_starterstotal_errorssnapshots_created)default_factoryzlist[tuple[str, str, str]]failed_detailsc           
     *   [        SS9nUR                  SSS9  UR                  SSSS	9  UR                  S
U R                  5        UR                  SU R                   SU R
                   35        UR                  SU R                  5        UR                  S[        U R                  5      5        UR                  S[        U R                  5      5        U R                  (       a$  UR                  S[        U R                  5      SS9  UR                  S[        U R                  5      5        UR                  S[        U R                  5      5        UR                  S[        U R                  5      5        U R                  (       a$  UR                  S[        U R                  5      SS9  U R                  (       a%  UR                  S[        U R                  5      5        [         R#                  S5        [         R#                  U5        U R$                  (       a  [         R#                  S5        U R&                  (       aa  [         R#                  S[)        U R&                  5       S35        U R&                   H%  u  p#n[         R#                  SU SU SU S35        M'     U R                  S:X  a'  U R$                  (       d  [         R#                  S5        g"U R                  S:  a$  [         R#                  S U R                   S!35        g"g")#z Render summary table to console.zBackfill SummarytitleMetriccyanstyleValuegreenright)r]   justifyCommandz
Date range to CategoryzTotal chunkszSuccessful chunkszFailed chunksredzTotal meetingszTotal raceszTotal startersErrorszRating snapshots
u6   
[yellow]⚠ DRY RUN — no data was modified[/yellow]u   
[yellow]⚠ z chunk(s) failed:[/yellow]z
  [yellow]z: z	[/yellow]r   u3   
[green]✓ Backfill completed successfully[/green]u   
[yellow]⚠ Completed with z failed chunk(s)[/yellow]N)r   
add_columnadd_rowrJ   r"   r#   rK   r=   rM   rN   rO   rP   rQ   rR   rS   rT   consoleprintrL   rV   len)selftablecsceerrs        r   rk   BackfillSummary.printp   sJ   ./0Ai.lt~~&6d4<<.$IJj$--0nc$*;*;&<=)3t/E/E+FGMM/3t/A/A+B%MP&D,?,?(@AmS)9)9%:;&D,?,?(@AMM(C(9(9$:%MH!!MM,c$2H2H.IJde<<MMSTMMN3t/B/B+C*DD^_`#22
2$d2$bYGH  3 "4<<MMPQ!#MM9$:L:L9MMfgh $r!   r?   N)returnNone)r@   rA   rB   rC   rD   rE   rM   rN   rO   rP   rQ   rR   rS   rT   r   listrV   rk   rF   r?   r!   r   rH   rH   ]   s    /LOMMML#sM3NCKNCL#s16t1LN.L#ir!   rH   z--fromTzStart date (YYYY-MM-DD))requiredhelpz--tozEnd date (YYYY-MM-DD)z
--category)THGF)case_sensitivez=Racing category: T (Thoroughbred), H (Harness), G (Greyhound))defaulttyperw   z	--dry-runz)Show what would be done without executing)is_flagr|   rw   c                     g)zBatch backfill historical TAB data in monthly chunks.


Commands:
  ingest     - Ingest data in monthly chunks
  recompute  - Recompute ratings for a date range
  full       - Run ingest + recompute sequentially
Nr?   r?   r!   r   clir      s     	r!   z--chunk-months   zNumber of months per chunk)r|   r}   show_defaultrw   z--sourcetabingestzData source)r}   r|   r   rw   c                H   [        U 5      n[        U5      n[        5       nU(       a  UR                  5       OUR                  R                  n	[        XgU5      n
[        SU S3UUU	U[        U
5      S9n[        R                  SU	 SU SU S[        U
5       S3	5        U(       a1  [        R                  S	5        [        U
5        UR                  5         g
[        [        5       [        S5      [        5       [        S5      [        5       [        S9 nUR!                  S[        U
5      S9nU
 GHE  u  p[#        XX5      nU=R$                  S-  sl        UR&                  (       a  U=R(                  S-  sl        U=R*                  UR,                  -  sl        U=R.                  UR0                  -  sl        U=R2                  UR4                  -  sl        U=R6                  UR8                  -  sl        OdU=R:                  S-  sl        U=R6                  S-  sl        UR<                  R?                  [A        U5      [A        U5      URB                  45        URE                  USSU SU 3S9  GMH     S
S
S
5        UR                  5         g
! , (       d  f       N= f)zIngest TAB data in monthly chunks.

Splits the date range into monthly (or multi-month) chunks and ingests
each chunk sequentially. Continues on chunk failure and reports summary.
zingest ()rJ   r"   r#   rK   rL   rM   z
[bold]Ingesting  data from rc   z in z chunk(s)[/bold]6   [yellow]DRY RUN — no data will be modified[/yellow]
N([progress.description]{task.description}-[progress.percentage]{task.percentage:>3.0f}%rj   Ingesting...totalr   
Ingesting advancedescription)#_parse_date_argr   upperr   default_categoryr1   rH   rl   rj   rk   _show_chunksr
   r   r   r	   r   add_task_do_ingest_chunkrM   r6   rN   rP   r8   rQ   r9   rR   r:   rS   r;   rO   rV   r'   r=   r>   update)r"   r#   rK   rL   r(   source
start_dateend_datesettingseffective_categoryr)   summaryprogresstaskr.   r-   results                    r   r   r      s=   @ !+Jw'H~H-5)8<<;X;X
lCF6(!$#[G MM
/0,d8*DV5E	G OPV	=>BC
 
  s6{ C&,"K%k>PYF  A% ~~))Q.)&&&//9&##v||3#&&&//9&$$5$%%*%$$)$&&--%s9~v7K7KL OOD!:k]RVW`Va9bOc# '-
: MMO;
 
s   E&J
J!z--clearz'Clear existing ratings before recomputez--learn-adjustmentsz3Learn barrier/handicap adjustments during recomputec           	     4   [        U 5      n[        U5      n[        SUUSUSS9n[        R                  SU SU S35        U(       a  [        R                  S5        U(       a  [        R                  S	5        U(       a&  [        R                  S
5        UR                  5         g SSKJn  [        5        n	U" U	UUUUS9n
SSS5        SUl        W
Ul        [        R                  SU
 S35        UR                  5         g! , (       d  f       NF= f! [         az  nSUl
        UR                  R                  [        U5      [        U5      [        U5      45        [        R                  SU 3SS9  [        R                  SU S35         SnANSnAff = f)zRecompute ratings for a date range.

Runs a single recompute over the full date range (no chunking since
recompute is incremental and deterministic).
	recomputezN/Ar   r   z 
[bold]Recomputing ratings from rc   z[/bold]z=[yellow]Will clear existing ratings before recompute[/yellow]z8[yellow]Will learn barrier/handicap adjustments[/yellow]u6   
[yellow]DRY RUN — no data will be modified[/yellow]Nr   recompute_ratingsclear_existinglearn_adjustmentsu   
[green]✓ ! rating snapshots created[/green]Recompute failed: Texc_infou   
[red]✗ Recompute failed: [/red])r   rH   rj   rk   packages.core.ratings.recomputer   r   rN   rT   	ExceptionrO   rV   r'   r=   loggererror)r"   r#   rL   clearr   r   r   r   r   session	snapshotses               r   r   r   !  sn   8 !+Jw'HG MM
+J<tH:WM UVPQOPAE]g)$"3I  %&!$-!i[0QRS MMO% ]  A !%%s:Hs1v&NO)!-=5aS?@@	As1   'D 7D/D 
DD 
FA0FFzData source for ingestionc                ~   [        U 5      n[        U5      n[        5       n	U(       a  UR                  5       OU	R                  R                  n
[        XxS5      n[        SU S3UUU
U[        U5      S9n[        R                  SU
 SU SU S[        U5       S	3	5        U(       a^  [        R                  S
5        [        U5        [        R                  SU(       a  SOS U(       a  SOS S35        UR                  5         g[        R                  S5        [        [        5       [        S5      [        5       [        S5      [        5       [        S9 nUR!                  S[        U5      S9nU GHG  u  nn[#        UUX5      nU=R$                  S-  sl        UR&                  (       a  U=R(                  S-  sl        U=R*                  UR,                  -  sl        U=R.                  UR0                  -  sl        U=R2                  UR4                  -  sl        U=R6                  UR8                  -  sl        OdU=R:                  S-  sl        U=R6                  S-  sl        UR<                  R?                  [A        U5      [A        U5      URB                  45        URE                  USSU SU 3S9  GMJ     SSS5        [        R                  S5        UR(                  S:X  a  [        R                  S5        OD SSK#J$n  [K        5        nU" UUUUUS9nSSS5        WUl&        [        R                  SU S35        UR                  5         g! , (       d  f       N= f! , (       d  f       NP= f! [N         a:  n[P        RS                  S U 3S!S"9  [        R                  S#U S$35         SnANrSnAff = f)%zRun ingest + recompute sequentially for a date range.

Ingests data in monthly chunks, then recomputes ratings over the
full date range. Reports a combined summary.
r   zfull (ingest=z + recompute)r   z
[bold]Full backfill: r   rc   z (z chunk(s))[/bold]r   z?[dim]After ingest: will recompute ratings and learn adjustmentsz (with clear)r<   z (learn adjustments)z[/dim]Nz*
[bold cyan]Phase 1: Ingestion[/bold cyan]r   r   r   r   r   r   r   z*
[bold cyan]Phase 2: Recompute[/bold cyan]r   u9   [yellow]No data ingested — skipping recompute.[/yellow]r   r   u   [green]✓ r   r   Tr   u   [red]✗ Recompute failed: r   )*r   r   r   r   r   r1   rH   rl   rj   rk   r   r
   r   r   r	   r   r   r   rM   r6   rN   rP   r8   rQ   r9   rR   r:   rS   r;   rO   rV   r'   r=   r>   r   r   r   r   rT   r   r   r   )r"   r#   rK   rL   r   r   r   r   r   r   r   r)   r   r   r   r.   r-   r   r   r   r   r   s                         r   fullr   q  sD   L !+Jw'H~H-5)8<<;X;X
a8Fx}5#[G MM
!"4!5[,d8*Bs6{m3D	F
 OPVM"'R0):%C6K	

 	 MM?@	=>BC
 
  s6{ C&,"K%k9>PYF  A% ~~))Q.)&&&//9&##v||3#&&&//9&$$5$%%*%$$)$&&--%s9~v7K7KL OOD!:k]RVW`Va9bOc# '-
< MM?@  A%QR	CI'-#(&7	  )2G%MMK	{2STU
 MMOi
 
L   	CLL-aS1DLAMM7s&ABB	Cs=   E(MM8 M'(M8 
M$'
M51M8 8
N<0N77N<c                     [         R                  " U 5      $ ! [         a2    [        R	                  SU  S35        [
        R                  " S5         gf = f)z&Parse a YYYY-MM-DD string into a date.z[red]Error: Invalid date 'z'. Use YYYY-MM-DD format.[/red]r   N)r   fromisoformat
ValueErrorrj   rk   sysexit)values    r   r   r     sI    !!%(( 25'9XYZs    9AAc                ,   [        SS9nUR                  SSS9  UR                  SSS9  UR                  SSS9  [        U S	5       H6  u  nu  p4UR                  [	        U5      [	        U5      [	        U5      5        M8     [
        R                  U5        g
)z+Display the chunks that would be processed.zPlanned Chunks (DRY RUN)rX   #dimr\   Startr[   Endr   N)r   rh   	enumerateri   r=   rj   rk   )r)   rn   idxro   rp   s        r   r   r     s    23E	S&	WF+	U&)"61-Xbc#hBR1 . MM%r!   c           
     .   [        XS9n [        5        n[        XSS9n[        R                  " UR                  XUS95      u  pxn	SSS5        SUl        WUl        WUl        W	Ul	        WR                  S   Ul        [        R                  S[        U 5      [        U5      UUU	UR                  S   S.S	9  U$ ! , (       d  f       Nz= f! [         a?  n
S
Ul        [        U
5      Ul        [        R#                  SU  SU SU
 3SS9   Sn
A
U$ Sn
A
ff = f)z1Ingest a single monthly chunk and return results.)r.   r-   )r   )rK   NTr;   zChunk ingested)r.   r-   r8   r9   r:   r;   )extraFzChunk rc   z	 failed: r   )r3   r   r   asyncioruningest_date_ranger6   r8   r9   r:   statsr;   r   infor=   r   r>   r   )r.   r-   rK   r   r   r   servicer8   r9   r:   r   s              r   r   r   	  s    [FF
]g&w>G(/))+8)T)%HX  ""h/";/ ^$$!--1 	 
	
& M? ].  
"1v[Mi[	!= 	 	

 M
s/   
C 1B:A2C :
CC 
D4DD__main__)r   r   rs   ztuple[date, date])r   )r"   r   r#   r   r(   r7   rs   list[tuple[date, date]])r"   r=   r#   r=   rK   
str | NonerL   r5   r(   r7   r   r=   )
r"   r=   r#   r=   rL   r5   r   r5   r   r5   )r"   r=   r#   r=   rK   r   rL   r5   r   r=   r   r5   r   r5   )r   r=   rs   r   )r)   r   rs   rt   )
r.   r   r-   r   rK   r=   r   r=   rs   r3   )7rD   
__future__r   r   r   calendarr   dataclassesr   r   datetimer   clickrich.consoler   rich.progressr	   r
   r   r   r   
rich.tabler   packages.core.common.loggingr   r   packages.core.common.settingsr   packages.core.storage.databaser   packages.core.storage.ingestionr   r@   r   rj   r    r1   r3   rH   option	_opt_from_opt_toChoice_opt_category_opt_dry_rungroupr   rJ   IntRanger   r   r   r   r   r   r?   r!   r   <module>r      s   #  
  (     [ [  C 6 6 < 	H	
) 9:!!"!25!!H 
 
 
 5i 5i 5it LL	"		 ,,
	 	 	oe	<	H	 ||	4	 		 		 
	1		% 	uh'	>	CCC C 	C
 C C   	  &CR 
	2	 	>	::: : 	:
 :  	   :@ 
	uh'	>	$ 	2	 	>	ddd d 	d
 d d d   	  0dT
))) ) 	)
 )X zE r!   