# app/modules/customers/exceptions.py
"""
Customers module exceptions.

This module provides exception classes for customer operations including:
- Customer management (create, update, authentication)
- Address management
- Password reset
"""

from typing import Any

from app.exceptions.base import (
    AuthenticationException,
    BusinessLogicException,
    ConflictException,
    ResourceNotFoundException,
    ValidationException,
)

__all__ = [
    # Customer exceptions
    "CustomerNotFoundException",
    "CustomerAlreadyExistsException",
    "DuplicateCustomerEmailException",
    "CustomerNotActiveException",
    "InvalidCustomerCredentialsException",
    "CustomerValidationException",
    "CustomerAuthorizationException",
    "InvalidPasswordResetTokenException",
    "PasswordTooShortException",
    # Address exceptions
    "AddressNotFoundException",
    "AddressLimitExceededException",
    "InvalidAddressTypeException",
]


# =============================================================================
# Customer Exceptions
# =============================================================================


class CustomerNotFoundException(ResourceNotFoundException):
    """Raised when a customer is not found."""

    def __init__(self, customer_identifier: str):
        super().__init__(
            resource_type="Customer",
            identifier=customer_identifier,
            message=f"Customer '{customer_identifier}' not found",
            error_code="CUSTOMER_NOT_FOUND",
        )


class CustomerAlreadyExistsException(ConflictException):  # noqa: MOD025
    """Raised when trying to create a customer that already exists."""

    def __init__(self, email: str):
        super().__init__(
            message=f"Customer with email '{email}' already exists",
            error_code="CUSTOMER_ALREADY_EXISTS",
            details={"email": email},
        )


class DuplicateCustomerEmailException(ConflictException):
    """Raised when email already exists for store."""

    def __init__(self, email: str, store_code: str):
        super().__init__(
            message=f"Email '{email}' is already registered for this store",
            error_code="DUPLICATE_CUSTOMER_EMAIL",
            details={"email": email, "store_code": store_code},
        )


class CustomerNotActiveException(BusinessLogicException):
    """Raised when trying to perform operations on inactive customer."""

    def __init__(self, email: str):
        super().__init__(
            message=f"Customer account '{email}' is not active",
            error_code="CUSTOMER_NOT_ACTIVE",
            details={"email": email},
        )


class InvalidCustomerCredentialsException(AuthenticationException):
    """Raised when customer credentials are invalid."""

    def __init__(self):
        super().__init__(
            message="Invalid email or password",
            error_code="INVALID_CUSTOMER_CREDENTIALS",
        )


class CustomerValidationException(ValidationException):
    """Raised when customer data validation fails."""

    def __init__(
        self,
        message: str = "Customer validation failed",
        field: str | None = None,
        details: dict[str, Any] | None = None,
    ):
        super().__init__(message=message, field=field, details=details)
        self.error_code = "CUSTOMER_VALIDATION_FAILED"


class CustomerAuthorizationException(BusinessLogicException):  # noqa: MOD025
    """Raised when customer is not authorized for operation."""

    def __init__(self, customer_email: str, operation: str):
        super().__init__(
            message=f"Customer '{customer_email}' not authorized for: {operation}",
            error_code="CUSTOMER_NOT_AUTHORIZED",
            details={"customer_email": customer_email, "operation": operation},
        )


class InvalidPasswordResetTokenException(ValidationException):
    """Raised when password reset token is invalid or expired."""

    def __init__(self):
        super().__init__(
            message="Invalid or expired password reset link. Please request a new one.",
            field="reset_token",
        )
        self.error_code = "INVALID_RESET_TOKEN"


class PasswordTooShortException(ValidationException):
    """Raised when password doesn't meet minimum length requirement."""

    def __init__(self, min_length: int = 8):
        super().__init__(
            message=f"Password must be at least {min_length} characters long",
            field="password",
            details={"min_length": min_length},
        )
        self.error_code = "PASSWORD_TOO_SHORT"


# =============================================================================
# Address Exceptions
# =============================================================================


class AddressNotFoundException(ResourceNotFoundException):
    """Raised when a customer address is not found."""

    def __init__(self, address_id: str | int):
        super().__init__(
            resource_type="Address",
            identifier=str(address_id),
            error_code="ADDRESS_NOT_FOUND",
        )


class AddressLimitExceededException(BusinessLogicException):
    """Raised when customer exceeds maximum number of addresses."""

    def __init__(self, max_addresses: int = 10):
        super().__init__(
            message=f"Maximum number of addresses ({max_addresses}) reached",
            error_code="ADDRESS_LIMIT_EXCEEDED",
            details={"max_addresses": max_addresses},
        )


class InvalidAddressTypeException(BusinessLogicException):  # noqa: MOD025
    """Raised when an invalid address type is provided."""

    def __init__(self, address_type: str):
        super().__init__(
            message=f"Invalid address type '{address_type}'. Must be 'shipping' or 'billing'",
            error_code="INVALID_ADDRESS_TYPE",
            details={"address_type": address_type},
        )
