import logging, pytest
from ..api.Database import Database
from ..api.entity._Entity import _Entity
from ..api.entity._RootEntity import _RootEntity
from ..api.entity.EntityAttributes import EntityAttributes
from ..api.Exceptions import WrongDatabaseEngine
from ..engines._DatabaseEngine import _DatabaseEngine
from ..engines.inmemory.InMemoryDatabaseEngine import InMemoryDatabaseEngine

logging.basicConfig(level=logging.INFO)

def test_database_gets_none_database_engine():
    # should fail with invalid database engine
    with pytest.raises(WrongDatabaseEngine) as e:
        Database(None)
    assert str(e.value) == 'database_engine must inherit from _DatabaseEngine'

def test_database_gets_correct_database_engine():
    # should work
    assert Database(InMemoryDatabaseEngine()) is not None

def test_entity_gets_invalid_parameters():

    class RootMockEntity(_RootEntity):
        def __init__(self, database_engine : _DatabaseEngine):
            super().__init__(database_engine, 'valid-uuid', 'valid-key', {}, {})

    # should fail with invalid parent
    with pytest.raises(AttributeError) as e:
        _Entity(None, 'valid-uuid', 'valid-attributes-key', {}, {})
    assert str(e.value) == 'parent must be an instance of _Entity'

    # should fail with invalid entity uuid
    with pytest.raises(AttributeError) as e:
        _Entity(RootMockEntity(InMemoryDatabaseEngine()), None, 'valid-attributes-key', {}, {})
    assert str(e.value) == 'entity_uuid must be a non-empty instance of str'

    # should fail with invalid entity uuid
    with pytest.raises(AttributeError) as e:
        _Entity(RootMockEntity(InMemoryDatabaseEngine()), '', 'valid-attributes-key', {}, {})
    assert str(e.value) == 'entity_uuid must be a non-empty instance of str'

    # should fail with invalid attribute key
    with pytest.raises(AttributeError) as e:
        _Entity(RootMockEntity(InMemoryDatabaseEngine()), 'valid-uuid', None, {}, {})
    assert str(e.value) == 'attributes_key must be a non-empty instance of str'

    # should fail with invalid attribute key
    with pytest.raises(AttributeError) as e:
        _Entity(RootMockEntity(InMemoryDatabaseEngine()), 'valid-uuid', '', {}, {})
    assert str(e.value) == 'attributes_key must be a non-empty instance of str'

    # should fail with invalid attribute validators
    with pytest.raises(AttributeError) as e:
        _Entity(RootMockEntity(InMemoryDatabaseEngine()), 'valid-uuid', 'valid-attributes-key', [], {})
    assert str(e.value) == 'attribute_validators must be an instance of dict'

    # should fail with invalid attribute transcoders
    with pytest.raises(AttributeError) as e:
        _Entity(RootMockEntity(InMemoryDatabaseEngine()), 'valid-uuid', 'valid-attributes-key', {}, [])
    assert str(e.value) == 'attribute_transcoders must be an instance of dict'

    # should work
    assert _Entity(RootMockEntity(InMemoryDatabaseEngine()), 'valid-uuid', 'valid-attributes-key', {}, {}) is not None

def test_entity_attributes_gets_invalid_parameters():

    class RootMockEntity(_RootEntity):
        def __init__(self, database_engine : _DatabaseEngine):
            super().__init__(database_engine, 'valid-uuid', 'valid-key', {}, {})

    # should work
    root_entity = RootMockEntity(InMemoryDatabaseEngine())
    validators = {'attr': lambda v: True}
    entity_attrs = EntityAttributes(root_entity, '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'}"
