# app/modules/catalog/exceptions.py
"""
Catalog module exceptions.

This module provides exception classes for catalog operations including:
- Product management (CRUD)
- Product validation
- Product dependencies (inventory, orders)
"""

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

__all__ = [
    "ProductNotFoundException",
    "ProductAlreadyExistsException",
    "ProductNotInCatalogException",
    "ProductNotActiveException",
    "InvalidProductDataException",
    "ProductValidationException",
    "CannotDeleteProductException",
    "CannotDeleteProductWithInventoryException",
    "CannotDeleteProductWithOrdersException",
    "ProductMediaException",
]


class ProductNotFoundException(ResourceNotFoundException):
    """Raised when a product is not found in store catalog."""

    def __init__(self, product_id: int, store_id: int | None = None):
        if store_id:
            message = f"Product with ID '{product_id}' not found in store {store_id} catalog"
        else:
            message = f"Product with ID '{product_id}' not found"

        super().__init__(
            resource_type="Product",
            identifier=str(product_id),
            message=message,
            error_code="PRODUCT_NOT_FOUND",
        )
        self.details["product_id"] = product_id
        if store_id:
            self.details["store_id"] = store_id


class ProductAlreadyExistsException(ConflictException):
    """Raised when trying to add a product that already exists."""

    def __init__(self, store_id: int, identifier: str | int):
        super().__init__(
            message=f"Product '{identifier}' already exists in store {store_id} catalog",
            error_code="PRODUCT_ALREADY_EXISTS",
            details={
                "store_id": store_id,
                "identifier": identifier,
            },
        )


class ProductNotInCatalogException(ResourceNotFoundException):  # noqa: MOD025
    """Raised when trying to access a product that's not in store's catalog."""

    def __init__(self, product_id: int, store_id: int):
        super().__init__(
            resource_type="Product",
            identifier=str(product_id),
            message=f"Product {product_id} is not in store {store_id} catalog",
            error_code="PRODUCT_NOT_IN_CATALOG",
        )
        self.details["product_id"] = product_id
        self.details["store_id"] = store_id


class ProductNotActiveException(BusinessLogicException):
    """Raised when trying to perform operations on inactive product."""

    def __init__(self, product_id: int, store_id: int):
        super().__init__(
            message=f"Product {product_id} in store {store_id} catalog is not active",
            error_code="PRODUCT_NOT_ACTIVE",
            details={
                "product_id": product_id,
                "store_id": store_id,
            },
        )


class InvalidProductDataException(ValidationException):
    """Raised when product data is invalid."""

    def __init__(
        self,
        message: str = "Invalid product data",
        field: str | None = None,
        details: dict | None = None,
    ):
        super().__init__(
            message=message,
            field=field,
            details=details,
        )
        self.error_code = "INVALID_PRODUCT_DATA"


class ProductValidationException(ValidationException):
    """Raised when product data validation fails."""

    def __init__(
        self,
        message: str = "Product validation failed",
        field: str | None = None,
        validation_errors: dict | None = None,
    ):
        details = {}
        if validation_errors:
            details["validation_errors"] = validation_errors

        super().__init__(
            message=message,
            field=field,
            details=details,
        )
        self.error_code = "PRODUCT_VALIDATION_FAILED"


class CannotDeleteProductException(BusinessLogicException):  # noqa: MOD025
    """Raised when a product cannot be deleted due to dependencies."""

    def __init__(self, product_id: int, reason: str, details: dict | None = None):
        super().__init__(
            message=f"Cannot delete product {product_id}: {reason}",
            error_code="CANNOT_DELETE_PRODUCT",
            details={"product_id": product_id, "reason": reason, **(details or {})},
        )


class CannotDeleteProductWithInventoryException(BusinessLogicException):  # noqa: MOD025
    """Raised when trying to delete a product that has inventory."""

    def __init__(self, product_id: int, inventory_count: int):
        super().__init__(
            message=f"Cannot delete product {product_id} - it has {inventory_count} inventory entries",
            error_code="CANNOT_DELETE_PRODUCT_WITH_INVENTORY",
            details={
                "product_id": product_id,
                "inventory_count": inventory_count,
            },
        )


class CannotDeleteProductWithOrdersException(BusinessLogicException):  # noqa: MOD025
    """Raised when trying to delete a product that has been ordered."""

    def __init__(self, product_id: int, order_count: int):
        super().__init__(
            message=f"Cannot delete product {product_id} - it has {order_count} associated orders",
            error_code="CANNOT_DELETE_PRODUCT_WITH_ORDERS",
            details={
                "product_id": product_id,
                "order_count": order_count,
            },
        )


class ProductMediaException(BusinessLogicException):
    """Raised when there's an issue with product media."""

    def __init__(self, product_id: int, message: str):
        super().__init__(
            message=message,
            error_code="PRODUCT_MEDIA_ERROR",
            details={"product_id": product_id},
        )
