
    ei}                        d Z ddlZddlmZmZ ddl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mZmZ dd
lmZ ddlmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$ ddl%m&Z& ddl'm(Z(  ee)          Z* G d d          Z+dS )z
Garmin API client wrapper for health data retrieval.

Supports Garmin Connect China (connect.garmin.cn) with authentication,
data fetching, error handling, and retry logic.
    N)datedatetime)OptionalDictAnyList)Path)Garmin)GarthHTTPError)config)GarminAuthErrorGarminAPIErrorRateLimitError)setup_logger)	StepsDataHeartRateData	SleepData
StressDataBodyBatteryDataSpO2DataRespirationDataHydrationData
FloorsDataIntensityMinutesDataHRVDataRHRDataLifestyleLoggingData)Activity)
WeightDatac            	       .   e Zd ZdZ	 	 	 ddee         dee         dee         ddfdZd dZd d	Z	e
j        d
dedefdZdedee         fdZdedee         fdZdedee         fdZdedee         fdZdedee         fdZdededee         fdZdedee         fdZdedee         fdZ dedee!         fdZ"dedee#         fdZ$dedee%         fdZ&dedee'         fdZ(dedee)         fdZ*dedee+         fdZ,dedee-         fdZ.dS )!GarminHealthClientz:Client for fetching health data from Garmin Connect China.Nemailpasswordtoken_storereturnc                     |pt           j        | _        |pt           j        | _        |pt           j        | _        | j        r| j        st          j                     d| _        d| _	        dS )a(  Initialize Garmin client.

        Args:
            email: Garmin account email (defaults to config.GARMIN_EMAIL)
            password: Garmin account password (defaults to config.GARMIN_PASSWORD)
            token_store: Path to token storage directory (defaults to config.TOKEN_STORE)
        NF)
r   GARMIN_EMAILr"   GARMIN_PASSWORDr#   TOKEN_STOREr$   validate_credentialsclient_authenticated)selfr"   r#   r$   s       6/root/projects/butler/health/services/garmin_client.py__init__zGarminHealthClient.__init__/   si     1f1
 :F$:&<&*<z 	* 	*')))(,#    c                 f   t                               d| j                    	 t          | j        | j        d          | _        | j        dz  }| j        dz  }|                                o|                                }|rt                               d           nt                               d           | j        	                    t          | j                             |sKt                               d	           | j        j                            t          | j                             d| _        t                               d
           dS # t          $ r5}t                               d|            t!          d|           |d}~wt"          $ r}t                               d|            	 | j        	                                 | j        j                            t          | j                             d| _        t                               d           nB# t&          $ r5}t                               d|            t!          d|           |d}~ww xY wY d}~dS d}~wt&          $ r5}t                               d|            t!          d|           |d}~ww xY w)zvAuthenticate with Garmin Connect China.

        Raises:
            GarminAuthError: If authentication fails
        z-Authenticating with Garmin Connect China for T)r"   r#   is_cnzoauth1_token.jsonzoauth2_token.jsonz.Found existing tokens, attempting to load themz9No existing tokens found, will use credential-based login)
tokenstorezSaving tokens for future usez4Successfully authenticated with Garmin Connect ChinazGarmin authentication failed: zAuthentication failed: Nz=Token files not found, retrying with credential-based login: z<Successfully authenticated with credentials and saved tokenszRetry authentication failed: z!Unexpected authentication error: )loggerinfor"   r
   r#   r+   r$   existsdebugloginstrgarthdumpr,   r   errorr   FileNotFoundErrorwarning	Exception)r-   oauth1_token_pathoauth2_token_pathtokens_existeretry_errors         r.   authenticatezGarminHealthClient.authenticateF   s    	PDJPPQQQ1	R j  DK !% 03F F $ 03F F,3355T:K:R:R:T:TL ZMNNNNXYYY KT-=)>)>???   >;<<<!&&s4+;'<'<==="&DKKNOOOOO 	H 	H 	HLL=!==>>>!"?A"?"?@@aG  	` 	` 	`NN^[\^^___	`!!###!&&s4+;'<'<===&*#Z[[[[ ` ` `J[JJKKK%&M&M&MNNT__` \[[[[[  	R 	R 	RLL@Q@@AAA!"Ia"I"IJJPQQ	RsU   D/E 
