
    O\i9                     h    d Z ddlZddlZddlmZ ddlmZmZmZm	Z	m
Z
 ddlmZ  G d d          ZdS )a  
Settings Service Layer

This module manages application settings persistence and MongoDB connection configuration.
Settings are stored in app_config.yaml and can be updated through the UI.

Key principles:
- Explicit user control: No automatic reconnections or background operations
- Safe persistence: Settings are validated before saving
- Clear error handling: All errors are surfaced to the UI
    N)Path)DictAnyOptionalTupleList)MongoClientc                   8   e Zd ZdZd"defdZdeeef         fdZdeeef         fdZ		 	 d#d	ed
ede
de
deeee         f         f
dZ	 	 d#d	ed
ede
de
deeee         f         f
dZdefdZdefdZd$dZdeeef         fdZdedeeef         fdZ	 d%dedee         dee         dededeeee         f         fdZde
fdZde
deeee         f         fdZdedeeeef                  fdZded eeeef                  deeee         f         fd!ZdS )&SettingsServicez
    Service for managing application settings and MongoDB configuration.
    
    This service handles:
    - Loading and saving settings to app_config.yaml
    - Testing MongoDB connections
    - Validating configuration values
    config/app_config.yamlconfig_pathc                 `    t          |          | _        |                                 | _        dS )z~
        Initialize settings service.
        
        Args:
            config_path: Path to YAML configuration file
        N)r   r   _load_configconfig)selfr   s     5/var/www/html/IGF-ODF-V3/services/settings_service.py__init__zSettingsService.__init__   s+      ,,''))    returnc                     | j                                         st          d| j                    t          | j         d          5 }t	          j        |          cddd           S # 1 swxY w Y   dS )zs
        Load configuration from YAML file.
        
        Returns:
            Configuration dictionary
        zConfiguration file not found: rN)r   existsFileNotFoundErroropenyaml	safe_load)r   fs     r   r   zSettingsService._load_config(   s     &&(( 	Y#$WTEU$W$WXXX$"C(( 	%A>!$$	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	%s   A''A+.A+c                    | j                             di           }|                    dd          }t          j        |d          }|||                    dd          |                    dd          |                    d	d          d
S )ad  
        Get current MongoDB settings.
        
        Returns:
            Dictionary with MongoDB configuration:
            - uri: Connection URI (from environment or default)
            - database: Database name
            - connection_timeout: Connection timeout in ms
            - server_selection_timeout: Server selection timeout in ms
        mongodburi_env	MONGO_URIzpmongodb://AdminUser:WnE0TjGIafVJutreZL7cTIoWNWU52YyxLVgwCUqIGCGg3YUT@18.184.249.241:27017/?authMechanism=DEFAULTdatabaseIGF_WORKconnection_timeout  server_selection_timeout)urir    r"   r$   r&   r   getosgetenv)r   mongo_configr    r'   s       r   get_mongodb_settingsz$SettingsService.get_mongodb_settings5   s     {y"55 ""9k::i  "T  U  U $((Z@@"."2"23G"N"N(4(8(89SUY(Z(Z
 
 	
r   r%   r'   r"   r$   r&   c                    d}	 t          |||          }|j                            d           ||         }|                                 	 ||                                 dS dS # t
          $ r2}dt          |          fcY d}~||                                 S S d}~ww xY w# ||                                 w w xY w)a  
        Test MongoDB connection with provided settings.
        
        Args:
            uri: MongoDB connection URI
            database: Database name
            connection_timeout: Connection timeout in milliseconds
            server_selection_timeout: Server selection timeout in milliseconds
        
        Returns:
            Tuple of (success: bool, error_message: Optional[str])
        N)serverSelectionTimeoutMSconnectTimeoutMSpingTNF)r	   admincommandlist_collection_namesclose	Exceptionstr)r   r'   r"   r$   r&   clientdbes           r   test_connectionzSettingsService.test_connectionN   s   & 	 )A!3  F L  ((( !B$$&&&   	  	! 	! 	!#a&&=       		!  s0   AA' '
B#1BB#B& B##B& &B?c                    	 |r|                                 sdS |r|                                 sdS |dk     rdS |dk     rdS |                                 }|                    d          s|                    d          sdS |                                 | j        d	         d
<   t          |          | j        d	         d<   t          |          | j        d	         d<   	 t	          | j        dd          5 }t          j        | j        |ddd           ddd           n# 1 swxY w Y   nC# t          $ r dd| j         dfcY S t          $ r}ddt          |           fcY d}~S d}~ww xY w| j        d	                             dd          }|t          j        |<   dS # t          $ r}	ddt          |	           fcY d}	~	S d}	~	ww xY w)aG  
        Save MongoDB settings to configuration file and environment.
        
        This method:
        1. Validates the settings
        2. Updates app_config.yaml
        3. Updates the environment variable for the current session
        
        Args:
            uri: MongoDB connection URI
            database: Database name
            connection_timeout: Connection timeout in milliseconds
            server_selection_timeout: Server selection timeout in milliseconds
        
        Returns:
            Tuple of (success: bool, error_message: Optional[str])
        )FzMongoDB URI cannot be empty)FzDatabase name cannot be emptyi  )Fz*Connection timeout must be at least 1000ms)Fz0Server selection timeout must be at least 1000msz
mongodb://zmongodb+srv://)Fz<MongoDB URI must start with 'mongodb://' or 'mongodb+srv://'r   r"   r$   r&   wutf-8encodingFTdefault_flow_style	sort_keysallow_unicodeN#Permission denied: Cannot write to z. Check file permissions.Failed to write config file: r    r!   r2   zFailed to save settings: )strip
startswithr   intr   r   r   dumpPermissionErrorr7   r8   r)   r*   environ)
r   r'   r"   r$   r&   uri_strippedr   
file_errorr    r;   s
             r   save_mongodb_settingsz%SettingsService.save_mongodb_settingsz   s   0(	? <ciikk <;; >8>>#3#3 >==!D( KJJ'$. QPP 99;;L**<88 ]AXAXYiAjAj ]\\ 2:1A1ADK	":.;>?Q;R;RDK	"#78ADE]A^A^DK	"#=>P$*C'BBB maIdk1RWgkllllm m m m m m m m m m m m m m m" p p poDDTooooooo P P POc*ooOOOOOOOOOP k),00KHHG".BJw: 	? 	? 	?>c!ff>>>>>>>>>	?s   F" F" F" F" >F" AF" D- 6D!D- !D%%D- (D%)D- ,F" -E-F" 	E-E("E-#F" (E--3F" "
G
,G?G
G
c                 `    | j                             di                               dd          S )zg
        Get the configured database name.
        
        Returns:
            Database name
        r   r"   r#   r   r)   r   s    r   get_database_namez!SettingsService.get_database_name   s*     {y"--11*jIIIr   c                     | j                             di                               dd          }t          j        |d          S )zw
        Get the MongoDB connection URI from environment.
        
        Returns:
            Connection URI
        r   r    r!   zmongodb://localhost:27017r(   )r   r    s     r   get_connection_uriz"SettingsService.get_connection_uri   s<     +//)R0044YLLy"=>>>r   Nc                 8    |                                  | _        dS )z
        Reload configuration from file.
        
        This is useful after settings have been saved to ensure
        the service has the latest configuration.
        N)r   r   rS   s    r   reload_configzSettingsService.reload_config   s     ''))r   c                 8    | j                             di           S )z
        Get all collection configurations.
        
        Returns:
            Dictionary of collection configurations
        collectionsrR   rS   s    r   get_all_collectionsz#SettingsService.get_all_collections   s     {}b111r   collection_namec                 d    | j                             di           }|                    |i           S )z
        Get configuration for a specific collection.
        
        Args:
            collection_name: Name of the collection
            
        Returns:
            Collection configuration dictionary
        rZ   rR   )r   r\   rZ   s      r   get_collection_configz%SettingsService.get_collection_config   s-     koomR88333r   Tbusiness_keysalternative_keysmatching_strategyenabledc                    	 d| j         vr
