
    P1iZ                        d dl m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mZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZmZmZ d dlmZ ddZ G d de      Z y)    )annotationsN)ListTuple)cache)BaseCommandCommandParser)transaction)timezone)settingsget_user_model)Person)find_sanhe_groups_for_ownerfind_sanxing_groups_for_ownerevaluate_pair)GroupRelationc                L    d|  d}|dz   |dz   |dz   |dz   |dz   |dz   |d	z   d
S )Nz	bazi:grp::state
started_at
updated_aterror_atlast_retry_atresultscount)r   r   r   r   r   r   r    )user_idprefixs     P/home/cursorai/projects/iching/bazi/management/commands/recalc_bazi_relations.py_cache_keysr       sR    	#F'!|+|+Z'/1I%'!     c                  \     e Zd ZdZ fdZd Zd ZddZd ZddZ	ddZ
dd	Zdd
Z xZS )Commandz]Recalculate pairwise and 3-party BaZi relations for a user or all users, store results in DB.c                D    t        |   |i | | j                          y N)super__init___setup_logging)selfargskwargs	__class__s      r   r'   zCommand.__init__(   s!    $)&)r!   c                l   d}t         j                  j                  |      st        j                  |d       t	        j
                  dt        j                                | _        | j                  j                  t        j                         | j                  j                  sKt         j                  j                  |d      }t	        j                  |d      }|j                  t        j                         | j                         st	        j                         }|j                  t        j                         t	        j                   d      }|j#                  |       |j#                  |       | j                  j%                  |       |j                  t        j                         t	        j                   d      }|j#                  |       | j                  j%                  |       | j                         s2| j                  j'                  d	t        j                          d
       yy)zSetup logging for the commandlogsT)exist_okrecalc_bazi_relations_zrecalc_bazi_relations.logzutf-8)encodingz4%(asctime)s - %(name)s - %(levelname)s - %(message)sz0=== Starting BaZi Relations Recalculation (PID: z) ===N)ospathexistsmakedirslogging	getLoggergetpidloggersetLevelDEBUGhandlersjoinFileHandler_is_test_environmentStreamHandlerINFO	FormattersetFormatter
addHandlerinfo)r)   log_dirlog_filefile_handlerconsole_handler	formatters         r   r(   zCommand._setup_logging,   s    ww~~g&KK$/ ''*@(NOW]]+ {{##ww||G-HIH"..x'JL!!'--0 ,,.")"7"7"9((6 $--J	 )))4,,Y7&&7 !!'--0))FI %%i0KK""<0 ((*KKOPRPYPYP[}\abc +r!   c                B    ddl }t        d |j                  D              S )z,Check if we're running in a test environmentr   Nc              3  @   K   | ]  }d |j                         v   yw)testN)lower).0args     r   	<genexpr>z/Command._is_test_environment.<locals>.<genexpr>\   s     =HS6SYY[(Hs   )sysanyargv)r)   rR   s     r   r?   zCommand._is_test_environmentY   s    =CHH===r!   c                    |j                  d      }|j                  dt        d       |j                  ddd	       |j                  d
dd	       y )NT)requiredz--userzOwner user id)typehelpz--all-users
store_truezRecalculate for all users)actionrX   z--forcez'Force recalculation regardless of state)add_mutually_exclusive_groupadd_argumentint)r)   parsergroups      r   add_argumentszCommand.add_arguments^   sV    33T3B8#OD=D_`IlAjkr!   c                   |j                  dd      }|j                  dd      }| j                         s!| j                  j                  d| d|        	 |r| j	                  |       nE|d   }| j                         s| j                  j                  d|        | j                  ||       | j                         s| j                  j                  d
       y y # t        $ r]}| j                  j                  dt        |              | j                  j                  d	t        j                                  d }~ww xY w# | j                         s| j                  j                  d
       w w xY w)N	all_usersFforcezCommand started - all_users: z	, force: userzProcessing single user: zFatal error in command: Traceback: z=== Command completed ===)getr?   r9   rE   _handle_all_users_handle_single_user	Exceptionerrorstr	traceback
