class DomainException(Exception):
    _context_attrs = tuple()

    def __init__(self, *args, **kwargs):
        super().__init__(*args)
        for attr in self._context_attrs:
            setattr(self, attr, kwargs[attr])

    @property
    def context_as_str(self):
        return ", ".join(
            map(lambda attr: f"{attr}={getattr(self, attr, None)}", self._context_attrs)
        )


class AgencyDoesNotExist(DomainException):
    _context_attrs = ("agency_id",)


class ClientDoesNotExist(DomainException):
    _context_attrs = ("client_id",)


class ClientByUidDoesNotExist(DomainException):
    _context_attrs = ("uid", "is_agency")


class ClientsDoNotExist(DomainException):
    _context_attrs = ("client_ids",)


class ContractDoesNotExist(DomainException):
    _context_attrs = ("contract_id",)


class ClientContractMismatch(DomainException):
    _context_attrs = ("client_id", "contract_id")


class ClientIsAgency(DomainException):
    _context_attrs = ("client_id",)


class ClientIsNotAgency(DomainException):
    _context_attrs = ("client_id",)


class ClientNotInAgency(DomainException):
    _context_attrs = ("client_id", "agency_id")


class ProductDoesNotExist(DomainException):
    _context_attrs = ("product_id",)


class ProductIsInactive(DomainException):
    _context_attrs = ("product_id",)


class ProductClientMismatch(DomainException):
    _context_attrs = ("product_id", "client_ids")


class ProductAgencyMismatch(DomainException):
    _context_attrs = ("product_id", "agency_id")


class ProductServiceMismatch(DomainException):
    _context_attrs = ("product_id", "product_service_id", "service_id")


class NoProductsMatched(DomainException):
    pass


class MultipleProductsMatched(DomainException):
    pass


class NonCPMProduct(DomainException):
    _context_attrs = ("product_id",)


class NoActiveVersionsForProduct(DomainException):
    _context_attrs = ("product_id",)


class OrderDoesNotExist(DomainException):
    _context_attrs = ("order_id",)


class OrdersDoNotExist(DomainException):
    _context_attrs = ("order_ids",)


class ExternalOrdersDoNotExist(DomainException):
    _context_attrs = ("external_order_ids",)


class OrdersBillInFuture(DomainException):
    _context_attrs = ("bill_timestamp",)


class WrongBalanceServiceID(Exception):
    pass


class BadDuplicatedCharge(DomainException):
    _context_attrs = ("order_ids",)


class UserIsAssignedToAnotherClient(DomainException):
    pass


class InvalidBillingType(DomainException):
    _context_attrs = ("billing_type",)


class NoPlatformsSpecified(DomainException):
    pass


class NoProductVersionsSpecified(DomainException):
    pass


class ConflictingProductVersionTimeSpans(DomainException):
    _context_attrs = ("to", "from_")


class ConflictingProducts(DomainException):
    _context_attrs = ("product_ids",)


class ClientsAreAlreadyInAgency(DomainException):
    _context_attrs = ("client_ids",)


class ClientsHaveOrdersWithAgency(DomainException):
    _context_attrs = ("client_ids",)


class ProductHasZeroCost(DomainException):
    pass


class ClientsAlreadyBoundToOverlappingProducts(DomainException):
    _context_attrs = ("client_ids", "platforms", "currency")


__all__ = [
    "AgencyDoesNotExist",
    "BadDuplicatedCharge",
    "ClientDoesNotExist",
    "ClientByUidDoesNotExist",
    "ClientsDoNotExist",
    "ClientContractMismatch",
    "ClientIsAgency",
    "ClientIsNotAgency",
    "ClientNotInAgency",
    "DomainException",
    "ContractDoesNotExist",
    "ProductDoesNotExist",
    "ProductIsInactive",
    "ProductClientMismatch",
    "ProductAgencyMismatch",
    "NoProductsMatched",
    "MultipleProductsMatched",
    "NonCPMProduct",
    "NoActiveVersionsForProduct",
    "OrderDoesNotExist",
    "OrdersDoNotExist",
    "OrdersBillInFuture",
    "WrongBalanceServiceID",
    "ExternalOrdersDoNotExist",
    "UserIsAssignedToAnotherClient",
    "InvalidBillingType",
    "NoPlatformsSpecified",
    "NoProductVersionsSpecified",
    "ConflictingProductVersionTimeSpans",
    "ConflictingProducts",
    "ProductHasZeroCost",
    "ClientsAlreadyBoundToOverlappingProducts",
]