J00FJ0I.:A+H&%I.&
I%00I  I%%I..J0;0J++J0c                 @    | j         r| j        st          d          dS )zEnsure client is authenticated before making API calls.

        Raises:
            GarminAuthError: If not authenticated
        z4Client not authenticated. Call authenticate() first.N)r,   r+   r   )r-   s    r.   _ensure_authenticatedz(GarminHealthClient._ensure_authenticated   s7     " 	$+ 	!F  	 	r0   )max_retriesrH   c                   t          |          D ]G}	  ||i |c S # t          $ r}|j        dk    rt          d|           |||dz
  k     ri|j        dk    s	|j        dv rUt          j        d|z  z  }t                              d|dz    d| d	| d
| d	           t          j	        |           Y d}~t          d| |j                  |d}~wt          $ rw}||dz
  k     rVt          j        d|z  z  }t                              d|dz    d| d	| d
| d	           t          j	        |           Y d}~.t          d|           |d}~ww xY wt          d| d          )a  Retry API call with exponential backoff.

        Args:
            func: Function to call
            max_retries: Maximum retry attempts
            *args: Positional arguments for func
            **kwargs: Keyword arguments for func

        Returns:
            Result of function call

        Raises:
            GarminAPIError: If all retries fail
            RateLimitError: If rate limit is exceeded
          zAPI rate limit exceeded:    i  )i  rJ      zAPI call failed (attempt /z): z. Retrying in zs...NzAPI call failed: )status_codezUnexpected error (attempt zUnexpected API error: zMax retries (z
) exceeded)ranger   statusr   r   RETRY_DELAY_SECONDSr4   r>   timesleepr   r?   )r-   funcrH   argskwargsattemptrC   delays           r.   _retry_api_callz"GarminHealthClient._retry_api_call   s5   $ [)) "	J "	JG!JtT,V,,,,,! [ [ [8s??()HQ)H)HIIqP [1_,,HOOqx:'='="6!W*EENN3GaK 3 3+ 3 3RS 3 3',3 3 3   Ju%%%HHHH %%<%<%<!(SSSYZZ 
J 
J 
J[1_,,"6!W*EENN3Wq[ 3 3; 3 3ST 3 3',3 3 3   Ju%%%HHHH$%Aa%A%ABBI
J D[DDDEEEs.   
EBC8CEAE>EEtarget_datec           	         |                                   t                              d|            	 |                     | j        j        |                                |                                          }|r(t          |t                    rt          |          dk    rdS |d         }t          ||                    d          |                    d          |                    d          |                    d          |          S # t          $ r  t          $ r(}t                              d	|            Y d}~dS d}~ww xY w)
zFetch daily step data.

        Args:
            target_date: Date to fetch data for

        Returns:
            StepsData model or None if no data available
        zFetching steps data for r   N
totalStepstotalDistancecaloriesstepGoal)r   total_stepstotal_distance_meterscalories_burned	step_goalraw_datazError parsing steps data: )rG   r4   r7   rY   r+   get_daily_steps	isoformat
isinstancelistlenr   getr   r?   r<   r-   rZ   raw_data_listrd   rC   s        r.   fetch_stepszGarminHealthClient.fetch_steps   se    	""$$$===>>>	 00+%%''%%'' M ! 
=$(G(G 3}K]K]abKbKbt$Q'H $LL66&.ll?&C&C (Z 8 8",,z22!     	 	 	 	 	 	LL9a99:::44444	s   A/D $A(D E	!EE	c           
      :   |                                   t                              d|            	 |                     | j        j        |                                          }|sdS t          ||                    d          |                    d          |                    d          |                    d          |                    d          |          S # t          $ r  t          $ r(}t                              d	|            Y d}~dS d}~ww xY w)
zFetch daily heart rate data.

        Args:
            target_date: Date to fetch data for

        Returns:
            HeartRateData model or None if no data available
        zFetching heart rate data for NrestingHeartRateminHeartRatemaxHeartRateaverageHeartRateheartRateZones)r   resting_heart_ratemin_heart_ratemax_heart_rateaverage_heart_rateheart_rate_zonesrd   zError parsing heart rate data: )rG   r4   r7   rY   r+   get_heart_ratesrf   r   rj   r   r?   r<   r-   rZ   rd   rC   s       r.   fetch_heart_ratez#GarminHealthClient.fetch_heart_rate   s9    	""$$$B[BBCCC	+++[-B-B-D-D H  t  #+<<0B#C#C'||N;;'||N;;#+<<0B#C#C!).>!?!?!     	 	 	 	 	 	LL>1>>???44444	s   4C )A4C D2DDc                    |                                   t                              d|            	 |                     | j        j        |                                          }|rd|vrdS |d         }t          ||                    d          |                    d          |                    d          |                    d          |                    d          |                    d	i                               d
