# 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.type_definition
    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.input
    assert storage.output
    assert storage.property
    assert storage.attribute

    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
