o
    O\i9                     @   sZ   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 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                   @   s  e Zd ZdZd1defddZdeeef fddZdeeef fd	d
Z			d2dedede
de
deeee f f
ddZ		d2dedede
de
deeee f f
ddZdefddZdefddZd3ddZdeeef fddZdedeeef fddZ	 d4ded!ee d"ee d#ed$edeeee f fd%d&Zde
fd'd(Zd)e
deeee f fd*d+Zdedeeeef  fd,d-Zded.eeeef  deeee f fd/d0ZdS )5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                 C   s   t || _|  | _dS )z~
        Initialize settings service.
        
        Args:
            config_path: Path to YAML configuration file
        N)r   r   _load_configconfig)selfr    r   5/var/www/html/IGF-ODF-V3/services/settings_service.py__init__   s   
zSettingsService.__init__returnc                 C   sT   | j  std| j  t| j d}t|W  d   S 1 s#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   fr   r   r   r   (   s
   
$zSettingsService._load_configc                 C   sN   | j di }|dd}t|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"   r   r   r   get_mongodb_settings5   s   


z$SettingsService.get_mongodb_settingsr    r"   r   r   r!   c              
   C   s   d}zFz#t |||d}|jd || }|  W W |dur%|  dS dS  tyH } zdt|fW  Y d}~W |durC|  S S d}~ww |durR|  w 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er   r   r   test_connectionN   s0   

zSettingsService.test_connectionc           
   
   C   s  z|r|  s
W dS |r|  sW dS |dk rW dS |dk r!W dS |  }|ds2|ds2W dS |  | jd	 d
< t|| jd	 d< t|| jd	 d< z%t| jddd}tj| j|dddd W d   n1 slw   Y  W n. ty   dd| j df Y W S  t	y } zddt
| fW  Y d}~W S d}~ww | jd	 dd}|tj|< W dS  t	y }	 zddt
|	 fW  Y d}	~	S d}	~	w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   r,   zFailed to save settings: )strip
startswithr   intr   r   r   dumpPermissionErrorr1   r2   r$   r%   environ)
r   r"   r   r   r!   uri_strippedr   
file_errorr   r5   r   r   r   save_mongodb_settingsz   sB    
z%SettingsService.save_mongodb_settingsc                 C   s   | j di ddS )zg
        Get the configured database name.
        
        Returns:
            Database name
        r   r   r   r   r$   r   r   r   r   get_database_name   s   z!SettingsService.get_database_namec                 C   s"   | j di dd}t|dS )zw
        Get the MongoDB connection URI from environment.
        
        Returns:
            Connection URI
        r   r   r   zmongodb://localhost:27017r#   )r   r   r   r   r   get_connection_uri   s   z"SettingsService.get_connection_uriNc                 C   s   |   | _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   rK   r   r   r   reload_config      zSettingsService.reload_configc                 C   s   | j di S )z
        Get all collection configurations.
        
        Returns:
            Dictionary of collection configurations
        collectionsrJ   rK   r   r   r   get_all_collections   rO   z#SettingsService.get_all_collectionscollection_namec                 C   s   | j di }||i S )z
        Get configuration for a specific collection.
        
        Args:
            collection_name: Name of the collection
            
        Returns:
            Collection configuration dictionary
        rP   rJ   )r   rR   rP   r   r   r   get_collection_config   s   
z%SettingsService.get_collection_configTbusiness_keysalternative_keysmatching_strategyenabledc           	   
   C   s`  zd| 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< z*t| jddd}tj| j |d	d	d
d W d   W W dS 1 s_w   Y  W W dS  tyy   d	d| j f Y W S  ty } zd	dt| fW  Y d}~W S d}~ww  ty } zd	dt| fW  Y d}~S d}~w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])
        rP   rW   rT   rU   rV   r7   r8   r9   FTr;   Nr?   r@   r,   z$Failed to update collection config: r   r   r   r   rD   rE   r1   r2   )	r   rR   rT   rU   rV   rW   r   rH   r5   r   r   r   update_collection_config   s4   

 z(SettingsService.update_collection_configc              	   C   s:   | j di dd}zt|W S  ttfy   Y dS w )zz
        Get the record limit for data loading.
        
        Returns:
            Record limit (default 5000)
        uidefault_record_limitr    )r   r$   rC   
ValueError	TypeError)r   limitr   r   r   get_record_limit  s   
z SettingsService.get_record_limitr^   c              
   C   s&  zw|dk rW dS |dkrW dS d| j vri | j d< || j d d< z*t| jddd	}tj| j |d
d
dd W d   W W dS 1 sBw   Y  W W dS  ty\   d
d| j f Y W S  tyw } zd
dt| fW  Y d}~W S d}~ww  ty } zd
dt| fW  Y d}~S d}~w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,000rZ   r[   r7   r8   r9   FTr;   Nr?   r@   r,   zFailed to update record limit: rX   )r   r^   r   rH   r5   r   r   r   update_record_limit,  s2   


 z#SettingsService.update_record_limitc                 C   s&   | 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
        rP   foreign_keysrJ   )r   rR   rP   collection_configr   r   r   get_foreign_keysP  s   z SettingsService.get_foreign_keysrb   c              
   C   s|  zd| j vri | j d< || j d vri | j d |< |D ]&}d|vs%|d s) W dS d|vs1|d s5 W dS d|vs=|d sA W dS q|| j d | d< z*t| jd	d
d}tj| j |dddd W d   W W dS 1 smw   Y  W W dS  ty   dd| j f Y W S  ty } zddt| fW  Y d}~W S d}~ww  ty } zddt| fW  Y d}~S d}~w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])
        rP   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' specifiedrb   r7   r8   r9   FTr;   Nr?   r@   r,   zFailed to update foreign keys: rX   )r   rR   rb   fkr   rH   r5   r   r   r   update_foreign_keysa  s>   

 z#SettingsService.update_foreign_keys)r
   )r    r    )r   N)T)__name__
__module____qualname____doc__r2   r   r   r   r   r(   rC   r   boolr   r6   rI   rL   rM   rN   rQ   rS   r   rY   r_   ra   rd   ri   r   r   r   r   r	      sx    	

0
B	

		
0$r	   )rm   r%   r   pathlibr   typingr   r   r   r   r   pymongor   r	   r   r   r   r   <module>   s    