# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest

from sqlalchemy import (
    Column,
    Integer,
    Text
)

from aria import (
    application_model_storage,
    modeling
)
from aria.storage import (
    ModelStorage,
    exceptions,
    sql_mapi,
)

from tests import (
    mock,
    storage as tests_storage,
    modeling as tests_modeling
)


@pytest.fixture
def storage():
    base_storage = ModelStorage(sql_mapi.SQLAlchemyModelAPI,
                                initiator=tests_storage.init_inmemory_model_storage)
    base_storage.register(tests_modeling.MockModel)
    yield base_storage
    tests_storage.release_sqlite_storage(base_storage)


@pytest.fixture(scope='module', autouse=True)
def module_cleanup():
    modeling.models.aria_declarative_base.metadata.remove(tests_modeling.MockModel.__table__)  #pylint: disable=no-member


def test_storage_base(storage):
    with pytest.raises(AttributeError):
        storage.non_existent_attribute()


def test_model_storage(storage):
    mock_model = tests_modeling.MockModel(value=0, name='model_name')
    storage.mock_model.put(mock_model)

    assert storage.mock_model.get_by_name('model_name') == mock_model

    assert [mm_from_storage for mm_from_storage in storage.mock_model.iter()] == [mock_model]
    assert [mm_from_storage for mm_from_storage in storage.mock_model] == [mock_model]

    storage.mock_model.delete(mock_model)
    with pytest.raises(exceptions.StorageError):
        storage.mock_model.get(mock_model.id)


def test_application_storage_factory():
    storage = application_model_storage(sql_mapi.SQLAlchemyModelAPI,
                                        initiator=tests_storage.init_inmemory_model_storage)

    assert storage.service_template
    assert storage.node_template
    assert storage.group_template
    assert storage.policy_template
    assert storage.substitution_template
    assert storage.substitution_template_mapping
    assert storage.requirement_template
    assert storage.relationship_template
    assert storage.capability_template
    assert storage.interface_template
    assert storage.operation_template
    assert storage.artifact_template

    assert storage.service
    assert storage.node
    assert storage.group
    assert storage.policy
    assert storage.substitution
    assert storage.substitution_mapping
    assert storage.relationship
    assert storage.capability
    assert storage.interface
    assert storage.operation
    assert storage.artifact

    assert storage.execution
    assert storage.service_update
    assert storage.service_update_step
    assert storage.service_modification
    assert storage.plugin
    assert storage.task

    assert storage.parameter
    assert storage.type
    assert storage.metadata

    tests_storage.release_sqlite_storage(storage)


def test_cascade_deletion(context):
    service = context.model.service.list()[0]

    assert len(context.model.service_template.list()) == 1
    assert len(service.nodes) == len(context.model.node.list()) == 2

    context.model.service.delete(service)

    assert len(context.model.service_template.list()) == 1
    assert len(context.model.service.list()) == 0
    assert len(context.model.node.list()) == 0


@pytest.fixture
def context(tmpdir):
    result = mock.context.simple(str(tmpdir))
    yield result
    tests_storage.release_sqlite_storage(result.model)


def test_mapi_include(context):
    service1 = context.model.service.list()[0]
    service1.name = 'service1'
    service1.service_template.name = 'service_template1'
    context.model.service.update(service1)

    service_template2 = mock.models.create_service_template('service_template2')
    service2 = mock.models.create_service(service_template2, 'service2')
    context.model.service.put(service2)

    assert service1 != service2
    assert service1.service_template != service2.service_template

    def assert_include(service):
        st_name = context.model.service.get(service.id, include=('service_template_name',))
        st_name_list = context.model.service.list(filters={'id': service.id},
                                                  include=('service_template_name', ))
        assert len(st_name) == len(st_name_list) == 1
        assert st_name[0] == st_name_list[0][0] == service.service_template.name

    assert_include(service1)
    assert_include(service2)


class MockModel(modeling.models.aria_declarative_base, modeling.mixins.ModelMixin): #pylint: disable=abstract-method
    __tablename__ = 'op_mock_model'

    name = Column(Text)
    value = Column(Integer)


class TestFilterOperands(object):

    @pytest.fixture()
    def storage(self):
        model_storage = application_model_storage(
            sql_mapi.SQLAlchemyModelAPI, initiator=tests_storage.init_inmemory_model_storage)
        model_storage.register(MockModel)
        for value in (1, 2, 3, 4):
            model_storage.op_mock_model.put(MockModel(value=value))
        yield model_storage
        tests_storage.release_sqlite_storage(model_storage)

    def test_gt(self, storage):
        assert len(storage.op_mock_model.list(filters=dict(value=dict(gt=3)))) == 1
        assert len(storage.op_mock_model.list(filters=dict(value=dict(gt=4)))) == 0

    def test_ge(self, storage):
        assert len(storage.op_mock_model.list(filters=dict(value=dict(ge=3)))) == 2
        assert len(storage.op_mock_model.list(filters=dict(value=dict(ge=5)))) == 0

    def test_lt(self, storage):
        assert len(storage.op_mock_model.list(filters=dict(value=dict(lt=2)))) == 1
        assert len(storage.op_mock_model.list(filters=dict(value=dict(lt=1)))) == 0

    def test_le(self, storage):
        assert len(storage.op_mock_model.list(filters=dict(value=dict(le=2)))) == 2
        assert len(storage.op_mock_model.list(filters=dict(value=dict(le=0)))) == 0

    def test_eq(self, storage):
        assert len(storage.op_mock_model.list(filters=dict(value=dict(eq=2)))) == 1
        assert len(storage.op_mock_model.list(filters=dict(value=dict(eq=0)))) == 0

    def test_neq(self, storage):
        assert len(storage.op_mock_model.list(filters=dict(value=dict(ne=2)))) == 3

    def test_gt_and_lt(self, storage):
        assert len(storage.op_mock_model.list(filters=dict(value=dict(gt=1, lt=3)))) == 1
        assert len(storage.op_mock_model.list(filters=dict(value=dict(gt=2, lt=2)))) == 0

    def test_eq_and_ne(self, storage):
        assert len(storage.op_mock_model.list(filters=dict(value=dict(eq=1, ne=3)))) == 1
        assert len(storage.op_mock_model.list(filters=dict(value=dict(eq=1, ne=1)))) == 0
