"""
Base error class for Atmosic applications
"""
from __future__ import annotations
from .errorcodes import (
    MajorErrorCodes, MAX_MAJOR_ERROR_CODE, MAX_MINOR_ERROR_CODE,
    ERROR_CODE_VERSION, SerialIoEntryErrorCode, DeviceIoModuleErrorCode,
    PacketModuleErrorCode, HciModuleErrorCode, HciGatewayErrorCode,
    UartLoaderAgentErrorCode, HciStatusErrorCode, UartLoaderTaskErrorCode,
    XmodemOperationErrorCode, UNEXPECTED_ERROR_CODE
)
from .inner_errorcodes import (
    InnerMajorErrorCodes, ResetSupportErrorCode, ResetOperationErrorCode,
)



def cal_error_code(minor_error_code: int, major_error_code: int = 0,
                   is_inner_error: bool = False,
                   error_code_version: int = ERROR_CODE_VERSION) -> int:
    """Calculate error code from major and minor error codes."""

    if not is_inner_error:
        return (error_code_version * 100000) + (major_error_code * 1000) \
            + minor_error_code
    else:
        return UNEXPECTED_ERROR_CODE + (error_code_version * 100000) \
            + (major_error_code * 1000) + minor_error_code

class AtmosicError(Exception):
    """Base exception class for all Atmosic application errors
    
    This class provides a common interface for all application-specific
    errors with optional error codes for detailed error reporting.
    """
    
    def __init__(self, message: str,
                 major_error_code: MajorErrorCodes | InnerMajorErrorCodes,
                 minor_error_code: int = 0):
        """Initialize AtmosicError
        
        Args:
            message: Human-readable error message
            error_code: Optional numeric error code
        """
        super().__init__(message)
        self.message = message
        self.major_error_code = major_error_code.value
        if self.major_error_code > MAX_MAJOR_ERROR_CODE:
            raise ValueError("Major error code must be <"
                             f" {MAX_MAJOR_ERROR_CODE}")
        self.minor_error_code = minor_error_code
        if self.minor_error_code > MAX_MINOR_ERROR_CODE:
            raise ValueError("Minor error code must be <"
                             f" {MAX_MINOR_ERROR_CODE}")
        self.is_inner_error = isinstance(major_error_code,
                                        InnerMajorErrorCodes)

    @property
    def error_code(self) -> int:
        """Combined error code (major + minor)"""
        return cal_error_code(self.minor_error_code, self.major_error_code,
                              self.is_inner_error)
    
    def __str__(self) -> str:
        """String representation of the error"""
        if self.minor_error_code != 0:
            return (f"[Error #{self.error_code}]"
                    f" {self.message}")
        return self.message
    
    def __repr__(self) -> str:
        """Detailed representation of the error"""
        return (f"{self.__class__.__name__}(message={self.message!r}, "
                f"error_code={self.error_code})")

class ResetSupportError(AtmosicError):
    """Exception raised when reset support operations fail"""
    def __init__(self, message: str, error_code: ResetSupportErrorCode):
        """Initialize ResetSupportError"""
        super().__init__(message, InnerMajorErrorCodes.RESET_SUPPORT_ERROR,
                         error_code.value)
class HciStatusError(AtmosicError):
    """Exception raised when HCI status errors occur"""
    def __init__(self, message: str, error_code: HciStatusErrorCode):
        super().__init__(message, MajorErrorCodes.HCI_STATUS_ERROR,
                         error_code.value)

class SerialIoEntryError(AtmosicError):
    """Exception raised when serial I/O operations fail"""
    def __init__(self, message: str, error_code: SerialIoEntryErrorCode):
        super().__init__(message, MajorErrorCodes.SERIAL_IO_ENTRY_ERROR,
                         error_code.value)

class DeviceIoModuleError(AtmosicError):
    """Exception raised for DeviceIoModule errors."""
    def __init__(self, message: str, error_code: DeviceIoModuleErrorCode):
        super().__init__(message, MajorErrorCodes.DEVICE_IO_MODULE_ERROR,
                         error_code.value)

class PacketModuleError(AtmosicError):
    """Exception raised for PacketModule errors."""
    def __init__(self, message: str, error_code: PacketModuleErrorCode):
        super().__init__(message, MajorErrorCodes.PACKET_MODULE_ERROR,
                         error_code.value)

class HciModuleError(AtmosicError):
    """Exception raised for HCI module errors."""
    def __init__(self, message: str, error_code: HciModuleErrorCode):
        super().__init__(message, MajorErrorCodes.HCI_MODULE_ERROR,
                         error_code.value)

class HciGatewayError(AtmosicError):
    """Exception raised for HCI gateway errors."""
    def __init__(self, message: str, error_code: HciGatewayErrorCode):
        super().__init__(message, MajorErrorCodes.HCI_GATEWAY_ERROR,
                         error_code.value)

class UartLoaderAgentError(AtmosicError):
    """Exception raised when uart loader agent operations fail"""
    
    def __init__(self, message: str, error_code: UartLoaderAgentErrorCode):
        super().__init__(message, MajorErrorCodes.UART_LOADER_AGENT_ERROR,
                         error_code.value)

class UartLoaderTaskError(AtmosicError):
    """Exception raised when HCI command operation fails"""
    def __init__(self, message: str, error_code: UartLoaderTaskErrorCode):
        super().__init__(message, MajorErrorCodes.HCI_COMMAND_OPERATION_ERROR,
                         error_code.value)

class ResetOperationError(AtmosicError):
    """Exception raised when reset operation fails"""
    def __init__(self, message: str, error_code: ResetOperationErrorCode):
        super().__init__(message, InnerMajorErrorCodes.RESET_OPERATION_ERROR,
                         error_code.value)

class XmodemOperationError(AtmosicError):
    """Exception raised when Xmodem operation fails"""
    def __init__(self, message: str, error_code: XmodemOperationErrorCode):
        super().__init__(message, MajorErrorCodes.XMODEM_OPERATION_ERROR,
                         error_code.value)