# Copyright (C) 2019 by eHealth Africa : http://www.eHealthAfrica.org
#
# See the NOTICE file distributed with this work for additional information
# regarding copyright ownership.
#
# Licensed 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 json
import pytest
import requests
import responses
from time import sleep

from elasticsearch.exceptions import NotFoundError

from aet.logger import get_logger


from app import index_handler

from . import *  # noqa  # fixtures


LOG = get_logger('TEST-IDX')


# convenience function for jsonpath

@responses.activate
@pytest.mark.unit
def test__handle_http():
    responses.add(
        responses.GET,
        'http://bad-url',
        json={'error': 'not found'},
        status=404
    )
    res = requests.get('http://bad-url')
    with pytest.raises(requests.exceptions.HTTPError):
        index_handler.handle_http(res)


@pytest.mark.unit
def test__get_es_index_from_autoconfig(SubscriptionDefinition, ComplexSchema):
    es_options = SubscriptionDefinition.get('es_options')
    tenant = 'dev'
    name = 'a-topic'
    alias = es_options.get('alias_name')
    index = index_handler.get_es_index_from_subscription(
        es_options, name, tenant, ComplexSchema
    )
    LOG.debug(json.dumps(index, indent=2))
    assert(first('$.name', index) == f'{tenant}.{name}')
    geo_name = es_options['geo_point_name']
    assert(first(
        f'$.body.mappings._doc.properties.{geo_name}', index) is not None)


@pytest.mark.unit
def test__get_index_for_topic(SubscriptionDefinition, ComplexSchema):
    name = 'Person'
    es_options = SubscriptionDefinition.get('es_options')
    geo_name = es_options.get('geo_point_name')
    auto_ts = es_options.get('auto_timestamp')
    index = index_handler.get_index_for_topic(name, geo_name, auto_ts, ComplexSchema)
    index = index.get('mappings', None)
    assert(len(index) == 1)
    assert(first('$._doc', index) is not None)
    assert(first(f'$._doc.properties.{geo_name}.type', index) == 'geo_point')
    assert(first(f'$._doc._meta.aet_auto_ts', index) == auto_ts)


@pytest.mark.unit
def test__get_es_types_from_schema(ComplexSchema):
    res = index_handler.get_es_types_from_schema(ComplexSchema)
    assert(first('$.beds.type', res) == 'integer')
    assert(first('$.username.type', res) == 'keyword')
    assert(first('$._start.type', res) == 'date')
    assert(first('$.geometry.type', res) == 'object')
    assert(first('$.meta.type', res) == 'object')
    assert(first('$.mandatory_date.type', res) == 'date')
    assert(first('$.mandatory_date.format', res) == 'date')
    assert(first('$.optional_dt.type', res) == 'date')
    assert(first('$.optional_dt.format', res) == 'epoch_millis')
    assert(len(list(res.keys())) == 55)


@pytest.mark.unit
def test__make_kibana_index(AutoGenSchema):
    name = 'kibana-index-name'
    res = index_handler.make_kibana_index(name, AutoGenSchema)
    assert(res.get('attributes', {}).get('title') == name)


@pytest.mark.unit
def test___find_timestamp(ComplexSchema):
    result = index_handler._find_timestamp(ComplexSchema)
    assert(result == 'timestamp')


@pytest.mark.unit
def test___format_lookups(ComplexSchema):
    formatted = index_handler._format_lookups(ComplexSchema)
    assert(
        json.dumps(
            formatted.get(
                'operational_status'), sort_keys=True) ==
        json.dumps(
            SAMPLE_FIELD_LOOKUP.get(
                'operational_status'), sort_keys=True)
    )


@pytest.mark.unit
def test___format_single_lookup(ComplexSchema):
    matching = ComplexSchema.get_node('MySurvey.operational_status')
    res = index_handler._format_single_lookup(matching)
    assert(
        json.dumps(res, sort_keys=True) ==
        json.dumps(SAMPLE_FIELD_LOOKUP.get(
            'operational_status'), sort_keys=True)
    )


@pytest.mark.unit
def test__get_alias_from_namespace():
    namespace = 'A_Gather_Form_V1'
    res = index_handler.get_alias_from_namespace(namespace)
    assert(res == 'A_Gather_Form')


@pytest.mark.integration
def test__update_es_index(TestElasticsearch, PolySchemaA, PolySchemaB):
    # register index with mapping
    es = TestElasticsearch.get_session()
    doc_id = 'poly-test-doc'
    doc = {
        'id': doc_id,
        'poly': '1001'
    }

    index_a = index_handler.get_es_index_from_subscription(
        es_options={},
        name='test1',
        tenant='test-tenant',
        schema=PolySchemaA
    )
    index_name = index_a.get('name')
    index_b = index_handler.get_es_index_from_subscription(
        es_options={},
        name='test1',
        tenant='test-tenant',
        schema=PolySchemaB
    )
    alias = index_handler.get_alias_from_namespace(PolySchemaA.name)
    # register schema A
    index_handler.update_es_index(es, index_a, 'test-tenant', alias)
    # put doc
    es.create(
        index=index_name,
        id=doc_id,
        body=doc
    )
    es.indices.refresh(index=index_name)
    res = es.search(index=index_name, body={
        "query": {"term": {"poly": "1001"}}
    })
    assert(res.get('hits').get('max_score') < 1.0)  # find imperfect by string
    res = es.search(index=index_name, body={
        "query": {"term": {"poly": 1001}}
    })
    assert(res.get('hits').get('max_score') < 1.0)  # find imperfect by string

    # migrate to schema B
    index_handler.update_es_index(es, index_b, 'test-tenant', alias)
    es.indices.refresh(index=index_name)

    res = es.search(index=index_name, body={
        "query": {"term": {"poly": "1001"}}
    })
    assert(res.get('hits').get('max_score') == 1.0)  # find by string
    res = es.search(index=index_name, body={
        "query": {"term": {"poly": 1001}}
    })
    assert(res.get('hits').get('max_score') == 1.0)  # find by int