i                               d          |                    d          |	  	        S # t          $ r  t          $ r(}t                              d|            Y d}~dS d}~ww xY w)zFetch daily sleep data.

        Args:
            target_date: Date to fetch data for

        Returns:
            SleepData model or None if no data available
        zFetching sleep data for dailySleepDTONsleepTimeSecondsdeepSleepSecondslightSleepSecondsremSleepSecondsawakeSleepSecondssleepScoresoverallvaluesleepLevels)	r   total_sleep_secondsdeep_sleep_secondslight_sleep_secondsrem_sleep_secondsawake_secondssleep_scoresleep_levelsrd   zError parsing sleep data: )rG   r4   r7   rY   r+   get_sleep_datarf   r   rj   r   r?   r<   )r-   rZ   rd   	sleep_dtorC   s        r.   fetch_sleepzGarminHealthClient.fetch_sleep  s    	""$$$===>>>	++*K,A,A,C,C H  h>>t 1I $-MM2D$E$E#,==1C#D#D$-MM2E$F$F"+--0A"B"B'mm,?@@%MM-<<@@BOOSST[\\%\\-88!
 
 
 
  	 	 	 	 	 	LL9a99:::44444	s   8D: -CD: :E6E11E6c                    |                                   t                              d|            	 |                     | j        j        |                                          }|sdS t          ||                    d          |                    d          |                    d          |                    d          |                    d          |                    d          |                    d	          |                    d
          |
  
        S # t          $ r  t          $ r(}t                              d|            Y d}~dS d}~ww xY w)zFetch daily stress data.

        Args:
            target_date: Date to fetch data for

        Returns:
            StressData model or None if no data available
        zFetching stress data for NavgStressLevelmaxStressLevelrestStressDurationactivityStressDurationlowStressDurationmediumStressDurationhighStressDurationstressValuesArray)
r   average_stress_levelmax_stress_levelrest_stress_duration_seconds activity_stress_duration_secondslow_stress_duration_secondsmedium_stress_duration_secondshigh_stress_duration_secondsstress_timelinerd   zError parsing stress data: )rG   r4   r7   rY   r+   get_stress_datarf   r   rj   r   r?   r<   rz   s       r.   fetch_stresszGarminHealthClient.fetch_stress:  sk    	""$$$>>>???	+++[-B-B-D-D H  t %-\\2B%C%C!).>!?!?-5\\:N-O-O19>V1W1W,4LL9L,M,M/7||<R/S/S-5\\:N-O-O (-@ A A!     	 	 	 	 	 	LL:q::;;;44444	s   4D )B0D E.EEc                    |                                   t                              d|            	 |                     | j        j        |                                |                                          }|r(t          |t                    rt          |          dk    rdS |d         }t          ||                    d          |                    d          |                    d          |                    d          |                    d          |                    d	          |
          S # t          $ r  t          $ r(}t                              d|            Y d}~dS d}~ww xY w)zFetch daily Body Battery data.

        Args:
            target_date: Date to fetch data for

        Returns:
            BodyBatteryData model or None if no data available
        zFetching Body Battery data for r   NchargeddrainedhighestBodyBatteryValuelowestBodyBatteryValuemostRecentValuebodyBatteryValuesArray)r   r   r   highest_valuelowest_valuemost_recent_valuetimelinerd   z!Error parsing Body Battery data: )rG   r4   r7   rY   r+   get_body_batteryrf   rg   rh   ri   r   rj   r   r?   r<   rk   s        r.   fetch_body_batteryz%GarminHealthClient.fetch_body_batterya  s    	""$$$D{DDEEE	 00,%%''%%'' M ! 
=$(G(G 3}K]K]abKbKbt$Q'H"  Y// Y//&ll+DEE%\\*BCC"*,,/@"A"A!&>??!	 	 	 	  	 	 	 	 	 	LL@Q@@AAA44444	s   A/D5 $BD5 5E1	E,,E1
start_dateend_datec                 .   |                                   t                              d| d|            	 |                     | j        j        |                                |                                          }|sg S g }|D ]%}	 t          d)i dt          |	                    d                    d|	                    di           	                    dd          d	|	                    d
          dt          j        |	                    d                              dd                                                    dt          j        |	                    d                              dd                    d|	                    d          d|	                    d          d|	                    d          d|	                    d          d|	                    d          d|	                    d          d|	                    d          d|	                    d          d|	                    d           d!|	                    d"          d#|}|                    |           # t          $ r(}t                              d$|            Y d%}~d%}~ww xY wt                              d&t%          |           d'           |S # t&          $ r  t          $ r)}t                              d(|            g cY d%}~S d%}~ww xY w)*zFetch activities within a date range.

        Args:
            start_date: Start date
            end_date: End date

        Returns:
            List of Activity models
        zFetching activities from z to activity_id
