# app/modules/inventory/exceptions.py
"""
Inventory module exceptions.

This module provides exception classes for inventory operations including:
- Inventory record management
- Quantity validation
- Location management
"""

from typing import Any

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

__all__ = [
    "InventoryNotFoundException",
    "InsufficientInventoryException",
    "InvalidInventoryOperationException",
    "InventoryValidationException",
    "NegativeInventoryException",
    "InvalidQuantityException",
    "LocationNotFoundException",
]


class InventoryNotFoundException(ResourceNotFoundException):
    """Raised when inventory record is not found."""

    def __init__(self, identifier: str, identifier_type: str = "ID"):
        if identifier_type.lower() == "gtin":
            message = f"No inventory found for GTIN '{identifier}'"
        else:
            message = (
                f"Inventory record with {identifier_type} '{identifier}' not found"
            )

        super().__init__(
            resource_type="Inventory",
            identifier=identifier,
            message=message,
            error_code="INVENTORY_NOT_FOUND",
        )


class InsufficientInventoryException(BusinessLogicException):
    """Raised when trying to remove more inventory than available."""

    def __init__(
        self,
        gtin: str,
        location: str,
        requested: int,
        available: int,
    ):
        message = f"Insufficient inventory for GTIN '{gtin}' at '{location}'. Requested: {requested}, Available: {available}"

        super().__init__(
            message=message,
            error_code="INSUFFICIENT_INVENTORY",
            details={
                "gtin": gtin,
                "location": location,
                "requested_quantity": requested,
                "available_quantity": available,
            },
        )


class InvalidInventoryOperationException(ValidationException):
    """Raised when inventory operation is invalid."""

    def __init__(
        self,
        message: str,
        operation: str | None = None,
        details: dict[str, Any] | None = None,
    ):
        if not details:
            details = {}

        if operation:
            details["operation"] = operation

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


class InventoryValidationException(ValidationException):
    """Raised when inventory data validation fails."""

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

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


class NegativeInventoryException(BusinessLogicException):  # noqa: MOD025
    """Raised when inventory quantity would become negative."""

    def __init__(self, gtin: str, location: str, resulting_quantity: int):
        message = f"Inventory operation would result in negative quantity ({resulting_quantity}) for GTIN '{gtin}' at '{location}'"

        super().__init__(
            message=message,
            error_code="NEGATIVE_INVENTORY_NOT_ALLOWED",
            details={
                "gtin": gtin,
                "location": location,
                "resulting_quantity": resulting_quantity,
            },
        )


class InvalidQuantityException(ValidationException):
    """Raised when quantity value is invalid."""

    def __init__(self, quantity: Any, message: str = "Invalid quantity"):
        super().__init__(
            message=f"{message}: {quantity}",
            field="quantity",
            details={"quantity": quantity},
        )
        self.error_code = "INVALID_QUANTITY"


class LocationNotFoundException(ResourceNotFoundException):  # noqa: MOD025
    """Raised when inventory location is not found."""

    def __init__(self, location: str):
        super().__init__(
            resource_type="Location",
            identifier=location,
            message=f"Inventory location '{location}' not found",
            error_code="LOCATION_NOT_FOUND",
        )
