"""
SWAI Installer Exception Classes

Custom exception classes for handling different types of errors in the SWAI installer.
These exceptions can be caught specifically in other codebases using SwaiError.
"""


class SwaiError(Exception):
    """
    Base exception class for all SWAI installer errors.
    
    This is the main exception that can be caught in other codebases to handle
    any SWAI-related errors specifically.
    """
    def __init__(self, message, error_code=None, original_exception=None):
        super().__init__(message)
        self.message = message
        self.error_code = error_code
        self.original_exception = original_exception
    
    def __str__(self):
        if self.error_code:
            return f"[{self.error_code}] {self.message}"
        return self.message


class SwaiFileError(SwaiError):
    """Exception raised when there are issues with SWAI file operations."""
    def __init__(self, message, file_path=None, **kwargs):
        super().__init__(message, **kwargs)
        self.file_path = file_path


class SwaiParseError(SwaiError):
    """Exception raised when there are issues parsing SWAI file content."""
    def __init__(self, message, file_path=None, line_number=None, **kwargs):
        super().__init__(message, **kwargs)
        self.file_path = file_path
        self.line_number = line_number


class SwaiDownloadError(SwaiError):
    """Exception raised when there are issues downloading files."""
    def __init__(self, message, url=None, status_code=None, **kwargs):
        super().__init__(message, **kwargs)
        self.url = url
        self.status_code = status_code


class SwaiInstallationError(SwaiError):
    """Exception raised when there are issues during installation process."""
    def __init__(self, message, app_id=None, installation_step=None, **kwargs):
        super().__init__(message, **kwargs)
        self.app_id = app_id
        self.installation_step = installation_step


class SwaiDesktopFileError(SwaiError):
    """Exception raised when there are issues creating or managing desktop files."""
    def __init__(self, message, desktop_file_path=None, **kwargs):
        super().__init__(message, **kwargs)
        self.desktop_file_path = desktop_file_path


class SwaiUpdateError(SwaiError):
    """Exception raised when there are issues during update process."""
    def __init__(self, message, app_id=None, update_url=None, **kwargs):
        super().__init__(message, **kwargs)
        self.app_id = app_id
        self.update_url = update_url


class SwaiValidationError(SwaiError):
    """Exception raised when SWAI file validation fails."""
    def __init__(self, message, field_name=None, expected_type=None, **kwargs):
        super().__init__(message, **kwargs)
        self.field_name = field_name
        self.expected_type = expected_type


class SwaiConfigError(SwaiError):
    """Exception raised when there are configuration-related issues."""
    def __init__(self, message, config_path=None, **kwargs):
        super().__init__(message, **kwargs)
        self.config_path = config_path


class SwaiBundleError(SwaiError):
    """Exception raised when there are issues with SWAI bundle operations."""
    def __init__(self, message, bundle_id=None, **kwargs):
        super().__init__(message, **kwargs)
        self.bundle_id = bundle_id


class SwaiPermissionError(SwaiError):
    """Exception raised when there are permission-related issues."""
    def __init__(self, message, path=None, required_permission=None, **kwargs):
        super().__init__(message, **kwargs)
        self.path = path
        self.required_permission = required_permission


# Error codes for common issues
class SwaiErrorCodes:
    """Constants for error codes that can be used for programmatic error handling."""
    
    # File-related errors
    FILE_NOT_FOUND = "SWAI_001"
    FILE_READ_ERROR = "SWAI_002"
    FILE_WRITE_ERROR = "SWAI_003"
    FILE_PERMISSION_DENIED = "SWAI_004"
    
    # Parse-related errors
    YAML_PARSE_ERROR = "SWAI_101"
    INVALID_SWAI_FORMAT = "SWAI_102"
    MISSING_REQUIRED_FIELD = "SWAI_103"
    
    # Download-related errors
    DOWNLOAD_FAILED = "SWAI_201"
    INVALID_URL = "SWAI_202"
    NETWORK_ERROR = "SWAI_203"
    
    # Installation-related errors
    INSTALLATION_FAILED = "SWAI_301"
    DESKTOP_FILE_ERROR = "SWAI_302"
    ICON_PROCESSING_ERROR = "SWAI_303"
    
    # Update-related errors
    UPDATE_FAILED = "SWAI_401"
    NO_UPDATE_URL = "SWAI_402"
    VERSION_CHECK_FAILED = "SWAI_403"
    
    # Validation errors
    VALIDATION_FAILED = "SWAI_501"
    UNSUPPORTED_VERSION = "SWAI_502"
    
    # Bundle-related errors
    BUNDLE_PARSE_ERROR = "SWAI_601"
    BUNDLE_INVALID_FORMAT = "SWAI_602"
    BUNDLE_APP_ERROR = "SWAI_603"
    BUNDLE_NOT_FOUND = "SWAI_604"


def create_swai_error_from_exception(original_exception, message_prefix="", error_code=None):
    """
    Helper function to create appropriate SwaiError from other exceptions.
    
    Args:
        original_exception: The original exception that was caught
        message_prefix: Optional prefix to add to the error message
        error_code: Optional error code to assign
        
    Returns:
        SwaiError: Appropriate SwaiError subclass based on the original exception type
    """
    base_message = str(original_exception)
    full_message = f"{message_prefix}: {base_message}" if message_prefix else base_message
    
    if isinstance(original_exception, FileNotFoundError):
        return SwaiFileError(full_message, error_code=error_code or SwaiErrorCodes.FILE_NOT_FOUND, original_exception=original_exception)
    elif isinstance(original_exception, PermissionError):
        return SwaiPermissionError(full_message, error_code=error_code or SwaiErrorCodes.FILE_PERMISSION_DENIED, original_exception=original_exception)
    elif isinstance(original_exception, (IOError, OSError)):
        return SwaiFileError(full_message, error_code=error_code or SwaiErrorCodes.FILE_READ_ERROR, original_exception=original_exception)
    elif "yaml" in str(type(original_exception)).lower():
        return SwaiParseError(full_message, error_code=error_code or SwaiErrorCodes.YAML_PARSE_ERROR, original_exception=original_exception)
    elif "request" in str(type(original_exception)).lower():
        return SwaiDownloadError(full_message, error_code=error_code or SwaiErrorCodes.DOWNLOAD_FAILED, original_exception=original_exception)
    else:
        return SwaiError(full_message, error_code=error_code, original_exception=original_exception) 