U
    c5h/                  	   @   s   d Z ddlZddlZddlmZmZmZ ddlZddlmZ ddl	Z	ddl
Z
ddlZddlmZmZmZ e
je	je	je	je ddlmZ G dd dZd	d
 Zedkre  dS )z8
Enhanced ActivityWatch Sync with Proper Categorization
    N)datetime	timedeltatimezone)RealDictCursor)DictListTuple)ActivityCategorizerc                   @   s   e Zd ZeedddZdeee dddZeeedd	d
Z	eeedddZ
ee edddZee edddZdd ZdedddZdS )EnhancedActivityWatchSync)developer_name	api_tokenc                 C   s^   || _ || _d| _d| _t | _tddtddtddtd	d
tddd| _d S )Nzhttp://localhost:5600z/https://api-timesheet.firsteconomy.com/api/syncZDB_HOSTZ	localhostZDB_NAMEZ	timesheetZDB_USERZpostgresZDB_PASSWORDZyour_passwordZDB_PORTZ5432)ZhostZdatabaseuserZpasswordZport)	r   r   aw_urlapi_urlr	   categorizerosgetenv	db_config)selfr   r    r   ./sync_scripts/enhanced_sync.py__init__   s    




z"EnhancedActivityWatchSync.__init__   )minutes_backreturnc                 C   s  z^t j| j ddd}|jdkr2td g W S | }tdt| d tt	j
}|t|d }g }| D ]\}}d	| krqtz| j d
| d}	| | dd}
t j|	|
dd}|jdkrW qt| }td| dt| d |D ]}| ||}|r|| qW qt tk
rX } z td| d|  W Y qtW 5 d}~X Y qtX qt|W S  tk
r } ztd|  g  W Y S d}~X Y nX dS )z$Get activity data from ActivityWatchz/api/0/buckets
   )timeout   u&   ❌ Could not connect to ActivityWatchu   📦 Found z ActivityWatch bucketsZminutesZafkz/api/0/buckets/z/events  )startendlimit)paramsr   z  - : z eventsu   ⚠️  Error processing Nu&   ❌ Error getting ActivityWatch data: )requestsgetr   status_codeprintjsonlenr   nowr   utcr   itemslower	isoformatprocess_eventappend	Exception)r   r   Zbuckets_responseZbucketsZend_timeZ
start_timeZall_activitiesbucket_nameZbucket_infoZ
events_urlr#   Zevents_responseZeventseventactivityer   r   r   get_activitywatch_data%   sF    

z0EnhancedActivityWatchSync.get_activitywatch_data)r4   r3   r   c                 C   sH  | di }| dd}| dd}|dk r0dS | dd	}| d
| dd}d|krZn$d|kr~| dd}|r~|d	kr~|}|r|dd}|dd}|dd}|dd}| j||}	zt|dd}
W n   ttj}
Y nX | j	||dd | dd| ddt
|d |
|	d | |||	d |ttjdS )z$Process a single ActivityWatch eventdatadurationr   	timestamp    NtitleZUntitledZappZapplicationZUnknownZwindowZweburlz - Google Chromez - Mozilla Firefoxz - Microsoft Edgez - Visual Studio CodeZz+00:00i  filer   categoryZsubcategory)Zdeveloper_idZapplication_namewindow_titler>   Z	file_pathr9   r:   rA   Zproject_nameZproject_typer3   Z
created_at)r&   replacer   Zget_detailed_categoryr   Zfromisoformatr+   r   r,   r   intextract_project_name)r   r4   r3   r8   r9   r:   rB   app_namer>   Zcategory_infoZparsed_timestampr   r   r   r0   \   sH    





z'EnhancedActivityWatchSync.process_event)rB   rF   r   c           	         s   ddl }|d|}|r&|d S |d|}|rZt fdddD rZ|d S |d	|}|rt|dS |d
|}|r|dS |d|}|r|dS dS )z-Try to extract project name from window titler   Nz2 - ([^-]+) - (?:Visual Studio Code|VS Code|Cursor)   u   ^([^–]+) – c                 3   s   | ]}|   kV  qd S )N)r.   ).0ZiderF   r   r   	<genexpr>   s     zAEnhancedActivityWatchSync.extract_project_name.<locals>.<genexpr>)ZintellijZpycharmZwebstormz\\([^\\]+)\\\.gitzgithub\.com/[^/]+/([^/\s]+)z\\([^\\]+)\\[^\\]+\.[a-z]+$Zgeneral)researchgroupstripany)	r   rB   rF   rK   Zvscode_matchZjetbrains_matchZ	git_matchZ
repo_matchZfolder_matchr   rI   r   rE      s"    


