U
    %hG                     @   s  d dl mZmZmZmZmZmZ d dlmZ d dl	m
Z
mZmZmZ d dlmZmZmZ d dlZd dlZd dlZd dlmZ d dlmZ d dlZe ZeeZG dd	 d	eZeeed
ddZ d-eeedddZ!d.eeee"dddZ#e$dedddedeefeeeedddZ%e&deedddZ'e&dddeefeee ee ed d!d"Z(e&d#ddeefee ee ed$d%d&Z)e&d'd(d) Z*e
ed*d+d,Z+dS )/    )	APIRouterDependsHTTPExceptionstatusHeaderRequest)Session)ListDictOptionalAny)datetimetimezone	timedeltaN)	BaseModel)get_dbc                   @   s.   e Zd ZU eed< eed< eeef ed< dS )ActivityWatchEvent	timestampdurationdataN)__name__
__module____qualname__str__annotations__floatr
   r    r   r   4/var/www/html/timesheet/backend/stateless_webhook.pyr      s   
r   )developer_idprovided_tokenreturnc                 C   sn   t dd}|  d| dt j }t|  }ddl	}t
|dd }|| d}||kS )z;Validate token without database lookup - uses master secretZMASTER_SECRETz'your-master-secret-for-token-generation:r   N0   =)osgetenvr   nowyearhashlibsha256encode	hexdigestbase64bytesfromhexurlsafe_b64encodedecoderstrip)r   r   Zmaster_secretZtoken_inputZ
token_hashr,   token_bytesZexpected_tokenr   r   r   validate_stateless_token   s    r3    )app_namewindow_titler    c                    s   | sdS |    |r|  nd}t fdddD r:dS t fdddD rTd	S t fd
ddD rndS t fdddD rdS t fdddD rdS t fdddD rdS dS )z5Categorize application based on name and window titleotherr4   c                 3   s   | ]}| kV  qd S Nr   .0browserapp_name_lowerr   r   	<genexpr>,   s     z)categorize_application.<locals>.<genexpr>)chromefirefoxsafariedgeZoperaZbraver;   c                 3   s   | ]}| kV  qd S r8   r   r:   Zider<   r   r   r>   0   s     )vscodezvisual studiopycharmintellijZsublimeZatomZvimZemacsz	notepad++cursorcodedevelopmentc                 3   s   | ]}| kV  qd S r8   r   )r:   dbr<   r   r   r>   4   s     )ZdatagripZpgadminmysqlZdbeaverZnavicatZ	sqlserveroracledatabasec                 3   s   | ]}| kV  qd S r8   r   )r:   prodr<   r   r   r>   8   s     )wordexcelZ
powerpointZoutlookZteamsZslackZdiscordZzoomZnotionZobsidianZpostmanproductivityc                 3   s   | ]}| kV  qd S r8   r   )r:   Zmediar<   r   r   r>   <   s     )ZspotifyZyoutubeZvlczmedia playerZnetflixZtwitchentertainmentc                 3   s   | ]}| kV  qd S r8   r   )r:   systemr<   r   r   r>   @   s     )	ZexplorerfinderZterminalcmdZ
powershellztask managerlockZdwmZwinlogonrS   )lowerany)r5   r6   window_title_lowerr   r<   r   categorize_application#   s"    rZ   )r6   r5   urlr    c              	      s   ddd|dd}| s|s|S |r(|  nd | r8|   nd}t fdddD rd| kr| d}t|d	kr|d
  }|d  }||dd|kr| d| n|d| d| d |S nt fdddD r|rzd
dlm} ||}	|	j	dddksdkrH|d|	j
p,d dd|  d |W S dddd d!d"g}
tfd#d|
D r|d$d%|  d |W S W n tk
r   Y nX d| kr| dd
  }||d&d'| d |S |r|	d(dnd)}||d| r| d*|  n|d |S )+z@Extract project information from window title, app name, and URLNWork)project_nameproject_type	file_pathr[   detailed_activityr4   c                 3   s   | ]}| kV  qd S r8   r   rC   r<   r   r   r>   V   s     z'extract_project_info.<locals>.<genexpr>)rG   rD   rH   rE   rF   z -    r      ZDevelopment./zCoding: z in )r]   r^   r_   r`   c                 3   s   | ]}| kV  qd S r8   r   r9   r<   r   r   r>   f   s     )r?   r@   rB   rA   )urlparsezwww.	localhostz	127.0.0.1z
localhost:Z3000zWeb DevelopmentzLocal Development: )r]   r^   r`   z
github.comzstackoverflow.comzdocs.zapi.z
developer.zconsole.c                 3   s   | ]}| kV  qd S r8   r   )r:   Zwork_domain)domainr   r   r>   x   s     zWeb Researchz
Research: zWeb Browsingz
Browsing: z.exeUnknownz: )rW   rX   splitlenstripupdateurllib.parsere   netlocreplaceport	Exception)r6   r5   r[   project_inforY   partsfilenameprojectre   parsedZwork_domainsZ
page_titleZclean_app_namer   )r=   rg   r   extract_project_infoE   sz    


