
    Bi;(                        U d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	m
Z
 ddlmZmZmZ ddlmZmZ  ej$                  e      Z G d d	e      Zdad
ed<   ddZddZddZy)a  
Configuration management for Napkin AI API Playground.

Key goals:
- Load settings from environment variables with optional .env support
- Validate with Pydantic Settings, providing clear errors and safe defaults
- Avoid side effects at import time; provide explicit lazy-loading
- Add minimal, non-noisy logging while protecting secrets
- Be thread-safe for concurrent access to the singleton
    )annotationsN)Path)DictOptional)FieldValidationErrorfield_validator)BaseSettingsSettingsConfigDictc                  |   e Zd ZU dZ edddddd      Z ed	d
d      Zded<    eddd      Z	ded<    eddd      Z
ded<    eddd      Zded<    eddd      Zded<    ed d!d"      Zded#<    ed$d%d&d$d'(      Zd)ed*<    e ed+      d,d-      Zd.ed/<    e ed0      d1d2      Zd.ed3<    ed4d5d6d78      Zd)ed9<    ed:d;d<d7=      Zd)ed><    ed?d@dAd7=      Zd)edB<    edCdDdEd7=      ZdFedG<    ed:dHdId7=      Zd)edJ<    edKdLdM      ZdedN<    eddOdP      ZdQedR<    edSdTdUd$dV(      Zd)edW<    eddXdY      ZdQedZ<    edd[d\      ZdQed]<    ed      edfd^              Z ed      edfd_              Z edN      edfd`              Z  ed/d3      edgda              Z!e"dhdb       Z#didcZ$diddZ%ye)jSettingsa  
    Application settings loaded from environment variables.

    Environment variable prefix: NAPKIN_
    Dotenv file: .env (UTF-8)

    Note: Secrets such as api_token must be provided via environment variables
    or supported secret providers. Secrets are never logged.
    z.envzutf-8FNAPKIN_ignoreT)env_fileenv_file_encodingcase_sensitive
env_prefixextravalidate_default.zNapkin API authentication tokenNAPKIN_API_TOKEN)descriptionaliasstr	api_tokenzhttps://api.napkin.aizNapkin API base URLNAPKIN_API_BASE_URL)defaultr   r   api_base_urlv1zAPI versionNAPKIN_API_VERSIONapi_versionzvibrant-strokeszDefault visual style IDNAPKIN_DEFAULT_STYLEdefault_stylesvgz"Default output format (svg or png)NAPKIN_DEFAULT_FORMATdefault_formatzen-USz Default language (BCP 47 format)NAPKIN_DEFAULT_LANGUAGEdefault_language   z"Default number of variations (1-4)NAPKIN_DEFAULT_VARIATIONS   )r   r   r   geleintdefault_variationsz./data/visualsz(Local storage path for generated visualsNAPKIN_STORAGE_PATHr   storage_pathz./data/database/napkin.dbz!SQLite database path for metadataNAPKIN_DATABASE_PATHdatabase_path   z Maximum number of retry attemptsNAPKIN_MAX_RETRIESr   )r   r   r   r+   max_retries   zRequest timeout in secondsNAPKIN_TIMEOUT_SECONDS)r   r   r   gttimeout_seconds<   zRate limit: requests per minuteNAPKIN_RATE_LIMIT_REQUESTSrate_limit_requestsg       @z"Status polling interval in secondsNAPKIN_POLL_INTERVAL_SECONDSfloatpoll_interval_secondszMaximum status polling attemptsNAPKIN_MAX_POLL_ATTEMPTSmax_poll_attemptsINFOzLogging levelNAPKIN_LOG_LEVEL	log_levelzEnable debug modeNAPKIN_DEBUG_MODEbool
debug_mode   z)Maximum concurrent requests in batch modeNAPKIN_BATCH_CONCURRENT_LIMIT
   batch_concurrent_limitzEnable colored terminal outputNAPKIN_USE_COLORS
use_colorszShow progress indicatorsNAPKIN_SHOW_PROGRESSshow_progressc                    |j                         }|j                  d      s|j                  d      st        d      |j                  d      S )z
        Normalize and validate the API base URL.
        - Strips trailing slashes to ensure consistent concatenation.
        - Basic sanity check to avoid malformed URLs.
        zhttps://zhttp://z4api_base_url must start with 'https://' or 'http://'/)strip
