o
    5)i&                     @   s   d dl mZ d dlmZmZ d dlmZ d dlmZm	Z	m
Z
mZ d dlZd dlZd dlZd dlZd dlmZ edZG dd	 d	Z	dd
ede	e de
fddZdd
ede	e fddZdefddZdS )    )Cache)current_appgwraps)AnyOptionalCallableUnionN)
get_loggercache_servicec                
   @   s   e Zd ZdZdZedd ZededefddZedd	ed
e	de	fddZ
edd	ede	dee defddZed	edefddZedefddZedefddZdS )CacheServicez7Simple and robust caching service for Flask applicationNc              
   C   s,  zjt d|jd  |jdd|jdd|jddd}|d d	kr4|d
|jd
di |d dkrW||jdd|jdd|jdd|jdd t||d| _t d|d   W dS  ty } zt 	dt
|  t|ddid| _t d W Y d}~dS d}~ww )z!Initialize caching with Flask appzCACHE_TYPE 
CACHE_TYPEsimpleCACHE_DEFAULT_TIMEOUTi,  CACHE_KEY_PREFIXqpgs_api)r   r   r   
filesystem	CACHE_DIRNredisCACHE_REDIS_HOST	localhostCACHE_REDIS_PORTi  CACHE_REDIS_DBr   CACHE_REDIS_PASSWORD)r   r   r   r   )configzCache initialized with type: zFailed to initialize cache: z&Falling back to simple in-memory cache)loggerdebugr   getupdater   cacheinfo	Exceptionerrorstrwarning)clsappcache_confige r*   8/var/www/html/oms-prod-mcp/app/services/cache_service.pyinit_app   s:   
zCacheService.init_appprefixreturnc              
   O   s   z*||r
t | ni d}tj|dtd}t|  dd }| d| W S  t	yU } zt
dt|  | dtt|t|  W  Y d}~S d}~ww )z-Generate consistent cache key from parameters)argskwargsT)	sort_keysdefaultN   :zError generating cache key: )sorteditemsjsondumpsr$   hashlibmd5encode	hexdigestr"   r   r%   hash)r&   r-   r/   r0   key_data
key_stringkey_hashr)   r*   r*   r+   get_cache_key;   s   *zCacheService.get_cache_keykeyr2   c              
   C   sf   z| j du r	|W S | j |p|W S  ty2 } ztd| dt|  |W  Y d}~S d}~ww )z(Get value from cache with error handlingNzCache get error for key : )r    r   r"   r   r%   r$   )r&   rB   r2   r)   r*   r*   r+   r   P   s   
zCacheService.getvaluetimeoutc              
   C   sf   z| j du r	W dS | j j|||dW S  ty2 } ztd| dt|  W Y d}~dS d}~ww )z&Set value in cache with error handlingNF)rE   zCache set error for key rC   )r    setr"   r   r%   r$   )r&   rB   rD   rE   r)   r*   r*   r+   rF   [   s   
zCacheService.setc              
   C   s`   z| j du r	W dS | j |W S  ty/ } ztd| dt|  W Y d}~dS d}~ww )zDelete value from cacheNFzCache delete error for key rC   )r    deleter"   r   r%   r$   )r&   rB   r)   r*   r*   r+   rG   f   s   
zCacheService.deletec              
   C   sX   z| j du r	W dS | j  W S  ty+ } ztdt|  W Y d}~dS d}~ww )zClear all cacheNFzCache clear error: )r    clearr"   r   r%   r$   )r&   r)   r*   r*   r+   rH   q   s   
zCacheService.clearc              
   C   s   z| j du rdddW S tjdd}d|tt| j j dW S  tyB } ztd	t|  d
t|dW  Y d}~S d}~ww )zGet cache statisticsNdisablednone)statustyper   unknownactive)rK   rL   backendzError getting cache stats: r#   )rK   r#   )	r    r   r   r   r$   rL   r"   r   r%   )r&   
cache_typer)   r*   r*   r+   	get_stats|   s   
zCacheService.get_statsN)__name__
__module____qualname____doc__r    classmethodr,   r$   rA   r   r   r   intboolrF   rG   rH   dictrQ   r*   r*   r*   r+   r      s"    
'
"


r   cache_key_prefixrE   	conditionc                    s    fdd}|S )z
    Decorator to cache function results

    Args:
        cache_key_prefix: Prefix for cache key
        timeout: Cache timeout in seconds (None = use default)
        condition: Function to determine if result should be cached
    c                    s   t   fdd}|S )Nc               
      s   t jd u r| i |S r| i |s| i |S t j g| R i |}t |}|d ur;td|  |S z| i |}|d urVt || td|  |W S  tys } ztdj	 dt
|   d }~ww )NzCache hit for key: zCache set for key: z Error executing cached function rC   )r   r    rA   r   r   r   rF   r"   r#   rS   r$   )r/   r0   	cache_keycached_resultresultr)   )r[   r\   funcrE   r*   r+   wrapper   s,   

z0cached_query.<locals>.decorator.<locals>.wrapperr   r`   ra   r[   r\   rE   r`   r+   	decorator   s   "zcached_query.<locals>.decoratorr*   )r[   rE   r\   re   r*   rc   r+   cached_query   s   &rf   c                    s    fdd}|S )z:
    Decorator specifically for caching API responses
    c                    s   t   fdd}|S )Nc            	   
      s  t jd u r| i |S ddlm} t|j|jr| nd d}t  j	|}t
d|  t |}t
d|  |d urLt
d|  |S z[| i |}d}t|drj|jd	k}t
d
|j  n*t|ttfryd}t
d nt|trt|dkr|d d	k}t
d|d   |rt || t
d|  |W S  ty } zt
dj	 dt|   d }~ww )Nr   )request)r/   r7   zGenerated cache key: zCache response: zAPI cache hit for: Fstatus_code   zFlask Response status: TzDirect data response received      zTuple response status: zAPI response cached: zError in cached API function rC   )r   r    flaskrg   rZ   r/   is_jsonget_jsonrA   rS   r   r   r   hasattrrh   
isinstancelisttuplelenrF   r"   r#   r$   )	r/   r0   rg   request_paramsr]   cached_responseresponseshould_cacher)   )r[   r`   rE   r*   r+   ra      sH   



z2cache_response.<locals>.decorator.<locals>.wrapperr   rb   r[   rE   rd   r+   re      s   6z!cache_response.<locals>.decoratorr*   )r[   rE   re   r*   rx   r+   cache_response   s   :ry   patternc              
   C   sl   zt jdu r	W dS td|   t  W S  ty5 } ztd|  dt|  W Y d}~dS d}~ww )z(Invalidate cache keys matching a patternNFzInvalidating cache pattern: z!Error invalidating cache pattern rC   )r   r    r   r!   rH   r"   r#   r$   )rz   r)   r*   r*   r+   invalidate_cache_pattern  s   

r{   )NNrR   )flask_cachingr   rl   r   r   	functoolsr   typingr   r   r	   r
   r9   r7   syspickleapp.utils.helpersr   r   r   r$   rX   rf   ry   r{   r*   r*   r*   r+   <module>   s,     
5B