rw   z/activitywatch/webhook.zDeveloper-ID)alias)requestr   authorizationrJ   c                    s  | dstddd|dd }t||sJtd|  tdddtd	|  z|  I d
H }d}| D ]\}}t	|t
rx|D ]t}	t	|	tsq|	d}
|	dd}|	di }|
r|dk rqzt|
dd}|dp|dd}|dd}|dd
}|r$|dkr(W qt||}t|||}ddlm} |||j|k|j|k|j|k|j|k }|rW q||||||d ||||d |d |d d}|| |d7 }W q tk
r } ztd|  W Y qW 5 d
}~X Y qX qqx|  td| d |  d!d"| d#|tt j!" d$W S  tj#k
rn   td%d&dY nR tk
r } z2|$  td'|  td(d)t%| dW 5 d
}~X Y nX d
S )*zCReceive ActivityWatch data via webhook - stateless token validationzBearer i  zInvalid authorization header)status_codedetail rb   zInvalid token for developer zInvalid developer or tokenz$Received ActivityWatch webhook from Nr   r   r   r      Z+00:00appapplicationrh   titler4   r[   ActivityRecordr_   r]   r^   r`   )r   application_namer6   r[   r_   categoryr   r   r]   r^   r`   zError processing event: zSuccessfully processed z activities from Zsuccessz
Processed z activities)r   messager   r   i  zInvalid JSON dataz(Error processing ActivityWatch webhook: i  zProcessing error: )&
startswithr   ri   r3   loggerwarninginfojsonitems
isinstancelistdictgetr   fromisoformatro   rZ   rw   modelsr   queryfilterr   r   r   r   firstaddrq   errorcommitr&   r   utc	isoformatJSONDecodeErrorrollbackr   )ry   r   rz   rJ   tokenZwebhook_dataZprocessed_activitiesZbucket_nameZbucket_dataeventZtimestamp_strr   r   r   r5   r6   r[   r   rr   r   existingZactivity_recorder   r   r   'receive_activitywatch_webhook_stateless   s    










r   z/activitywatch/validate-token)r   r   c                    s"   t | |}| |ttj dS )z1Test endpoint to validate a token (for debugging))r   Ztoken_validr   )r3   r   r&   r   r   r   )r   r   is_validr   r   r   validate_token_endpoint	  s
    
r   z//activitywatch/developer-summary/{developer_id})r   
start_dateend_daterJ   c           	         s   |rt |dd}nt tjjddddd}|rJt |dd}nt tj}ddlm} ||	|j
| k|j|k|j|k }|s| | | dddi i ddS t|}| | | d|dS )	zFGet activity summary for a developer (no user authentication required)r   r   r   hourminutesecondmicrosecondr   startend)total_activities
total_time
categoriesprojects)r   
date_rangesummary)r   r   ro   r&   r   r   r   r   r   r   r   r   allr   process_developer_activities)	r   r   r   rJ   r   r   r   
activitiesr   r   r   r   get_developer_summary_stateless  s,    

r   z/activitywatch/team-summary)r   r   rJ   c                    s  | rt | dd}nt tjjddddd}|rJt |dd}nt tj}ddlm} ddlm	} |
||j|jd|j|k|j|k }g }d}	d}
|D ]\}|sq|
||j|k|j|k|j|k }t|}|	|d 7 }	|
|d	 7 }
|d
d }d
|kr@|d
dd }d| }||||d q| | d|t||	|	d dd|
ddS )z;Get team-wide summary without requiring user authenticationr   r   r   r   )distinctr   Nr   r   _r}   )r   namer   r     .2fh)r   total_time_formattedr   )r   	team_dataZtotal_developersZteam_totals)r   r   ro   r&   r   r   
sqlalchemyr   r   r   r   r   r   isnotr   r   r   r   ri   joinappendr   rj   )r   r   rJ   r   r   r   r   Zdeveloper_idsr   Ztotal_team_timeZtotal_team_activitiesZdev_idr   r   Zdeveloper_nameZ
name_partsr   r   r   get_team_summary_statelessC  sX    	




r   z/healthc                      s   ddt tj ddS )zHealth check endpointZhealthyZ	statelessz:ActivityWatch webhook endpoint is running (stateless mode))r   moder   r   )r   r&   r   r   r   r   r   r   r   health_check  s
    r   )r   r    c              	   C   s  | sddi i dddS t dd | D }i }i }d}| D ]}|jpDd}|jpNd}|j}||krlddd||< || d  d	7  < || d
  |7  < ||krdd|jpdd||< || d  d	7  < || d
  |7  < dddddddd}	|	|d}
|||
 7 }q8|dkr|| d nd}| D ]}|d
 d dd|d< q*| D ]}|d
 d dd|d< qRt| ||d dd||d ddt|d	||dS )z*Process activities into summary statisticsr   )r   r   r   r   working_hoursproductivity_percentagec                 s   s   | ]}|j V  qd S r8   )r   )r:   activityr   r   r   r>     s     z/process_developer_activities.<locals>.<genexpr>r7   rh   )countr   r   rb   r   r\   )r   r   typeg      ?g333333?g      ?g?g        )rI   rM   rQ   r;   r7   rS   rR   d   r   r   r   duration_formatted)r   r   r   r   Zworking_hours_formattedr   r   r   )	sumr   r]   r   r^   r   valuesrj   round)r   r   r   r   r   r   r   ru   r   Zcategory_weightsweightr   Zcategory_dataZproject_datar   r   r   r     s`    	


r   )r4   )N),fastapir   r   r   r   r   r   sqlalchemy.ormr   typingr	   r
   r   r   r   r   r   r   r(   r$   pydanticr   rM   r   loggingrouter	getLoggerr   r   r   r   boolr3   rZ   r   rw   postr   r   r   r   r   r   r   r   r   r   r   <module>   sf    
"R
q+F
	