from sqlalchemy import Column, Integer, inspect
from sqlalchemy.ext.declarative import as_declarative, declared_attr

@as_declarative()
class Base(object):
    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

    __table_args__ = {
        'mysql_engine': 'InnoDB',
        'mysql_charset': 'utf8',
    }

    id = Column(Integer, primary_key=True)

    @classmethod
    def get_or_create(cls, session, **kwargs):
        instance = session.query(cls).filter_by(**kwargs).first()
        if not instance:
            instance = cls(**kwargs)
            session.add(instance)
        return instance

    # TODO: maybe this should be in the association proxy object?
    def sync_m2m_proxy(self, m2m_attr_proxy, list_):
        m2m_proxy = getattr(self, m2m_attr_proxy)
        m2m_proxy_class = getattr(self.__class__, m2m_attr_proxy)
        remote_attr_key = m2m_proxy_class.remote_attr.key
        local_attr_key = m2m_proxy_class.local_attr.key
        target_class = m2m_proxy_class.target_class
        m2m = getattr(self, local_attr_key)
        session = inspect(self).session

        list_ = set(list_)
        list_current = set([getattr(i, remote_attr_key) for i in m2m])

        for i in list_:
            if i not in list_current:
                kwargs_ = dict(
                    session=session
                )
                kwargs_[remote_attr_key] = i
                m2m.append(target_class.get_or_create(**kwargs_))

        for i in list_current:
            if i not in list_:
                m2m_proxy.remove(i)