i | j         d<   || j         d         vri | j         d         |<   || j         d         |         d<   || j         d         |         d<   || j         d         |         d<   || j         d         |         d<   	 t          | j        dd          5 }t          j        | j         |d	d	d
           ddd           n# 1 swxY w Y   nB# t
          $ r d	d| j         fcY S t          $ r}d	dt          |           fcY d}~S d}~ww xY wdS # t          $ r}d	dt          |           fcY d}~S d}~ww xY w)a  
        Update collection configuration.
        
        Args:
            collection_name: Name of the collection
            business_keys: List of business key field names
            alternative_keys: List of alternative key field names
            matching_strategy: Matching strategy (primary_only, primary_or_alternative, alternative_only)
            enabled: Whether collection is enabled
            
        Returns:
            Tuple of (success: bool, error_message: Optional[str])
        rZ   rb   r_   r`   ra   r>   r?   r@   FTrB   NrF   rG   r2   z$Failed to update collection config: r   r   r   r   rK   rL   r7   r8   )	r   r\   r_   r`   ra   rb   r   rO   r;   s	            r   update_collection_configz(SettingsService.update_collection_config   s   *	JDK/ 0-/M*dk-&@@ A>@M*?; FMDK&7	BKXDK&7HN^DK&78JKO`DK&78KLP$*C'BBB maIdk1RWgkllllm m m m m m m m m m m m m m m" W W WVDDTVVVVVV P P POc*ooOOOOOOOOOP : 	J 	J 	JIQIIIIIIIII	Js~   B
D C $CC CC CC D D1D 3	D<DDD DD 
E)E<EEc                     | j                             di                               dd          }	 t          |          S # t          t          f$ r Y dS w xY w)zz
        Get the record limit for data loading.
        
        Returns:
            Record limit (default 5000)
        uidefault_record_limitr%   )r   r)   rJ   
ValueError	TypeError)r   limits     r   get_record_limitz SettingsService.get_record_limit  sb     b))--.DdKK	u::I& 	 	 	44	s   A   AArk   c                    	 |dk     rdS |dk    rdS d| j         vr
i | j         d<   || j         d         d<   	 t          | j        dd	          5 }t          j        | j         |d
d
d           ddd           n# 1 swxY w Y   nB# t
          $ r d
d| j         fcY S t          $ r}d
dt          |           fcY d}~S d}~ww xY wdS # t          $ r}d
dt          |           fcY d}~S d}~ww xY w)z
        Update the record limit for data loading.
        
        Args:
            limit: New record limit
            
        Returns:
            Tuple of (success: bool, error_message: Optional[str])
        d   )Fz!Record limit must be at least 100i )Fz"Record limit cannot exceed 100,000rg   rh   r>   r?   r@   FTrB   NrF   rG   r2   zFailed to update record limit: rd   )r   rk   r   rO   r;   s        r   update_record_limitz#SettingsService.update_record_limit,  s   	Es{ BAAv~ CBB4;& '$&D!8=DK45P$*C'BBB maIdk1RWgkllllm m m m m m m m m m m m m m m" W W WVDDTVVVVVV P P POc*ooOOOOOOOOOP : 	E 	E 	EDCFFDDDDDDDDD	Es   C C #C B A8,B 8A<<B ?A< B C CC 	C%B>8C9C >CC 
C0C+%C0+C0c                     | j                             di           }|                    |i           }|                    dg           S )a  
        Get foreign key relationships for a collection.
        
        Args:
            collection_name: Name of the collection
            
        Returns:
            List of foreign key definitions, each with:
            - field: Field name in this collection
            - references_collection: Target collection name
            - references_field: Field name in target collection
        rZ   foreign_keysrR   )r   r\   rZ   collection_configs       r   get_foreign_keysz SettingsService.get_foreign_keysP  sC     koomR88'OOOR@@ $$^R888r   rq   c                 t   	 d| j         vr
i | j         d<   || j         d         vri | j         d         |<   |D ]/}d|vs|d         s dS d|vs|d         s dS d|vs|d         s dS 0|| j         d         |         d<   	 t          | j        d	d
          5 }t          j        | j         |ddd           ddd           n# 1 swxY w Y   nB# t
          $ r dd| j         fcY S t          $ r}ddt          |           fcY d}~S d}~ww xY wdS # t          $ r}ddt          |           fcY d}~S d}~ww xY w)a*  
        Update foreign key relationships for a collection.
        
        Args:
            collection_name: Name of the collection
            foreign_keys: List of foreign key definitions
            
        Returns:
            Tuple of (success: bool, error_message: Optional[str])
        rZ   field)Fz)Foreign key must have a 'field' specifiedreferences_collection)Fz9Foreign key must have a 'references_collection' specifiedreferences_field)Fz4Foreign key must have a 'references_field' specifiedrq   r>   r?   r@   FTrB   NrF   rG   r2   zFailed to update foreign keys: rd   )r   r\   rq   fkr   rO   r;   s          r   update_foreign_keysz#SettingsService.update_foreign_keysa  sZ   	EDK/ 0-/M*dk-&@@ A>@M*?; # Y Y"$ NBwK NMMM*"4 ^B?V<W ^]]]%R/ Yr:L7M YXXXY KWDK&7GP$*C'BBB maIdk1RWgkllllm m m m m m m m m m m m m m m" W W WVDDTVVVVVV P P POc*ooOOOOOOOOOP : 	E 	E 	EDCFFDDDDDDDDD	Es   AD D D %D =C B?3C ?CC CC 
D D
!D #	D
,D?D
 D D

D 
D7D2,D72D7)r   )r%   r%   )r   N)T)__name__
__module____qualname____doc__r8   r   r   r   r   r-   rJ   r   boolr   r<   rP   rT   rV   rX   r[   r^   r   re   rl   ro   rs   ry    r   r   r   r      s9        * *C * * * *%d38n % % % %
d38n 
 
 
 
: #'(,* ** *  	*
 #&* 
tXc]"	#* * * *` #'(,@? @?@? @?  	@?
 #&@? 
tXc]"	#@? @? @? @?DJ3 J J J J?C ? ? ? ?* * * *2T#s(^ 2 2 2 24S 4T#s(^ 4 4 4 4& .J .J.J Cy.J s)	.J
 .J .J 
tXc]"	#.J .J .J .J`#    "E "EtXc]7J1K "E "E "E "EH9 9T#s(^8L 9 9 9 9".E.E 4S>*.E 
tXc]"	#	.E .E .E .E .E .Er   r   )r}   r*   r   pathlibr   typingr   r   r   r   r   pymongor	   r   r   r   r   <module>r      s   
 
 
			        3 3 3 3 3 3 3 3 3 3 3 3 3 3      {E {E {E {E {E {E {E {E {E {Er   