format_exc)r)   r*   optionsrb   rc   r   es          r   handlezCommand.handled   sJ   KKU3	GU+ ((*KK<YKyQVPWXY	>&&u-!&/002KK$$'?y%IJ((%8 ,,.  !<= /  	KK 8QABKKI,@,@,B+CDE	
 ,,.  !<= /s&   AC 	E&AD>>EE .E4c                   ddl m}  |       }| j                  j                  d| d       |j                  j                  dd      j                         }|j                         }| j                  j                  d| d	       | j                  j                  d| d	       t        |d
      D ]Z  \  }}| j                  j                  d| d| d|j                   d|j                  xs |j                   d	       | j                  j                  d| d| d|j                   d|j                  xs |j                   d	       t        j                         }	 | j!                  |j                  |       t        j                         }	|	|z
  }
| j                  j                  d|j                   d|
j#                         dd       | j                  j                  d|j                   d|
j#                         dd       ] | j                  j                  d | d!       | j                  j                  d | d!       | j                  j                  d"       y# t$        $ r}t        j                         }	|	|z
  }
d|j                   d|
j#                         ddt'        |       }| j                  j                  |       | j                  j)                  |       | j                  j)                  d|j                   dt+        j,                                 	 d|_        t        j                         |_        |j3                  ddg       d|j                   d}| j                  j                  |       | j                  j                  |       n# t$        $ r~}dt'        |       }| j                  j                  |       | j                  j)                  |       | j                  j)                  dt+        j,                                 Y d}~nd}~ww xY wY d}~d}~ww xY w)#z"Handle recalculation for all usersr   r   z2Starting bulk recalculation for all users (force: )TF)person__ownerperson__bazi_result__isnullFound z users with BaZi records   Processing user /: z (u   ✓ Completed user z in z.2fsu   ✗ Failed user z after zs: zError details for user rj   group_relations_stategroup_relations_error_atupdate_fieldsu     → Marked user z as error stateu"     → Failed to mark error state: zSave error details: NzCompleted processing z userszVUse --force flag if you need to recalculate for users who are not currently processing)django.contrib.authr   r9   rE   objectsfilterdistinctr   stdoutwrite	enumerateidemailusernamedj_tznowrh   total_secondsri   rk   rj   rl   rm   r{   r|   save)r)   rc   r   Userusers_with_bazitotal_usersird   
start_timeend_timedurationro   	error_msgsuccess_msg
save_errors                  r   rg   zCommand._handle_all_users|   s   6MeWTUVW ,,--(- . 
 (* 	
 &++-6+.FGHF;-/GHI !4GAtKK 01[MDGG9BtzzOj]a]j]jNkklmnKK/s!K=477)2djjNi\`\i\iMjjklmJ((%8 99;#j0!!$7yXE[E[E]^aDbbc"de  #6twwitHDZDZD\]`Caab!cd 5D 	1+fEF0VDErs5   99;#j0.twwiwx?U?U?WX[>\\_`cde`f_gh	!!),!!),!!$;DGG9ByG[G[G]F^"_`W18D.49IIKD1II-DF`,aIb$6twwi"OKKK%%k2KK$$[1  W"DS_DU VIKK%%i0KK%%i0KK%%(<Y=Q=Q=S<T&UVV	W -sF   "B+I**
P>4B9P9.A:N)(P9)	P02A4P+&P9+P00P99P>c           	     
     j                   j                  d d|        t              }ddl}|j	                         |j                         u }|rddl} fd} j                         s j                   j                  d d       |j                  |j                  |       |j                  d       	  j                  |       	 |j                  d        j                         s j                   j                  d        yy j                         s j                   j                  d        ddl}ddl|j%                         fd}	|j'                  |	d      }
