U
    %hH                     @   sn   d Z 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mZ ddlZddlmZ G dd	 d	ZdS )
zF
Realistic Hours Calculator - More accurate working hours calculation
    )datetime	timedeltatimezone)DictListOptional)Session)funcand_N)ActivityWatchClientc                   @   s   e Zd Zdd ZeedddZeedddZe	e
j edd	d
Zeeef edddZeeef edddZeee	e dddZeeeee	e dddZe	e edddZeeeeedddZdS )RealisticHoursCalculatorc                 C   s   dddd| _ d S )Ng      @g       @)lowmediumhigh
thresholds)self r   =/var/www/html/timesheet/backend/realistic_hours_calculator.py__init__   s    z!RealisticHoursCalculator.__init__)hoursreturnc                 C   s`   |dkrdS t |d }|d }|d }|dkr:| dS |dkrL| dS | d| dS dS )z@Convert decimal hours to readable format (e.g., 5.5 -> '5h 30m')r   0h<   mhzh N)int)r   r   total_minutes
hours_partminutes_partr   r   r   format_time_readable   s    

z-RealisticHoursCalculator.format_time_readablec                 C   sP   || j d k rddddddS || j d k r<ddd	d
ddS ddddddS dS )z3Get status color and message based on working hoursr   z#ef4444z#fef2f2zBelow targetu   🔴)statuscolor
backgroundmessageiconr   z#f59e0bz#fffbebzOn tracku   🟡r   z#22c55ez#f0fdf4z
Excellent!u   🟢Nr   )r   r   r   r   r   get_status_info%   s(    	z(RealisticHoursCalculator.get_status_info)
activitiesr   c                 C   s4  |sddi dS i }d}|D ]}|j }|j}||7 }||krLddi d||< || d  |7  < || d  d7  < |j}||| d krd|| d |< || d |  |7  < qd}i }	| D ]X\}}
|
d }|d	 }|d
kr|}||7 }||ddd|	|< q|dkr2|}||7 }||ddd|	|< q|dkr\|}||7 }||ddd|	|< q|dkr| |
d }||d  }|||d  7 }|||| dd|	|< q|dkr| |
d }||d  }|||d  7 }|||| dd|	|< q|d }||d 7 }||ddd|	|< q|d	 |d	 |	dS )z<Calculate realistic working hours based on activity patterns        )working_hourstotal_hours	breakdownr   )
total_timecountappsr,   r-      r.   i  developmentd   zAll coding/development work)r*   r)   
percentagereasondatabasezAll database workproductivityzAll productivity toolsbrowserz!% estimated work-related browsingotherz#% estimated work-related activitiesg?
   zMinimal work-related time)categorydurationapplication_nameitemsanalyze_browser_usageanalyze_other_usage)r   r'   category_datar,   activityr9   r:   app_nameZworking_timer+   dataZcat_timeZ	cat_hoursr)   Zwork_percentager   r   r   !calculate_realistic_working_hours@   s    





	z:RealisticHoursCalculator.calculate_realistic_working_hours)r.   r   c                 C   s   dS )z2Analyze browser usage to determine work percentageU   r   )r   r.   r   r   r   r=      s    z.RealisticHoursCalculator.analyze_browser_usagec                 C   s   ddddg}t | }d}| D ]n\}}d| ksDd| krR||d 7 }q$d	| krl||d
 7 }q$d| kr||d
 7 }q$||d 7 }q$|dkrt|| d S dS )z:Analyze 'other' category apps to determine work percentagezdatagrip64.exezPostman.exezSnippingTool.exezLockApp.exer   datagrippostmang      ?Zsnippingg?lockappg      ?r1   2   )sumvaluesr<   lowerr   )r   r.   Zwork_related_appsr,   Z	work_timeapptimer   r   r   r>      s$    z,RealisticHoursCalculator.analyze_other_usage)
start_dateend_dater   c                 C   s  t  }|jddddd}|jddddd}z|||}W n8 tk
rr } ztd|  g  W Y S d}~X Y nX i }|D ].}|d  }||krg ||< || | q|g }	| }
| }|
|kr|
|kr||
 }g }|D ]6}td	d
|d |d |d |d d }|| q| |}|d }|d }| 	|}|	|

dt|dt|d| || |t|dkr|| d nddt||d |d |d |d |d |d d nB| 	d}|	|

ddddddd|d |d |d ddi d |
tdd 7 }
q|	S )!z6Calculate daily hours directly from ActivityWatch datar   hourminutesecondmicrosecond   ;   ?B z#Error fetching ActivityWatch data: N	timestampMockActivityr   r9   r:   r;   )r9   r:   r;   rX   r)   r*   %Y-%m-%d   r1   r/   r!   r"   r#   r$   r%   r+   dater)   r*   working_hours_formattedZtotal_hours_formattedproductivity_percentageZactivities_countr!   Zstatus_colorZstatus_backgroundZstatus_messageZstatus_iconr+   r(   r   No activity   ⚪days)r   replaceget_activity_data	Exceptionprintr]   appendtyperC   r&   strftimeroundr    lenr   )r   rN   rO   	aw_clientactivity_dataedaily_activitiesr@   activity_dateresultcurrent_dateend_date_onlyday_activitiesmock_activitiesmock_activity
hours_datar)   r*   status_infor   r   r   (calculate_daily_hours_from_activitywatch   s    






zARealisticHoursCalculator.calculate_daily_hours_from_activitywatch)dbuser_idrN   rO   r   c                 C   s  |j ddddd}|j ddddd}|tjttjj|ktjj|ktjj|ktjj	 
 }i }|D ],}|j }||krg ||< || | qpg }	| }
| }|
|kr|
|krp||
 }| |}|d }|d }| |}|	|
dt|d	t|d	| || |t|dkr6|| d
 nddt||d |d |d |d |d |d d nB| d}|	|
ddddddd|d |d |d ddi d |
tdd7 }
q|	S )z.Calculate realistic working hours for each dayr   rP   rU   rV   rW   r)   r*   rZ   r[   r1   r/   r!   r"   r#   r$   r%   r+   r\   r(   r   r`   ra   rb   )rd   querymodelsActivityRecordfilterr
   r|   rX   order_byascallr]   rh   rC   r&   rj   rk   r    rl   r   )r   r{   r|   rN   rO   r'   rp   r@   rq   rr   rs   rt   ru   rx   r)   r*   ry   r   r   r   calculate_daily_hours1  sx    



	






z.RealisticHoursCalculator.calculate_daily_hours)
daily_datar   c              
   C   s   |sdddddddddS t dd |D }tdd |D }td	d |D }td
