
    P1i-              	          d dl mZm Z mZ d dlmZ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 d d	lmZmZmZ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jM                  e%jN                  jQ                         D  cg c]  \  } }|  d|  c}}       Z)dZ*e*dz   e)z   Z+deeef   fdZ,de-dedz  fdZ.dedefdZ/ G d de      Z0yc c}} w )    )datedatetime	timedelta)DictListTuple)timezone)APIView)Response)IsAuthenticated)SessionAuthentication)JWTAuthentication)extend_schemaOpenApiParameterOpenApiTypesOpenApiExampleinline_serializer)serializers)Person)bz)get_month_reasons_cached)bzshagodz, z: u&  
Return compact good-day flags for a date range.

Compact response schema:
- user: { person_id?, day_stem, day_branch, source }
- range: { start, end, timezone }
- days: [ { date, day:{g,e}, month:{e}, is_good, reasons } ]
- shagod: { index -> short Chinese name }

reasons entries are compact:
- Relationship: { t: 'r', c: <int>, by: [[who,pillar,component,index], ...] }
  where c indices are:
    0: 六合, 1: 半三合, 3: 六冲, 6: 三合 (full triad)
    Note: 六冲 (index 3) is a clash relationship displayed as black badges in the UI
- Sha god:     { t: 's', i: <int>, by: [[who,pillar,component,index], ...] }

Abbreviations: who = 'u' (user) | 'd' (date); pillar = 'd' (day) | 'm' (month);
component = 'g' (stem) | 'e' (branch); index = stem/branch index.

Sha God index mapping (i -> name):

returnc                 h   t        j                  t        j                        j	                         }t        |j                  |j                  d      }|j                  dk(  rt        |j                  dz   dd      }n$t        |j                  |j                  dz   d      }|t        d      z
  }||fS )N      days)	r   nowbzugMYTimezoner   dt_dateyearmonthr   )now_tztoday_tzstart
next_firstends        5/home/cursorai/projects/iching/api/views_good_days.py_month_start_endr,   .   s     ||COO,113HHMM8>>15E{{bUZZ!^Q2
UZZq!<

ya(
(C#:    sNc                 j    	 t        j                  | d      j                         S # t        $ r Y y w xY w)N%Y-%m-%d)r   strptimer   	Exception)r.   s    r+   _parse_dater3   ;   s5      J/4466 s   #& 	22r(   r*   c              #      K   | j                   | j                  }}	 t        ||d      }||kD  ry | |dk(  r|dz  }d}n|dz  }*w)Nr   r   )r$   r%   r#   )r(   r*   ymfirsts        r+   _month_iterr8   B   sZ     ::u{{qA
1a 3;7FAAFA s   AAc                      e Zd ZeegZegZ ee	 e
dej                  e
j                  dd       e
dej                  e
j                  dd       e
dej                  e
j                  dd       e
d	ej                  e
j                  dd
       e
dej                  e
j                  dd      g eddddddddddddddddidddg dg d gd!dd"g dg d gd!d#d$g d%g d gd&gd'gd()      g ed* ed+ ej&                  dd,       ej&                          ej&                          ej(                  dd-g.      d/       ed0 ej*                          ej*                          ej,                         d/       ej.                   ed1 ej*                          ed2 ej&                          ej&                         d/       ed3d ej&                         i/       ej0                          ej.                   ej2                         d45      d'/      6       ej2                   ej,                         d75      d8/      9      d:        Zy;)<GoodDaysAPIViewr(   Fz?Start date YYYY-MM-DD (defaults to 1st of current month, UTC+8))nametypelocationrequireddescriptionr*   zBEnd date YYYY-MM-DD (defaults to last day of current month, UTC+8)	person_idzLUse a specific Person owned by the user. If omitted, uses owner=True record.dobzQOptional. Use provided birth date (YYYY-MM-DD) instead of Person to compute BaZi.timezaOptional. HH:MM in 24h (UTC+8). Used with dob to determine day pillar boundary (23:00 crossover).zExample response{   r      personr@   day_stem
day_branchsourcez
2025-08-01z
2025-08-31+08:00r(   r*   r	   z
2025-08-03      gerP      Tr)udrP   rD   )rT   rT   rP   rM   )tcby   r.      )rS   rT   rO   r   )rU   irW   r   dayr%   is_goodreasons)userranger   )valueGoodDaysResponseGoodDaysUser)r>   
allow_nullparams)choices)r;   fieldsGoodDaysRangeGoodDayItem	PillarDayPillarMonthz#Compact reasons as documented above)child	help_text)rl   z,Mapping: sha-god index -> short Chinese namer_   r`   r   shagod)r?   
parametersexamples	responsesc           	      	   |j                   j                  d      }|j                   j                  d      }|r0|r.t        |      }t        |      }|r|r||k  r+t        ddid      S t	        t
        j                        \  }}d d d d d}|j                   j                  d      }|j                   j                  d	      }|r	 t        j                  |d
      }	|r,|j                  d      D 
cg c]  }
t        |
       c}
