"""Custom exception hierarchy for Teams Phone CLI.

This module defines the base exception class and specialized exceptions
that map to CLI exit codes for structured error handling.
"""

from teams_phone.constants import ExitCode


class TeamsPhoneError(Exception):
    """Base exception for all Teams Phone CLI errors.

    All custom exceptions inherit from this class, providing:
    - An exit_code property for CLI exit status
    - Optional remediation guidance for user-facing messages
    - Consistent string formatting

    Attributes:
        message: The error description.
        remediation: Optional guidance on how to fix the issue.
        exit_code: CLI exit code (defaults to GENERAL_ERROR=1).
    """

    exit_code: int = ExitCode.GENERAL_ERROR

    def __init__(self, message: str, *, remediation: str | None = None) -> None:
        """Initialize the exception.

        Args:
            message: The error description.
            remediation: Optional guidance on how to fix the issue.
        """
        self.message = message
        self.remediation = remediation
        super().__init__(message)

    def __str__(self) -> str:
        """Format the exception for display.

        If remediation is provided, it's appended to the message.
        """
        if self.remediation:
            return f"{self.message}\n\nTo fix:\n{self.remediation}"
        return self.message


class AuthenticationError(TeamsPhoneError):
    """Authentication failure (exit code 2).

    Raised when authentication fails due to:
    - Expired access token
    - Invalid credentials
    - Certificate issues
    - Missing authentication configuration
    """

    exit_code: int = ExitCode.AUTH_ERROR


class AuthorizationError(TeamsPhoneError):
    """Authorization failure (exit code 3).

    Raised when the authenticated principal lacks required permissions:
    - Missing Graph API application permissions
    - Insufficient role assignments
    - Tenant-level restrictions
    """

    exit_code: int = ExitCode.AUTHZ_ERROR


class NotFoundError(TeamsPhoneError):
    """Resource not found (exit code 4).

    Raised when a requested resource doesn't exist:
    - User not found in tenant directory
    - Phone number not in inventory
    - Policy not configured
    - Location not defined
    """

    exit_code: int = ExitCode.NOT_FOUND


class ValidationError(TeamsPhoneError):
    """Input validation failure (exit code 5).

    Raised when input data fails validation:
    - Invalid phone number format
    - Missing required E911 location for Calling Plan numbers
    - Invalid policy name or configuration
    - CSV format or content errors
    """

    exit_code: int = ExitCode.VALIDATION_ERROR


class RateLimitError(TeamsPhoneError):
    """Rate limit exceeded (exit code 6).

    Raised when Graph API returns HTTP 429 (throttled):
    - Too many requests in a time window
    - Tenant-level throttling limits reached

    Note: The CLI will automatically retry with exponential backoff
    before raising this exception.
    """

    exit_code: int = ExitCode.RATE_LIMIT


class ConfigurationError(TeamsPhoneError):
    """Configuration error (exit code 7).

    Raised when configuration is invalid or missing:
    - Config file doesn't exist or is malformed
    - Required tenant not configured
    - Invalid configuration values
    """

    exit_code: int = ExitCode.CONFIG_ERROR


class ContractError(TeamsPhoneError):
    """API contract violation (exit code 8).

    Raised when API responses don't match expected schemas:
    - Missing required fields in response
    - Unexpected data types
    - Schema validation failures

    Note: This exception indicates an internal error that users
    cannot remediate directly. It typically signals either an API
    change or a bug in the CLI.
    """

    exit_code: int = ExitCode.CONTRACT_ERROR