activityIdactivity_typeactivityTypetypeKeyunknownactivity_nameactivityNamer   startTimeLocalZ 
start_timeduration_secondsdurationdistance_metersdistanceelevation_gain_meterselevationGainelevation_loss_meterselevationLossr^   rw   	averageHRrv   maxHRaverage_speed_mpsaverageSpeedmax_speed_mpsmaxSpeedaverage_cadence%averageRunningCadenceInStepsPerMinuterd   zFailed to parse activity: NzFetched z activitieszError fetching activities:  )rG   r4   r7   rY   r+   get_activities_by_daterf   r   r9   rj   r   fromisoformatreplacer   appendr?   r>   r5   ri   r   r<   )r-   r   r   activities_data
activitiesraw_activityactivityrC   s           r.   fetch_activitiesz#GarminHealthClient.fetch_activities  s    	""$$$KKKKKLLL0	"222$$&&""$$ O # 	J /  '      $'(8(8(F(F$G$G$G &2&6&6~r&J&J&N&NyZc&d&d&d  '3&6&6~&F&F&F  &3(,,-=>>FFsBOO $&&&  $,#9(,,-=>>FFsBOO$ $ $  *6)9)9*)E)E)E  )5(8(8(D(D(D  /;.>.>.O.O.O  /;.>.>.O.O.O  ".!1!1*!=!=!=  ,8+;+;K+H+H+H   (4'7'7'@'@'@! " +7*:*:>*J*J*J# $ '3&6&6z&B&B&B% & )5(8(89`(a(a(a' ( ".) H, %%h////    NN#C#C#CDDDHHHH KK?3z?????@@@ 	 	 	 	 	 	LL:q::;;;IIIIII	sO   AK ?K G,I53K 5
J'?J"K "J''/K L+L	LLc                    |                                   t                              d|            	 |                     | j        j        |                                |                                          }|rd|vrdS |d         }|sdS |d         }|                    d|          }t          ||                    d          r|                    d          dz  nd|                    d          |                    d	          |                    d
          |                    d          r|                    d          dz  nd|                    d          r|                    d          dz  nd|                    d          |	  	        S # t          $ r  t          $ r(}t                              d|            Y d}~dS d}~ww xY w)zFetch weight data for a specific date.

        Args:
            target_date: Date to fetch data for

        Returns:
            WeightData model or None if no data available
        zFetching weight data for dailyWeightSummariesNr   latestWeightweighti  bmibodyFat	bodyWaterboneMass
muscleMass
sourceType)	r   	weight_kgr   body_fat_percentagebody_water_percentagebone_mass_kgmuscle_mass_kgsourcerd   zError parsing weight data: )rG   r4   r7   rY   r+   get_weigh_insrf   rj   r   r   r?   r<   )r-   rZ   rd   	summariessummarylatest_weightrC   s          r.   fetch_weightzGarminHealthClient.fetch_weight  s    	""$$$>>>???%	++)%%''%%'' H  5XEEt !78I t  lG $KK@@M @M@Q@QRZ@[@[e-++H55<<ae!%%e,,$1$5$5i$@$@&3&7&7&D&DEREVEVWaEbEbl]..z::TAAhlIVIZIZ[gIhIhr}00>>EEnr$((66!
 
 
 
  	 	 	 	 	 	LL:q::;;;44444	s%   AF  
F DF G)GGc           	         |                                   t                              d|            	 |                     | j        j        |                                          }|sdS t          ||                    d          |                    d          |                    d          |                    d          |          S # t          $ r  t          $ r(}t                              d|            Y d}~dS d}~ww xY w)	zFetch SpO2 (blood oxygen saturation) data.

        Args:
            target_date: Date to fetch data for

        Returns:
            SpO2Data model or None if no data available
        zFetching SpO2 data for NaverageSpO2
lowestSpO2
latestSpO2spO2ValueDescriptorsDTOList)r   average_spo2min_spo2max_spo2readingsrd   zError parsing SpO2 data: )rG   r4   r7   rY   r+   get_spo2_datarf   r   rj   r   r?   r<   rz   s       r.   
fetch_spo2zGarminHealthClient.fetch_spo2  s*    	""$$$<{<<===	++);+@+@+B+B H  t  %\\-88!l33!l33!&CDD!     	 	 	 	 	 	LL8Q8899944444	s   4C
 )A C
 
