import os
import yaml
from typing import Dict, Any, Optional
from pydantic import BaseModel, Field


class Exports(BaseModel):
    """
    Pydantic model for managing CloudFormation export values.
    
    This model provides a mapping interface for accessing export values.
    """
    data: Dict[str, str] = Field(default_factory=dict)
    
    # Essential mapping interface methods
    def __getitem__(self, key: str) -> str:
        """Allow dict-like access: exports[key]"""
        return self.data[key]
    
    def __setitem__(self, key: str, value: str) -> None:
        """Allow dict-like assignment: exports[key] = value"""
        self.data[key] = value
    
    @property
    def _data(self) -> Dict[str, str]:
        """Return the underlying data dict"""
        return self.data.copy()


class InfraConfig(BaseModel):
    """
    Pydantic model for managing infra.yml configuration.
    
    This model provides a clean interface for accessing CloudFormation export values
    and other infrastructure configuration data.
    """
    exports: Exports = Field(default_factory=Exports, description="CloudFormation export values")
    
    @classmethod
    def load(cls, file_path: Optional[str] = None) -> 'InfraConfig':
        """
        Load infra configuration from a YAML file.
        
        Args:
            file_path: Path to the infra.yml file. If None, looks for 'infra.yml' in current directory.
            
        Returns:
            InfraConfig instance with loaded data
            
        Raises:
            FileNotFoundError: If infra.yml is not found
            yaml.YAMLError: If the YAML file is malformed
        """
        if file_path is None:
            file_path = os.path.join(os.getcwd(), 'infra.yml')
        
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"infra.yml not found at {file_path}")
        
        with open(file_path, 'r') as f:
            data = yaml.safe_load(f) or {}
        
        # Handle the exports data
        exports_data = data.get('exports', {})
        return cls(exports=Exports(data=exports_data))
    
    
    def save(self, file_path: Optional[str] = None) -> None:
        """
        Save the configuration to a YAML file.
        
        Args:
            file_path: Path to save the infra.yml file. If None, saves to 'infra.yml' in current directory.
        """
        if file_path is None:
            file_path = os.path.join(os.getcwd(), 'infra.yml')
        
        data = {
            'exports': self.exports._data
        }
        with open(file_path, 'w') as f:
            yaml.dump(data, f, default_flow_style=False)
