from io import BytesIO
from urllib.parse import parse_qsl, urlparse

import django_webtest
import pytest
from django.contrib.auth.models import User
from django.core.cache import cache
from django.core.files import File
from httmock import HTTMock, remember_called, response, urlmatch

from tests.utils import make_resource


@pytest.fixture(autouse=True)
def media(settings, tmpdir):
    settings.MEDIA_ROOT = str(tmpdir.mkdir('media'))


@pytest.fixture
def app(request):
    wtm = django_webtest.WebTestMixin()
    wtm._patch_settings()
    request.addfinalizer(wtm._unpatch_settings)
    cache.clear()
    return django_webtest.DjangoTestApp()


@urlmatch(netloc='^api-adresse.data.gouv.fr$', path='^/search/$')
@remember_called
def api_adresse_data_gouv_fr_search(url, request):
    return response(
        200,
        {
            "limit": 1,
            "attribution": "BAN",
            "version": "draft",
            "licence": "ODbL 1.0",
            "query": "plop",
            "type": "FeatureCollection",
            "features": [
                {
                    "geometry": {"type": "Point", "coordinates": [-0.593775, 47.474633]},
                    "properties": {
                        "citycode": "49007",
                        "name": "Rue Roger Halope",
                        "id": "49007_6950_be54bd",
                        "city": "Angers",
                        "context": "49, Maine-et-Loire, Pays de la Loire",
                        "score": 0.14097272727272728,
                        "label": "Rue Roger Halope 49000 Angers",
                        "postcode": "49000",
                        "type": "street",
                    },
                    "type": "Feature",
                }
            ],
        },
        request=request,
    )


@urlmatch(netloc='^api-adresse.data.gouv.fr$', path='^/reverse/$')
@remember_called
def api_adresse_data_gouv_fr_reverse(url, request):
    return response(
        200,
        {
            "limit": 1,
            "attribution": "BAN",
            "version": "draft",
            "licence": "ODbL 1.0",
            "type": "FeatureCollection",
            "features": [
                {
                    "geometry": {"type": "Point", "coordinates": [-0.593775, 47.474633]},
                    "properties": {
                        "citycode": "49007",
                        "name": "Rue Roger Halope",
                        "id": "49007_6950_be54bd",
                        "city": "Angers",
                        "distance": 0,
                        "context": "49, Maine-et-Loire, Pays de la Loire",
                        "score": 1.0,
                        "label": "Rue Roger Halope 49000 Angers",
                        "postcode": "49000",
                        "type": "street",
                    },
                    "type": "Feature",
                }
            ],
        },
        request=request,
    )


@pytest.fixture
def mock_api_adresse_data_gouv_fr_search():
    with HTTMock(api_adresse_data_gouv_fr_search):
        yield api_adresse_data_gouv_fr_search


@pytest.fixture
def mock_api_adresse_data_gouv_fr_reverse():
    with HTTMock(api_adresse_data_gouv_fr_reverse):
        yield api_adresse_data_gouv_fr_reverse


@pytest.fixture
def endpoint_dummy_cache(monkeypatch):
    from django.core.cache import caches

    import passerelle.views

    monkeypatch.setattr(passerelle.views, 'cache', caches['dummy'])


@urlmatch()
def internal_server_error(url, request):
    return response(500, 'Internal server error')


@pytest.fixture
def mock_500():
    with HTTMock(internal_server_error):
        yield None


@pytest.fixture
def dummy_csv_datasource(db):
    from passerelle.apps.csvdatasource.models import CsvDataSource, Query

    data = b'''id,label
1,a
2,b
3,c'''
    obj = make_resource(
        CsvDataSource,
        slug='dummy-slug',
        title='Dummy Title',
        description='dummy description',
        csv_file=File(BytesIO(data), 'dummy.csv'),
    )

    Query.objects.create(
        resource=obj,
        slug='dummy-query',
        structure='array',
        label='Dummy Query',
        description='dummy query description',
        projections='id:int(id)\ntext:label',
    )

    return obj


@pytest.fixture
def relax_openssl(tmpdir):
    """OpenSSL default configuration has been really strict for some years,
    this fixture set a temporary really permisive ciphers list."""
    import os

    openssl_cnf_path = tmpdir / 'openssl.cnf'
    with openssl_cnf_path.open('w') as fd:
        fd.write(
            '''
[default_conf]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
CipherString = ALL'''
        )
    old_value = os.environ.get('OPENSSL_CONF', None)
    try:
        os.environ['OPENSSL_CONF'] = str(openssl_cnf_path)
        yield
    finally:
        if old_value is None:
            del os.environ['OPENSSL_CONF']
        else:
            os.environ['OPENSSL_CONF'] = old_value


@pytest.fixture(autouse=True)
def clear_cache():
    from zeep.cache import InMemoryCache

    # prevent silent change in zeep private interface
    assert InMemoryCache._cache == {}

    InMemoryCache._cache = {}
    try:
        yield
    finally:
        InMemoryCache._cache = {}

    cache.clear()


@pytest.fixture
def simple_user(db):
    return User.objects.create_user('user', password='user')


@pytest.fixture
def admin_user(db):
    return User.objects.create_superuser('admin', email=None, password='admin')


@pytest.fixture
def httpbin():
    @urlmatch(netloc=r'^httpbin\.org$', path=r'^/cookies/set$')
    def httpbin_cookies_set(url, request):
        headers = []
        cookies = {}
        for key, value in parse_qsl(urlparse(request.url).query):
            cookies[key] = value
            headers.append(('Set-Cookie', f'{key}={value}; Path=/'))
        headers.append(('Location', '/cookies'))
        return response(200, b'', headers=headers, request=request)

    with HTTMock(httpbin_cookies_set) as fixture:
        fixture.url = 'http://httpbin.org'
        yield fixture