\  }}nd\  }}t        |	j                  |	j                  |	j                  ||dt
        j                        }t        j                  |j                  |j                  |j                  |j                  |j                   |j"                        }|d   d   }|d   d   }|j%                  ||dd       n|j                   j                  d      }d }|r5	 t(        j*                  j                  t        |      |j,                        }|Ht(        j*                  j3                  |j,                  d      j5                  d      j7                         }||j8                  rd|j8                  vrt        d g d      S 	 |j8                  d   d   }|j8                  d   d   }|j%                  |j:                  ||dd       g }|}t=        t?        ||            }i }|D ]7  }|j                  d|j                  d}tA        |||d        \  }}||f||<   9 |}||k  r|j                  d|j                  d}|j                  |i i f      \  }}|jC                         }|j                  |      xs g |j                  |      xs g z   }t        jD                  |j                  |j                  |j                  d!d"d"      }|jG                  ||d   d   |d   d   d#d|d$   d   itI        |      |d%       |tK        d&'      z  }||k  rtL        jN                  }t        ||jC                         |jC                         d(d)||d*      S c c}
w # t&        $ r t        ddid      cY S w xY w# t(        j.                  t0        f$ r d }Y w xY w# t&        $ r t        d g d      cY S w xY w)+Nr(   r*   errorzInvalid date rangei  )statusrF   rA   rB   r0   :)r   r   r   )tzinfor\   rO   rP   re   )rG   rH   rI   z:Invalid dob/time format. dob=YYYY-MM-DD, time=HH:MM (24h).r@   )pk
created_byT)ry   ownerz-created_at)r_   r   godearthrE   04d02d)ttl_seconds   ;   rN   r%   r[   r   r   rJ   rK   rn   )(query_paramsgetr3   r   r,   r!   r"   r   r1   splitintr$   r%   r\   getDateTimeGodEarthStemhourminutesecondupdater2   r   objectsr_   DoesNotExist
ValueErrorfilterorder_byr7   bazi_resultidlistr8   r   	isoformatgetCalendar10kGodEarthStemappendboolr   sggShagodNames) selfrequeststart_param	end_paramr(   r*   	user_info	dob_param
time_paramdob_datexhhmmdt_localb
user_day_g
user_day_er@   rE   resultscurrentmonthsmonthly_cachemonth_first	month_str
branch_mapstem_mapr\   keyr^   bazishagod_index_maps                                    r+   r   zGoodDaysAPIView.getT   s   F **..w7((,,U3	9,Ei(CsU{*> ?LL)#//:JE3 #'DX\]	((,,U3	))--f5
u#,,Y
C.8.>.>s.CD.Cc!f.CDFB!FB#HMM8>>8<<QSUWYZcfcrcrs//x~~x||]e]j]jltl{l{  ~F  ~M  ~M  NuXc]
uXc]
  j
^f!gh
  ,,00=IF"#^^//3y>gll/[F ~NN))W\\)NXm,UW  ~V%7%75HZHZ;Zr :;;<#//6u=
#//6w?
 699*\frz{| !k%-. Y[!K&++C01B1B30GHI#;J$ J )3H'=M)$ " Sj88C.38I#0#4#4YR#I J--/C!~~c*0bX\\#5F5L"MG 11#((CIIswwPRTVXZ[DNN!%eS!1UC8HI!4=#56#G}& 9!$$C% Sj* ??!"__.==? (
  *	
 	
[ E  u*f gpsttu ++Z8 "!F"  <r :;;<sI   +Q, 1Q'CQ, *4R
 $R, 'Q, ,RR
R)(R),SSN)__name__
__module____qualname__r   r   authentication_classesr   permission_classesr   _GOOD_DAYS_DESCRIPTIONr   r   DATEQUERYINTSTRr   r   r   IntegerFieldChoiceField	DateField	CharField	ListFieldBooleanField	DictFieldr    r-   r+   r:   r:   P   s   35FG)**'0A0AL\LbLbmr  AB  C%l.?.?JZJ`J`kp  C  D+L4D4DO_OeOepu  DR  S%l.?.?JZJ`J`kp  R  S&|/?/?JZJ`J`kp  b  c
 "*-1AYab'3LV^_ %1)*#3&)1X'+&)//9Z [&)//9Z [&)//9Z [(

, $#)'%=[%=%=uY]%^$<K$<$<$>&>k&>&>&@"9+"9"98XBV"W	 +(!6!6!6!84{446$9K$9$9$; .--4E& 5 5 5 70kPhP[PhPhPj  rJq|  rJ  rJ  rL  KM   N!2sTlT_TlTlTnNo!p#;;#;#;#=#8;#8#8?T{?T?T?V  cH  $I	5 	 0+//6Kk6K6K6M  ZH  I9 
?@Bo
C@Bo
r-   r:   )1r   r   r#   r   typingr   r   r   django.utilsr	   dj_timezonerest_framework.viewsr
   rest_framework.responser   rest_framework.permissionsr   rest_framework.authenticationr   'rest_framework_simplejwt.authenticationr   drf_spectacular.utilsr   r   r   r   r   rest_frameworkr   bazi.modelsr   iching.utilsr   r!   iching.utils.person_good_daysr   r   r   joinr   items_SHAGOD_DOC_LINES_BASE_DESCRIPTIONr   r,   strr3   r8   r:   )kvs   00r+   <module>r      s    9 9 $ $ 0 ( , 6 ? E r r &  " B ' IIr7L7L7NO7Ntq!!Bqc{7NOP  , +T14EE 
gw&6 7 
3 7T> w W t
g t
{ Ps   C
