from .fields import Field
from .query import Query


class EntityMeta(type):

    def __new__(mcs, name, bases, cls_dict):
        if 'Entity' in globals():
            if '__slots__' in cls_dict:
                raise (TypeError, 'Entity classes cannot contain __slots__ variable')
            cls_dict['__slots__'] = ()
        return super(EntityMeta, mcs).__new__(mcs, name, bases, cls_dict)

    def __init__(cls, name, bases, cls_dict):
        super(EntityMeta, cls).__init__(name, bases, cls_dict)
        cls._database_ = None
        if name == 'Entity':
            return
        if hasattr(cls, '__tablename__'):
            cls.table_name = cls.__tablename__
        else:
            cls.table_name = cls.__name__.lower()
        databases = set()
        for base_class in bases:
            if isinstance(base_class, EntityMeta):
                database = base_class._database_
                if database is None:
                    raise (Exception, 'Base Entity does not belong to any database')
                databases.add(database)
        if not databases:
            assert False  # pragma: no cover
        elif len(databases) > 1:
            raise (Exception, 'With multiple inheritance of entities, all entities must belong to the same database')
        database = databases.pop()

        if cls.__name__ in database.entities:
            raise (Exception, 'Entity %s already exists' % cls.__name__)
        assert cls.__name__ not in database.__dict__

        if database.schema is not None:
            raise (Exception,
            'Cannot define entity %r: database mapping has already been generated' % cls.__name__)

        cls._database_ = database

        new_attrs = []
        cls.attrs_dict = {}
        for name, attr in list(cls.__dict__.items()):
            if not isinstance(attr, Field):
                continue
            attr._init_(cls, name)
            new_attrs.append(attr)
            cls.attrs_dict[name] = attr
        cls.attrs = new_attrs

    def _query_from_args_(cls, args, kwargs):
        return Query(cls, args, kwargs).get()

    def get(cls, *args, **kwargs):
        return cls._query_from_args_(args, kwargs)


    def create_table(cls):


        # print(cls.attrs, cls.table_name)
        primary_keys = []
        fields = []
        # sql = f'CREATE TABLE `{cls.table_name}`\n(\n'
        for attr in cls.attrs:
            # print(attr.title, attr.name)
            # fields.append(f'`{attr.name}` {attr.title}')
            fields.append((attr.name, attr.ydb_type))
            if attr.pk:
                primary_keys.append(attr.name)
        if not primary_keys:
            raise (Exception, 'no primary key')
        cls._database_.create_table(cls.table_name, fields, primary_keys)
        # fields.append(f"PRIMARY KEY ({', '.join(primary_keys)})")
        # sql = f'''CREATE TABLE `{cls.table_name}`
        # (
        #     {", ".join(fields)}
        # );
        # '''
        # cls._database_.query_(sql)