d |D }tdd |D }|rt|dd dnd}t|||rt|t| dndt|d||||r|d |d dnddS )z!Calculate summary from daily datar   r(   N)Z
total_daysworking_daysZavg_working_hourstotal_working_hoursdays_above_targetdays_on_trackdays_below_targetbest_dayc                 s   s   | ]}|d  V  qdS )r)   Nr   .0dayr   r   r   	<genexpr>  s     z7RealisticHoursCalculator.get_summary.<locals>.<genexpr>c                 S   s   g | ]}|d  dkr|qS )r)   r   r   r   r   r   r   
<listcomp>  s      z8RealisticHoursCalculator.get_summary.<locals>.<listcomp>c                 S   s   g | ]}|d  dkr|qS )r!   r   r   r   r   r   r   r     s      c                 S   s   g | ]}|d  dkr|qS )r!   r   r   r   r   r   r   r     s      c                 S   s   g | ]}|d  dkr|qS )r!   r   r   r   r   r   r   r     s      c                 S   s   | d S )Nr)   r   )xr   r   r   <lambda>      z6RealisticHoursCalculator.get_summary.<locals>.<lambda>)keyr[   r]   r)   )r]   r   )rI   rl   maxrk   )r   r   r   r   r   r   r   r   r   r   r   get_summary  s<    z$RealisticHoursCalculator.get_summaryc                 C   s8   |  ||}| |}||| j|d|dddS )zFGenerate complete realistic daily hours report from ActivityWatch datarZ   )startend)r   summaryr   
date_range)rz   r   r   rj   )r   r{   r|   rN   rO   r   r   r   r   r   calculate_daily_report  s    
z/RealisticHoursCalculator.calculate_daily_reportN)__name__
__module____qualname__r   floatstrr    r   r&   r   r~   r   rC   r   r=   r>   r   rz   r   r   r   r   r   r   r   r   r      s$   u	Y  N%  r   )__doc__r   r   r   typingr   r   r   sqlalchemy.ormr   
sqlalchemyr	   r
   r~   my_activitywatch_clientr   r   r   r   r   r   <module>   s   