|
j)                          	  j+                  |       	 j-                           j                         s j                   j                  d        yy# t        $ r   j                   j                  d	         t        $ r`} j                   j                  d
 dt        |               j                   j                  dt        j                                   d}~ww xY w# |j                  d        j                         s j                   j                  d        w w xY w# t        $ r   j                   j                  d	         t        $ r`} j                   j                  d
 dt        |               j                   j                  dt        j                                   d}~ww xY w# j-                           j                         s j                   j                  d        w w xY w)z&Handle recalculation for a single userz)Starting single user processing: user_id=z, force=r   Nc                Z    d }j                   j                  |       t        |      )NProcessing timeout for user )r9   rj   TimeoutError)signumframetimeout_msgr)   r   s      r   timeout_handlerz4Command._handle_single_user.<locals>.timeout_handler   s,     <WIF!!+.";//r!   z"Setting 5-minute timeout for user z (signal-based),  zTimeout occurred for user zError processing user ry   re   zCleared timeout for user zBRunning in background thread, using thread-based timeout for user c                 H     j                  d       j                          y )Nr   )sleepset)timetimeout_events   r   timeout_workerz3Command._handle_single_user.<locals>.timeout_worker   s    

3!!#r!   T)targetdaemon)r9   rE   r    	threadingcurrent_threadmain_threadsignalr?   SIGALRMalarm_process_single_userr   rj   ri   rk   rl   rm   r   EventThreadstart!_process_single_user_with_timeoutr   )r)   r   rc   keysr   is_main_threadr   r   ro   r   timeout_threadr   r   s   ``         @@r   rh   zCommand._handle_single_user   s   DWIXV[U\]^7# 	"113y7L7L7NN0 ,,.  #EgYo!^_MM&../:LLL))'59 Q002KK$$'@	%JK 3 ,,.  #efmen!op &OO-M$
 '--^D-QN  "L66w}U !!#002KK$$'@	%JK 3Y   !!$>wi"HI !!$:7)2c!fX"NO!!K	0D0D0F/G"HI Q002KK$$'@	%JK 30   !!$>wi"HI !!$:7)2c!fX"NO!!K	0D0D0F/G"HI !!#002KK$$'@	%JK 3sL   >G J. 0I&AI!!I&&I) )AJ+.0L>AL99L>>M ANc                    |j                         rt        d|       |j                         rt        d|       | j                  ||       |j                         rt        d|       y)zBProcess a single user with timeout checking for background threadsr   N)is_setr   r   )r)   r   rc   r   s       r   r   z)Command._process_single_user_with_timeout   s|     !!=gYGHH !!=gYGHH 	!!'51 !!=gYGHH "r!   c                  %& | j                         s"| j                  j                  d| d| d       t        |      }ddlm}  |       }	 |j                  j                  |      }|j                  xs d}| j                         s!| j                  j                  d| d	|        |d
k7  r|s|rd
|_        t        j                         |_        |j                  ddg       d| d| d}| j                         sg| j                  j                  |       | j                  j                  |       n0| j                         s| j                  j                  d| d       y| j                  j                  d|        t"        j                  j%                  |d      j'                  d      j)                         }	|	r)| j                  j                  d|	j*                          n| j                  j!                  d|        |	|	j,                  rd|	j,                  vr%| j                  j                  d| d       t/        j0                         5  t2        j                  j%                  |      j5                         d   }
| j                  j                  d|
 d|         |       }	 |j                  j7                         j                  |      }|s|j                  d
k(  rSd|_        t        j                         |_        |j                  dd g       | j                  j                  d!| d"       ddd       y|	j,                  j                  di       }|j                  d$      }|j                  d%      }||#t/        j0                         5  t2        j                  j%                  |      j5                          t"        j                  j%                  |&      j;                  |	j*                        j=                  ddddt        j                         '        |       }	 |j                  j7                         j                  |      }|s|j                  d
k(  r4d|_        t        j                         |_        |j                  dd g       ddd       y| j                  j                  d(|        t"        j                  j%                  |&      j;                  |	j*                        }g }|j?                         }| j                  j                  d)| d*|        |dkD  r"| j                  j                  d+| d,| d-       d}d}tA        |d.      D ]  \  }}	 |j,                  r|j,                  j                  d      r|j,                  d   }|j                  d$      }|j                  d%      }|||jC                  |j*                  ||f       tE        ||||      }|j                  d/g       }|j                  d0g       }|jG                          |r|nd|_$        |r|nd|_%        tM        |      |_'        tM        |      |_(        t        j                         |_)        |j                  g d'       |d.z  }|d1kD  r|d1z  dk(  rd2| d3| d4}| j                  j                  |       | j                  j                  |       nb| j                  j!                  d5|j*                   d6| d7|        |d.z  }n.| j                  j!                  d5|j*                   d8       |d.z  } | j                  j                  d=| d>| d?       |D cg c]
  \  }}}||f }}}}g }t_        ||      D ]R  \  %&ta        %fd@|D              } ta        &fdA|D              }!|jC                  d%&dBdCdD|gdEdCdD| gdFdCdD|!ggdG       T tc        ||      D ]R  \  %&ta        %fdH|D              } ta        &fdI|D              }!|jC                  d.%&dBdCdD|gdEdCdD| gdFdCdD|!ggdG       T | j                  j                  dJ|        t/        j0                         5  t2        j                  j%                  |      j5                         d   }