startswith
ValueErrorrstrip)clsvs     //var/www/html/Napkin-AI-API/src/utils/config.pyvalidate_base_urlzSettings.validate_base_url   s@     GGIZ(ALL,CSTTxx}    c                    ddh}|j                         j                         }||vrt        dt        |             |S )zValidate output format.r#   pngzdefault_format must be one of )rR   lowerrT   sorted)rV   rW   valid_formatsvalues       rX   validate_formatzSettings.validate_format   sE     	!%=f]>S=TUVVrZ   c                    h d}|j                         j                         }||vrt        dt        |             |S )zValidate log level.>   rB   DEBUGERRORWARNINGCRITICALzlog_level must be one of )rR   upperrT   r^   )rV   rW   valid_levelsr`   s       rX   validate_log_levelzSettings.validate_log_level   sB     I	!$89M8NOPPrZ   c                    t        |      }	 |j                  j                  dd       |S # t        $ r}t	        d|d|       |d}~ww xY w)a#  
        Ensure parent directories exist for paths.

        Note: This writes to disk on first model construction. This is a controlled,
        explicit side effect tied to instantiation, not import. It ensures
        subsequent code paths do not fail due to missing directories.
        T)parentsexist_okz&Unable to create parent directory for z: N)r   parentmkdirOSErrorrT   )rV   rW   pathes       rX   ensure_parent_existszSettings.ensure_parent_exists   sb     Aw	KKdT:
 	  	81#F	s   , 	AAAc                8    | j                    d| j                   S )zGet the full API URL.rQ   )r   r    selfs    rX   api_urlzSettings.api_url   s#     ##$Ad&6&6%788rZ   c                (    d| j                    dddS )z
        Get API request headers with authentication.

        Secrets are not logged. Callers must avoid printing headers.
        zBearer zapplication/json)AuthorizationzContent-TypeAccept)r   rt   s    rX   get_headerszSettings.get_headers   s#      't~~&67.(
 	
rZ   c                   | j                   rdnd}i d| j                  d| j                  d| j                  d| j                  d| j
                  dt        | j                        d	t        | j                        d
t        | j                        dt        | j                        dt        | j                        dt        | j                        dt        | j                        dt        | j                        d| j                  dt        | j                         dt        | j"                        dt        | j$                        t        | j&                        |dS )z
        Returns a redacted, JSON-serializable representation suitable for debug logs.
        Secret values are masked.
        z**** r   r    r"   r%   r'   r.   r0   r2   r5   r9   r<   r?   rA   rD   rG   rK   rM   )rO   r   )r   r   r    r"   r%   r'   r   r.   r0   r2   r5   r9   r<   r?   rA   rD   rG   rK   rM   rO   )ru   masked_tokens     rX   safe_debug_dictzSettings.safe_debug_dict   s   
 "&vR
D--
4++
 T//
 d11	

  5 5
 !#d&=&=">
 C 1 12
 S!3!34
 3t//0
 s4#7#78
 "3t'?'?#@
 $S)C)C%D
  T%;%;!<
 
 #doo.
  %c$*E*E&F!
" #doo.#
$ !!3!34%'
 	
rZ   N)rW   r   returnr   )rW   r   r   r   )r   r   )r   zDict[str, str])&__name__
__module____qualname____doc__r   model_configr   r   __annotations__r   r    r"   r%   r'   r.   r   r0   r2   r5   r9   r<   r?   rA   rD   rG   rK   rM   rO   r	   classmethodrY   ra   ri   rr   propertyrv   rz   r~    rZ   rX   r   r      s    &!L 5 Is 
 ')#L# 
 !"K  !-$M3 
  8%NC 
 "6'c 
 $8)  %&>#L$ 
  017$M4  6"	K  !0&	OS   %5*	   $)8,	$5  #5(	s  # Is 
 '!J 
 #(?-#C  4!J 
  .$M4  ^$	  %	 %&  ' [!  " ^_5  6" 9 9


rZ   r   zOptional[Settings]	_settingsc                    t         j                  j                  d      st        j	                  d       	 t               } t        j                  t        j                        r$t        j	                  d| j                                | S # t        $ rC}t        j                  dt        j                  |j                         t                      d}~ww xY w)zR
    Internal constructor for Settings with logging of non-sensitive context.
    r   zuNAPKIN_API_TOKEN not found in environment. If expected, ensure .env exists or environment variables are properly set.zLoaded configuration: %sz$Failed to validate configuration: %s)r   N)osenvirongetloggerdebugr   isEnabledForloggingrc   r~   r   errorjsondumpserrorsr   )srq   s     rX   _build_settingsr     s     ::>>,-9	


J w}}-LL3Q5F5F5HI  2DJJqxxzSV4W	
 		s   
B	 		C>CCc                 .    t         
t               a t         S )aG  
    Get application settings singleton.

    Returns:
        Settings: instance with validated configuration.

    Raises:
        ValidationError: If required settings are missing or invalid.

    Thread-safety:
        This function is safe for concurrent calls. It uses a simple, idempotent
        initialization without heavy contention. Minor risk of double-init in
        extremely tight concurrent races is acceptable because initialization is
        pure and yields equivalent instances. If a strict single-init is desired,
        wrap this in a process-wide lock.
    )r   r   r   rZ   rX   get_settingsr     s    $ #%	rZ   c                 "    t               at        S )a  
    Force reload settings from environment.

    Useful for testing or when environment variables change during runtime.

    Returns:
        Settings: a fresh Settings instance.

    Note:
        Callers should ensure that components depending on settings can handle
        live-reloads safely. This does not alter existing client instances that
        captured old settings.
    )r   r   r   rZ   rX   reload_settingsr   6  s      !IrZ   )r   r   )r   
__future__r   r   r   r   pathlibr   typingr   r   pydanticr   r   r	   pydantic_settingsr
   r   	getLoggerr   r   r   r   r   r   r   r   r   rZ   rX   <module>r      sd   	 #   	  ! < < >			8	$h
| h
V !%	 $..rZ   