DDDc                    |                                   t                              d|            	 |                     | j        j        |                                          }|sdS t          ||                    d          |                    d          |                    d          |          S # t          $ r  t          $ r(}t                              d|            Y d}~dS d}~ww xY w)zFetch respiration rate data.

        Args:
            target_date: Date to fetch data for

        Returns:
            RespirationData model or None if no data available
        zFetching respiration data for NavgWakingRespirationValuelowestRespirationValuehighestRespirationValue)r   average_respiration_ratemin_respiration_ratemax_respiration_raterd   z Error parsing respiration data: )rG   r4   r7   rY   r+   get_respiration_datarf   r   rj   r   r?   r<   rz   s       r.   fetch_respirationz$GarminHealthClient.fetch_respiration)  s    	""$$$CkCCDDD	++0+2G2G2I2I H  t # )16Q)R)R%-\\2J%K%K%-\\2K%L%L!     	 	 	 	 	 	LL?A??@@@44444	s   4B6 )AB6 6C2
C--C2c                    |                                   t                              d|            	 |                     | j        j        |                                          }|sdS t          ||                    d          |                    d          |          S # t          $ r  t          $ r(}t                              d|            Y d}~dS d}~ww xY w)zFetch hydration tracking data.

        Args:
            target_date: Date to fetch data for

        Returns:
            HydrationData model or None if no data available
        zFetching hydration data for N	valueInMLsweatLossInML)r   total_intake_mlgoal_mlrd   zError parsing hydration data: )rG   r4   r7   rY   r+   get_hydration_datarf   r   rj   r   r?   r<   rz   s       r.   fetch_hydrationz"GarminHealthClient.fetch_hydrationL  s    	""$$$AKAABBB	++.0E0E0G0G H  t !  ([ 9 9 _55!	     	 	 	 	 	 	LL=!==>>>44444	s   4B" )8B" "C6CCc                    |                                   t                              d|            	 |                     | j        j        |                                          }|sdS d}d}|                    dg           }|D ]A}|r=t          |          dk    r*||d         r|d         ndz  }||d         r|d         ndz  }Bt          ||dk    rt          |          nd|dk    rt          |          nd|                    d          |	          S # t          $ r  t          $ r(}t                              d
|            Y d}~dS d}~ww xY w)zFetch floors climbed data.

        Args:
            target_date: Date to fetch data for

        Returns:
            FloorsData model or None if no data available
        zFetching floors data for Nr   floorValuesArray   rL      userFloorsAscendedGoal)r   floors_climbedfloors_descended