[((35, 6, 35, 28), 'aet.logger.get_logger', 'get_logger', ({(35, 17, 35, 27): '"""TEST-IDX"""'}, {}), "('TEST-IDX')", False, 'from aet.logger import get_logger\n'), ((43, 4, 48, 5), 'responses.add', 'responses.add', (), '', False, 'import responses\n'), ((49, 10, 49, 40), 'requests.get', 'requests.get', ({(49, 23, 49, 39): '"""http://bad-url"""'}, {}), "('http://bad-url')", False, 'import requests\n'), ((60, 12, 62, 5), 'app.index_handler.get_es_index_from_subscription', 'index_handler.get_es_index_from_subscription', ({(61, 8, 61, 18): 'es_options', (61, 20, 61, 24): 'name', (61, 26, 61, 32): 'tenant', (61, 34, 61, 47): 'ComplexSchema'}, {}), '(es_options, name, tenant,\n    ComplexSchema)', False, 'from app import index_handler\n'), ((76, 12, 76, 85), 'app.index_handler.get_index_for_topic', 'index_handler.get_index_for_topic', ({(76, 46, 76, 50): 'name', (76, 52, 76, 60): 'geo_name', (76, 62, 76, 69): 'auto_ts', (76, 71, 76, 84): 'ComplexSchema'}, {}), '(name, geo_name, auto_ts, ComplexSchema)', False, 'from app import index_handler\n'), ((86, 10, 86, 63), 'app.index_handler.get_es_types_from_schema', 'index_handler.get_es_types_from_schema', ({(86, 49, 86, 62): 'ComplexSchema'}, {}), '(ComplexSchema)', False, 'from app import index_handler\n'), ((102, 10, 102, 62), 'app.index_handler.make_kibana_index', 'index_handler.make_kibana_index', ({(102, 42, 102, 46): 'name', (102, 48, 102, 61): 'AutoGenSchema'}, {}), '(name, AutoGenSchema)', False, 'from app import index_handler\n'), ((108, 13, 108, 57), 'app.index_handler._find_timestamp', 'index_handler._find_timestamp', ({(108, 43, 108, 56): 'ComplexSchema'}, {}), '(ComplexSchema)', False, 'from app import index_handler\n'), ((114, 16, 114, 60), 'app.index_handler._format_lookups', 'index_handler._format_lookups', ({(114, 46, 114, 59): 'ComplexSchema'}, {}), '(ComplexSchema)', False, 'from app import index_handler\n'), ((128, 10, 128, 55), 'app.index_handler._format_single_lookup', 'index_handler._format_single_lookup', ({(128, 46, 128, 54): 'matching'}, {}), '(matching)', False, 'from app import index_handler\n'), ((139, 10, 139, 59), 'app.index_handler.get_alias_from_namespace', 'index_handler.get_alias_from_namespace', ({(139, 49, 139, 58): 'namespace'}, {}), '(namespace)', False, 'from app import index_handler\n'), ((153, 14, 158, 5), 'app.index_handler.get_es_index_from_subscription', 'index_handler.get_es_index_from_subscription', (), '', False, 'from app import index_handler\n'), ((160, 14, 165, 5), 'app.index_handler.get_es_index_from_subscription', 'index_handler.get_es_index_from_subscription', (), '', False, 'from app import index_handler\n'), ((166, 12, 166, 68), 'app.index_handler.get_alias_from_namespace', 'index_handler.get_alias_from_namespace', ({(166, 51, 166, 67): 'PolySchemaA.name'}, {}), '(PolySchemaA.name)', False, 'from app import index_handler\n'), ((168, 4, 168, 68), 'app.index_handler.update_es_index', 'index_handler.update_es_index', ({(168, 34, 168, 36): 'es', (168, 38, 168, 45): 'index_a', (168, 47, 168, 60): '"""test-tenant"""', (168, 62, 168, 67): 'alias'}, {}), "(es, index_a, 'test-tenant', alias)", False, 'from app import index_handler\n'), ((186, 4, 186, 68), 'app.index_handler.update_es_index', 'index_handler.update_es_index', ({(186, 34, 186, 36): 'es', (186, 38, 186, 45): 'index_b', (186, 47, 186, 60): '"""test-tenant"""', (186, 62, 186, 67): 'alias'}, {}), "(es, index_b, 'test-tenant', alias)", False, 'from app import index_handler\n'), ((50, 9, 50, 53), 'pytest.raises', 'pytest.raises', ({(50, 23, 50, 52): 'requests.exceptions.HTTPError'}, {}), '(requests.exceptions.HTTPError)', False, 'import pytest\n'), ((51, 8, 51, 38), 'app.index_handler.handle_http', 'index_handler.handle_http', ({(51, 34, 51, 37): 'res'}, {}), '(res)', False, 'from app import index_handler\n'), ((63, 14, 63, 41), 'json.dumps', 'json.dumps', (), '', False, 'import json\n'), ((130, 8, 130, 39), 'json.dumps', 'json.dumps', (), '', False, 'import json\n')]