import logging, pytest
from common.orm._Database import _Database
from common.orm.backend._Backend import _Backend
from common.orm.backend.inmemory.InMemoryBackend import InMemoryBackend
from common.orm.fields.FloatField import FloatField
from common.orm.fields.IntegerField import IntegerField
from common.orm.fields.PrimaryKeyField import PrimaryKeyField
from common.orm.fields.StringField import StringField
from common.orm.model.Model import Model

logging.basicConfig(level=logging.INFO)

def test_database_instantiation():
    with pytest.raises(AttributeError) as e:
        _Database(None)
    str_class_path = '{}.{}'.format(_Backend.__module__, _Backend.__name__)
    assert str(e.value) == 'backend must inherit from {}'.format(str_class_path)

    assert _Database(InMemoryBackend()) is not None

def test_model_without_attributes():
    with pytest.raises(AttributeError) as e:
        Model(None, 'valid-uuid')
    str_class_path = '{}.{}'.format(Model.__module__, Model.__name__)
    assert str(e.value) == 'parent must inherit from {}'.format(str_class_path)

    database = _Database(InMemoryBackend())

    with pytest.raises(AttributeError) as e:
        Model(database, '')
    assert str(e.value) == 'Unable to set primary_key() since no PrimaryKeyField is defined in the model'

    with pytest.raises(AttributeError) as e:
        Model(database, 'primary-key')
    assert str(e.value) == 'Unable to set primary_key(primary-key) since no PrimaryKeyField is defined in the model'

def test_model_with_primarykey():
    database = _Database(InMemoryBackend())

    class TestModel(Model):
        pk = PrimaryKeyField()
        name = StringField(min_length=1)
        age = IntegerField(min_value=0)
        salary = FloatField(min_value=0.0)

    with pytest.raises(ValueError) as e:
        TestModel(database)
    assert str(e.value) == 'pk(None) is None.'

    with pytest.raises(ValueError) as e:
        TestModel(database, '')
    assert str(e.value) == 'pk() is out of range: allow_empty(False).'

    obj = TestModel(database, 'valid-pk')
    assert obj is not None

def test_model_with_primarykey_and_attributes():
    database = _Database(InMemoryBackend())

    class TestModel(Model):
        pk = PrimaryKeyField()
        name = StringField(min_length=1)
        age = IntegerField(min_value=0)
        salary = FloatField(min_value=0.0)

    with pytest.raises(AttributeError) as e:
        Attributes(obj, None, {}, {})
    assert str(e.value) == 'key_pattern must be a non-empty instance of str'

#    # should fail with invalid attribute key
#    with pytest.raises(AttributeError) as e:
#        Attributes(obj, '', {}, {})
#    assert str(e.value) == 'key_pattern must be a non-empty instance of str'
#
#    # should fail with invalid attribute validators
#    with pytest.raises(AttributeError) as e:
#        Attributes(obj, 'valid-attributes-key', [], {})
#    assert str(e.value) == 'validators must be an instance of dict'
#
#    # should fail with invalid attribute transcoders
#    with pytest.raises(AttributeError) as e:
#        Attributes(obj, 'valid-attributes-key', {}, [])
#    assert str(e.value) == 'transcoders must be an instance of dict'
#
#    # should work
#    attrs = Attributes(obj, 'valid-attributes-key', {}, {})
#    assert attrs is not None

#def testModel_attributes_gets_invalid_parameters():
#    # should work
#    rootModel = _Database(InMemoryBackend())
#    validators = {'attr': lambda v: True}
#    entity_attrs = Attributes(rootModel, 'valid-attributes-key', validators, {})
#    assert entity_attrs is not None
#
#    with pytest.raises(AttributeError) as e:
#        entity_attrs.update(update_attributes={'non-defined-attr': 'random-value'})
#    assert str(e.value) == "Unexpected update_attributes: {'non-defined-attr': 'random-value'}"
#
#    with pytest.raises(AttributeError) as e:
#        entity_attrs.update(remove_attributes=['non-defined-attr'])
#    assert str(e.value) == "Unexpected remove_attributes: {'non-defined-attr'}"