floor_goalrd   zError parsing floors data: )rG   r4   r7   rY   r+   
get_floorsrf   rj   ri   r   intr   r?   r<   )r-   rZ   rd   r  r  floor_values_arrayentryrC   s           r.   fetch_floorszGarminHealthClient.fetch_floorsn  s    	""$$$>>>??? 	++&(=(=(?(? H  t N !).@"!E!E , D D DSZZ1__"%(&AeAhhAN$E!H(Ca!C$ 6Dq6H6Hs>222d:JQ:N:N%5!6!6!6TX#<<(@AA!     	 	 	 	 	 	LL:q::;;;44444	s   4D )B.D E,EEc           	         |                                   t                              d|            	 |                     | j        j        |                                          }|sdS |                    d          }|                    d          }d}|
|||dz  z   }t          |||||                    d          |          S # t          $ r  t          $ r(}t                              d|            Y d}~dS d}~ww xY w)	zFetch intensity minutes data.

        Args:
            target_date: Date to fetch data for

        Returns:
            IntensityMinutesData model or None if no data available
        z$Fetching intensity minutes data for NmoderateMinutesvigorousMinutesrL   weekGoal)r   moderate_minutesvigorous_minutestotal_minutesweekly_goalrd   z&Error parsing intensity minutes data: )rG   r4   r7   rY   r+   get_intensity_minutes_datarf   rj   r   r   r?   r<   )r-   rZ   rd   r  r  r  rC   s          r.   fetch_intensity_minutesz*GarminHealthClient.fetch_intensity_minutes  sN    	""$$$IKIIJJJ	++68M8M8O8O H  t  (||,=>>'||,=>> !M+0@0L 03Ca3G G' !1!1+$LL44!     	 	 	 	 	 	LLE!EEFFF44444	s   4C	 )AC	 	DD  Dc                    |                                   t                              d|            	 |                     | j        j        |                                          }|sdS |                    di           }t          |                    d          t                    r|                    di           ni }t          ||                    d          |                    d          |                    d          |          S # t          $ r  t          $ r(}t                              d	|            Y d}~dS d}~ww xY w)
zFetch Heart Rate Variability (HRV) data.

        Args:
            target_date: Date to fetch data for

        Returns:
            HRVData model or None if no data available
        zFetching HRV data for N
hrvSummarybaselinelastNightAvglowUpperrP   )r   	hrv_valuebaseline_hrvrP   rd   zError parsing HRV data: )rG   r4   r7   rY   r+   get_hrv_datarf   rj   rg   dictr   r   r?   r<   )r-   rZ   rd   hrv_summaryr#  rC   s         r.   	fetch_hrvzGarminHealthClient.fetch_hrv  sc    	""$$$;k;;<<<	++(+*?*?*A*A H  t #,,|R88K:D[__U_E`E`bf:g:go{z2666moH %//.99%\\*55"x00!     	 	 	 	 	 	LL7A7788844444	s   4D )B"D E EEc                 x   |                                   t                              d|            	 |                     | j        j        |                                          }|sdS d}|                    di           }|                    di           }|                    dg           }|r<t          |          dk    r)t          |d                             dd                    }t          |||          S # t          $ r  t          $ r(}t                              d	|            Y d}~dS d}~ww xY w)
zFetch resting heart rate data.

        Args:
            target_date: Date to fetch data for

        Returns:
            RHRData model or None
        zFetching RHR data for N
allMetrics
metricsMapWELLNESS_RESTING_HEART_RATEr   r   )r   rt   rd   zError parsing RHR data: )rG   r4   r7   rY   r+   get_rhr_dayrf   rj   ri   r  r   r   r?   r<   )r-   rZ   rd   rt   all_metricsmetrics_maprhr_metricsrC   s           r.   	fetch_rhrzGarminHealthClient.fetch_rhr  sm    	""$$$;k;;<<<	++')>)>)@)@ H  t "&",,|R88K%//,;;K%//*GLLK Is;//!33%(Q););GQ)G)G%H%H" #5!     	 	 	 	 	 	LL7A7788844444	s   4C= )BC= =D9D44D9c           	        
 |                                   t                              d|            	 |                     | j        j        |                                          }|sdS |                    dg           

