from __future__ import annotations
from functools import wraps
from typing import Type
from pydantic import BaseModel

class OperationBase:
    def __init_subclass__(cls, *, ctx_type: Type[BaseModel] | None = None,
                          **kwargs):
        super().__init_subclass__(**kwargs)

        if ctx_type is None:
            return

        if not isinstance(ctx_type, type) or not issubclass(ctx_type,
                                                            BaseModel):
            raise TypeError(
                f"{cls.__name__}.ctx_type must be a pydantic BaseModel type."
            )

        orig_init = cls.__init__

        @wraps(orig_init)
        def __init__(self, ctx: BaseModel, *args, **kwargs):
            if type(ctx) is not ctx_type:
                raise TypeError(
                    f"Init {cls.__name__} requires exact {ctx_type.__name__}. "
                    f"But got {type(ctx).__name__}. Please dispatch explicitly."
                )
            return orig_init(self, ctx, *args, **kwargs)

        cls.__init__ = __init__  # type: ignore[assignment]