| j                  j                  d|
 dK|        g }"|D ]B  }#|#dL   dk(  rdMndN}$|"jC                  t3        ||#dE   |#dF   |$|#j                  dO      P             D |"rJt2        j                  je                  |"       | j                  j                  dQtM        |"       dR|        n| j                  j                  dS|         |       }	 |j                  j7                         j                  |      }|s|j                  d
k(  rSd|_        t        j                         |_        |j                  dd g       | j                  j                  dT| dU       ddd       tg        j                  |dV         xs dd
k(  r7tg        jh                  |dV   d       | j                  j                  dW|        | j                  j                  d| dX       y# |j                  $ r2 | j                         s| j                  j!                  d| d       Y yw xY w# |j                  $ r# | j                  j!                  d| d#       Y w xY w# 1 sw Y   yxY w# |j                  $ r Y w xY w# 1 sw Y   yxY w# tT        $ r}d9|j*                   d:tW        |       }| j                  j                  |       | j                  jY                  d;|j*                   d:tW        |              | j                  jY                  d5|j*                   d<t[        j\                                 |d.z  }Y d}~d}~ww xY wc c}}}w # |j                  $ r# | j                  j!                  d| d#       Y  w xY w# 1 sw Y   &xY w)Yz(Internal method to process a single userrw   z	 (force: rr   r   r   )r   idlezUser z current state: 
processingr{   group_relations_started_atr}   zForcing recalculation for user z (state was: zSkipping user z  - not processing and not forcedNz not found in databasez#Loading owner BaZi record for user T)created_by_idownerz-created_atzFound owner BaZi record: z$No owner BaZi record found for user dayz+ has no valid BaZi data, clearing relations)owner_user_idzDeleted z group relations for user 	completedgroup_relations_updated_atzMarked user z as completed (no data)z! not found when marking completedgodearth)r   )relation_goodrelation_badrelation_good_countrelation_bad_countrelation_updated_atz1Starting pairwise relation calculations for user ru   z persons to process for user z  Processing z persons for user z...rv   goodbad
   z    Processed rx   z persons...zPerson z missing god/earth data: g=z, e=z  missing bazi_result or day datau       ⚠️  Skipped person ry   zError processing person z error traceback: zPerson processing completed: z processed, z skippedc              3  4   K   | ]  \  }}|k(  s|  y wr%   r   rO   pidro   p1_ids      r   rQ   z/Command._process_single_user.<locals>.<genexpr>       DmFCse|am   c              3  4   K   | ]  \  }}|k(  s|  y wr%   r   rO   r   ro   p2_ids      r   rQ   z/Command._process_single_user.<locals>.<genexpr>  r   r   odro   p1p2)tr   r   byc              3  4   K   | ]  \  }}|k(  s|  y wr%   r   r   s      r   rQ   z/Command._process_single_user.<locals>.<genexpr>  r   r   c              3  4   K   | ]  \  }}|k(  s|  y wr%   r   r   s      r   rQ   z/Command._process_single_user.<locals>.<genexpr>  r   r   z0Persisting group relations to database for user z# existing group relations for user r   sanhesanxingr   )r   
person1_id
person2_idrelation_typer   zCreated z new group relations for user z"No group relations found for user zSuccessfully marked user z as completedr   z*Updated cache state to completed for user z" processing completed successfully)5r?   r9   rE   r    r   r   r   rf   r{   r   r   r   r   r   r   DoesNotExistwarning
BaziPersonr   order_byfirstr   bazi_resultr	   atomicr   deleteselect_for_updater   excludeupdater   r   appendr   refresh_from_dbr   r   lenr   r   r   ri   rk   rj   rl   rm   r   nextr   bulk_creater   r   )'r)   r   rc   r   r   r   usrr   	force_msgr   deleted_count	owner_dayowner_gowner_e
persons_qspersonstotal_personsprocessed_countskipped_countr   pr   gro   resultgood_reasonsbad_reasonsprogress_msgr   r   group_personsr   e1e2bulkitemrel_typer   r   s'                                        @@r   r   zCommand._process_single_user  so   ((*KK/y	%JK7# 	7	,,""g".C--7E,,.  5	1A%!IJ$U0<C-5:YY[C2HH,CEa+bHc"A'-X]W^^_ `I446)))4((3446((>'Bb)cd 	>wiHI%%G4%HXm$UW 	 KK8
CDKK"Fwi PQ= 1 1U%BSBS5SKKuWI-XYZ##% - 5 5 < <7 < S Z Z \]^ _  8M?:TU\T]!^_ &'\,,88:>>'>JC 9 9\ I4?19>60GIe/fg((<y@W)XY &  %%))%4	--&--(?go##%%%,,7,CJJL"")))@HHEHHHU\\"&T()a(-		 ]  &',,88:>>'>JC 9 9\ I4?19>60GIe/fg &$  	LWIVW''..W.EMMQVQYQYMZ
.0"((*6-0MgYWX1KKm_<NwiWZ[\j!,DAq,==Q]]%6%6u%=--.CA(A}a|4 "/wA!F'-zz&"'=&,jj&; ))+:F,D8C03L0A-/2;/?,05		- .  (1,(2-!b&A+-;A3ak+ZL KK--l; KK,,\:++gaddV;VWXVYY]^_]`,ab%*KK'''!$$7W(XY!Q&MM -^ 	88IVcUddlmn KR/R'YS!Qa'/R ! 8OLE5DmDDBDmDDBNNS#w/$S"1EcSVXZG[\	 	 P :'=QLE5DmDDBDmDDBNNS#w/$S"1EcSVXZG[\	  R 	KG9UV!)1188w8OVVXYZ[MKKx6YZaYbcdD&*3i1n7)M")#Dz#Dz"*xx~    %%11$7  8CI;6TU\T]!^_  #EgY!OP "#DXll446::g:FC55E0;C-5:YY[C2HH,CEa+bHcKK$$'@	%WX9 "D IId7m$.<?IId7m[1KKI'ST5	)KLMG    	,,.##eG94J$KL	F (( \KK''%y8Y(Z[\ &  0 (( ! &$ j  9!$$r#a&J	!!),!!$<QTTF"SVH"MN!!GADD61CIDXDXDZC["\]" 0Sv $$ X##eG94U$VWX; "!s   Dj$ Al8Bk(&Bl?=A/l)?Gmp
Dq
Bp$>k%$k%(.lllll&)l<8l?;l<<l??m	pB,pp.qq
qq

q)r^   r   returnNone)rc   bool)r   r]   rc   r  )r   r]   rc   r  r   zthreading.Event)__name__
__module____qualname__rX   r'   r(   r?   r`   rp   rg   rh   r   r   __classcell__)r,   s   @r   r#   r#   %   s@    jD+dZ>
l>05tnGLRI(aNr!   r#   )r   r]   )!
__future__r   r2   r6   rl   typingr   r   django.core.cacher   django.core.management.baser   r   	django.dbr	   django.utilsr
   r   django.confr   r   r   bazi.modelsr   r   iching.utils.bazi_relationsr   r   r   bazi.models_groupr   r    r#   r   r!   r   <module>r     sM    " 	    # B ! *   . , 
 ,
LNk LNr!   