sdS t          d 
D                       }|sdS dt          dt          t                   f
fd}dt          d	t          dt          fd
} |d          } |d          } |d          }t          d/i d|d|dud|r ||d          ndd|r ||d          ndd|r ||d          ndd|r ||d          ndd|dud|r ||d          ndd|r ||d          ndd|r ||d          ndd|dud |r ||d          ndd!|r ||d          ndd"|r ||d          ndd# |d$          dud% |d&          dud' |d(          dud) |d*          dud+ |d,          dud-|S # t          $ r  t          $ r(}	t                              d.|	            Y d}	~	dS d}	~	ww xY w)0az  Fetch lifestyle logging data from Garmin Lifestyle Logging feature.

        Parses alcohol, caffeine, meal quality/timing, light exercise, and
        intermittent fasting behaviors logged by the user in Garmin Connect.

        Args:
            target_date: Date to fetch data for

        Returns:
            LifestyleLoggingData model or None if no data available
        z$Fetching lifestyle logging data for NdailyLogsReportc              3   H   K   | ]}|                     d           dk    V  dS )	logStatusYESNrj   ).0rC   s     r.   	<genexpr>z=GarminHealthClient.fetch_lifestyle_logging.<locals>.<genexpr>5  s3      GGQQUU;//58GGGGGGr0   namer%   c                 ~    D ]8}|                     d          | k    r|                     d          dk    r|c S 9d S )Nr=  r8  r9  r:  )r=  r  logss     r.   _findz9GarminHealthClient.fetch_lifestyle_logging.<locals>._find:  sN    ! % %Eyy((D00UYY{5K5Ku5T5T$tr0   r  subtypec                     |                      dg           D ]@}|                     d          |k    r%t          |                     dd                    c S AdS )NdetailssubTypeNameamountr   )rj   r  )r  rA  ds      r.   _amountz;GarminHealthClient.fetch_lifestyle_logging.<locals>._amountA  sb    9b11 7 7Auu]++w66"1551#5#566666 7qr0   AlcoholzMorning CaffeinezLate Caffeiner   alcohol_loggedalcohol_beerBEERr   alcohol_wineWINEalcohol_spiritSPIRITalcohol_otherOTHERmorning_caffeine_loggedmorning_caffeine_coffeeCOFFEEmorning_caffeine_teaTEAmorning_caffeine_otherlate_caffeine_loggedlate_caffeine_coffeelate_caffeine_tealate_caffeine_otherlight_exercisezLight Exercisehealthy_mealszHealthy Mealsheavy_mealszHeavy Meals
late_mealsz
Late Mealsintermittent_fastingzIntermittent Fastingrd   z&Error parsing lifestyle logging data: r   )rG   r4   r7   rY   r+   get_lifestyle_logging_datarf   rj   anyr9   r   r)  r  r   r   r?   r<   )r-   rZ   rd   
any_loggedr@  rG  alcohol_entrymorning_caf_entrylate_caf_entryrC   r?  s             @r.   fetch_lifestyle_loggingz*GarminHealthClient.fetch_lifestyle_logging  s    	""$$$IKIIJJJC	++68M8M8O8O H  t<< 1266D t GG$GGGGGJ tC HTN      t c c     "E),,M %&8 9 9"U?33N'    [  -D88 @MSWW]F;;;RS	
 @MSWW]F;;;RS DQWww}h???VW BOUggmW===TU ):(E(E Qb(h0A8(L(L(Lgh K\%bWW->%F%F%Fab O`'fww/@''J'J'Jef &44%?%? KY%_WW^X%F%F%F^_  ES"Y''.%"@"@"@XY!" IW$]GGNG$D$D$D\]#&  %u%566dBB'( $eO44D@@)* "E-00<<+, !5..d::-. &+U+A%B%B$%N%N/0 "1 6  	 	 	 	 	 	LLE!EEFFF44444	s*   4H	 *H	 H	 !E'H	 	II  I)NNN)r%   N)/__name__
__module____qualname____doc__r   r9   r	   r/   rE   rG   r   MAX_RETRIESr  r   rY   r   r   rm   r   r{   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r	  r   r  r   r   r   r+  r   r4  r   rg  r   r0   r.   r!   r!   ,   sF       DD  $"&&*	$ $}$ 3-$ d^	$
 
$ $ $ $.9R 9R 9R 9Rv	 	 	 	 /5.@6F 6F 6F(+6F	6F 6F 6F 6Ft&t &0C & & & &P"D "Xm5L " " " "H&t &0C & & & &P% %*1E % % % %N(d (x7P ( ( ( (T??*.?	h? ? ? ?B1 1*1E 1 1 1 1p#d #x/A # # # #J!T !h6O ! ! ! !F 4  H]4K        D, ,*1E , , , ,\*4 *HEY<Z * * * *X%T %hw.? % % % %N'T 'hw.? ' ' ' 'RR4 RHEY<Z R R R R R Rr0   r!   ),rk  rR   r   r   typingr   r   r   r   pathlibr	   garminconnectr
   	garth.excr   healthr   health.utils.exceptionsr   r   r   health.utils.logging_configr   health.models.daily_metricsr   r   r   r   r   r   r   r   r   r   r   r   r   health.models.activityr   health.models.body_metricsr   rh  r4   r!   r   r0   r.   <module>rw     s     # # # # # # # # , , , , , , , , , , , ,                   $ $ $ $ $ $               
 5 4 4 4 4 4                              , + + + + + 1 1 1 1 1 1	h		~ ~ ~ ~ ~ ~ ~ ~ ~ ~r0   