z.EnhancedActivityWatchSync.extract_project_name)
activitiesr   c           	      C   s   |sdS d}zt jf | j}| }d}|D ]h}z*dd | D }||| |d7 }W q, tk
r } ztd|  W Y q,W 5 d}~X Y q,X q,|  |	  |	  td| d	 W n0 tk
r } ztd
|  W 5 d}~X Y nX |S )zSave activities to databaser   a  
                INSERT INTO activity_records (
                    developer_id, application_name, window_title,
                    url, file_path, duration, timestamp,
                    category, project_name, project_type,
                    created_at
                ) VALUES (
                    %(developer_id)s, %(application_name)s, %(window_title)s,
                    %(url)s, %(file_path)s, %(duration)s, %(timestamp)s,
                    %(category)s, %(project_name)s, %(project_type)s,
                    %(created_at)s
                )
                ON CONFLICT (developer_id, timestamp, application_name, window_title) 
                DO NOTHING
            c                 S   s   i | ]\}}|d kr||qS )r3   r   )rH   kvr   r   r   
<dictcomp>   s       z>EnhancedActivityWatchSync.save_to_database.<locals>.<dictcomp>rG   u   ⚠️  Error saving activity: Nu
   ✅ Saved z activities to databaseu   ❌ Database error: )
psycopg2Zconnectr   Zcursorr-   Zexecuter2   r(   Zcommitclose)	r   rP   Zsaved_countZconnZcurZinsert_queryr5   Zactivity_datar6   r   r   r   save_to_database   s,     z*EnhancedActivityWatchSync.save_to_databasec              
   C   s   |sdS z| j | j|ttj d}tj| j	|ddidd}|j
dkr| }|drvtd	t| d
 W dS td|dd  ntd|j
  W n0 tk
r } ztd|  W 5 d}~X Y nX dS )zSend activities to API endpointT)nametokenr8   r:   zContent-Typezapplication/json   )r)   Zheadersr   r   successu	   ✅ Sent z activities to APIu   ❌ API error: errorzUnknown erroru   ❌ API returned status u   ❌ Error sending to API: NF)r   r   r   r+   r   r,   r/   r%   Zpostr   r'   r)   r&   r(   r*   r2   )r   rP   ZpayloadZresponseresultr6   r   r   r   send_to_api   s0    

 z%EnhancedActivityWatchSync.send_to_apic                 C   s   t d| j d |  }|rt dt| d i }|D ] }|d }||dd ||< q:t d | D ]\}}t d	| d
| d ql| |}| | nt d dS )zPerform a single syncu%   
🔄 Syncing ActivityWatch data for z...u   📊 Processed z activitiesrA   r   rG   u   📈 Category breakdown:z   - r$   u   📝 No new activities to syncN)r(   r   r7   r*   r&   r-   rV   r]   )r   rP   
categoriesr5   catcountZsavedr   r   r   	sync_once  s    
z#EnhancedActivityWatchSync.sync_oncer<   )interval_minutesc                 C   s   t d| d t d t d zJ|   t t|d }t d|d  t d t|d  q"W n tk
r   t d	 Y nX d
S )zRun continuous syncu$   🚀 Starting continuous sync every z minutesu   ⏹️  Press Ctrl+C to stopz2--------------------------------------------------r   u   
⏳ Next sync at z%H:%M:%S<   u   
🛑 Sync stopped by userN)	r(   ra   r   r+   r   strftimetimesleepKeyboardInterrupt)r   rb   Z	next_syncr   r   r   continuous_sync#  s    z)EnhancedActivityWatchSync.continuous_syncN)r   )r<   )__name__
__module____qualname__strr   rD   r   r   r7   r0   rE   rV   boolr]   ra   rh   r   r   r   r   r
      s   78 /#r
   c                  C   s   d} d}t | |}|  d S )NZmrunaliZYOUR_TOKEN_HERE)r
   rh   )ZDEVELOPER_NAMEZ	API_TOKENsyncr   r   r   main6  s    
ro   __main__)__doc__r%   r)   r   r   r   rT   Zpsycopg2.extrasr   r   sysre   typingr   r   r   pathr1   dirnameabspath__file__Zactivity_categorizerr	   r
   ro   ri   r   r   r   r   <module>   s"   $  $