from __future__ import annotations

import inspect
from functools import wraps
from typing import Any, List, Type, TypeVar

from fastapi.encoders import jsonable_encoder
from sqlmodel import SQLModel, select
from sqlmodel.ext.asyncio.session import AsyncSession

Self = TypeVar("Self", bound="Base")


class InvalidTable(RuntimeError):
    """Raised when calling a method coupled to SQLAlchemy operations.

    It should be called only by SQLModel objects that are tables.
    """


def is_table(cls: Type[Self]) -> bool:
    base_is_table = False
    for base in cls.__bases__:
        config = getattr(base, "__config__")
        if config and getattr(config, "table", False):
            base_is_table = True
            break
    return getattr(cls.__config__, "table", False) and not base_is_table


def validate_table(func):
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        cls = self if inspect.isclass(self) else self.__class__
        if not is_table(cls):
            raise InvalidTable(
                f'"{cls.__name__}" is not a table. '
                "Add the class parameter `table=True` or don't use with this object."
            )
        return func(self, *args, **kwargs)

    return wrapper


class Base(SQLModel):
    @classmethod
    @validate_table
    async def get(
        cls: Type[Self], session: AsyncSession, *args: Any, **kwargs: Any
    ) -> Self:
        result = await session.execute(