"""
Pytest fixtures and config.
"""
import asyncio
import email.mime.multipart
import email.mime.text
import ssl
from pathlib import Path

import pytest

from aiosmtplib import SMTP
from aiosmtplib.sync import shutdown_loop

from .mocks import EchoServerProtocol
from .smtpd import RecordingHandler, TestSMTPD


try:
    import uvloop
except ImportError:
    HAS_UVLOOP = False
else:
    HAS_UVLOOP = True
BASE_CERT_PATH = Path("tests/certs/")


def pytest_addoption(parser):
    parser.addoption(
        "--event-loop", action="store", default="asyncio", choices=["asyncio", "uvloop"]
    )


@pytest.fixture(scope="session")
def event_loop_type(request):
    return request.config.getoption("--event-loop")


@pytest.fixture(scope="function")
def event_loop(event_loop_type):
    if event_loop_type == "asyncio":
        loop = asyncio.new_event_loop()
    elif event_loop_type == "uvloop":
        if not HAS_UVLOOP:
            raise RuntimeError("uvloop not installed.")
        loop = uvloop.new_event_loop()
    else:
        raise ValueError("Unknown event loop type: {}".format(event_loop_type))

    yield loop

    shutdown_loop(loop)


@pytest.fixture(scope="session")
def hostname(request):
    return "localhost"


@pytest.fixture(scope="function")
def port(request, unused_tcp_port):
    """Alias for ununsed_tcp_port."""
    return unused_tcp_port


@pytest.fixture(scope="function")
def message(request):
    message = email.mime.multipart.MIMEMultipart()
    message["To"] = "recipient@example.com"
    message["From"] = "sender@example.com"
    message["Subject"] = "A message"
    message.attach(email.mime.text.MIMEText("Hello World"))

    return message


@pytest.fixture(scope="function")
def recieved_messages(request):
    return []


@pytest.fixture(scope="function")
def recieved_commands(request):
    return []


@pytest.fixture(scope="function")
def smtpd_responses(request):
    return []


@pytest.fixture(scope="function")
def smtpd_handler(request, recieved_messages, recieved_commands, smtpd_responses):
    return RecordingHandler(recieved_messages, recieved_commands, smtpd_responses)


@pytest.fixture(scope="session")
def smtpd_class(request):
    return TestSMTPD


@pytest.fixture(scope="session")
def valid_cert_path(request):
    return str(BASE_CERT_PATH.joinpath("selfsigned.crt"))


@pytest.fixture(scope="session")
def valid_key_path(request):
    return str(BASE_CERT_PATH.joinpath("selfsigned.key"))


@pytest.fixture(scope="session")
def invalid_cert_path(request):
    return str(BASE_CERT_PATH.joinpath("invalid.crt"))


@pytest.fixture(scope="session")
def invalid_key_path(request):
    return str(BASE_CERT_PATH.joinpath("invalid.key"))


@pytest.fixture(scope="session")
def client_tls_context(request, valid_cert_path, valid_key_path):
    tls_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
    tls_context.check_hostname = False
    tls_context.verify_mode = ssl.CERT_NONE

    return tls_context


@pytest.fixture(scope="session")
def server_tls_context(request, valid_cert_path, valid_key_path):
    tls_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    tls_context.load_cert_chain(valid_cert_path, keyfile=valid_key_path)

    return tls_context


@pytest.fixture(scope="function")
def smtpd_server(
    request, event_loop, hostname, port, smtpd_class, smtpd_handler, server_tls_context
):
    def factory():
        return smtpd_class(
            smtpd_handler,
            hostname=hostname,
            enable_SMTPUTF8=False,
            tls_context=server_tls_context,
        )

    server = event_loop.run_until_complete(
        event_loop.create_server(factory, host=hostname, port=port)
    )

    def close_server():
        server.close()
        event_loop.run_until_complete(server.wait_closed())

    request.addfinalizer(close_server)

    return server


@pytest.fixture(scope="session")
def smtpd_response_handler(request):
    def smtpd_response(response_text, write_eof=False, close_after=False):
        async def response_handler(smtpd, *args, **kwargs):
            if args and args[0]:
                smtpd.session.host_name = args[0]
            if response_text is not None:
                await smtpd.push(response_text)
            if write_eof:
                smtpd.transport.write_eof()
            if close_after:
                smtpd.transport.close()

        return response_handler

    return smtpd_response


@pytest.fixture(scope="function")
def smtp_client(request, event_loop, hostname, port):
    client = SMTP(hostname=hostname, port=port, loop=event_loop, timeout=1.0)

    return client


@pytest.fixture(scope="function")
def echo_server(request, hostname, port, event_loop):
    server = event_loop.run_until_complete(
        event_loop.create_server(EchoServerProtocol, host=hostname, port=port)
    )

    def close_server():
        server.close()
        event_loop.run_until_complete(server.wait_closed())

    request.addfinalizer(close_server)

@@ -636,20 +636,22 @@
 nt_loop_
-type
+policy
 (request
@@ -657,22 +657,27 @@
 t):%0A    
-return
+loop_type =
  request
@@ -714,386 +714,408 @@
 p%22)%0A
-%0A%0A@pytest.fixture(scope=%22function%22)%0Adef event_loop(event_loop_type):%0A    if event_loop_type == %22asyncio%22:%0A        loop = asyncio.new_event_loop()%0A    elif event_loop_type == %22uvloop%22:%0A        if not HAS_UVLOOP:%0A            raise RuntimeError(%22uvloop not installed.%22)%0A        loop = uvloop.new_event_loop()%0A    else:%0A        raise ValueError(%22Unknown 
+    if loop_type == %22uvloop%22:%0A        if not HAS_UVLOOP:%0A            raise RuntimeError(%22uvloop not installed.%22)%0A        return uvloop.EventLoopPolicy()%0A%0A    return asyncio.get_event_loop_policy()%0A%0A%0A@pytest.fixture(scope=%22function%22)%0Adef event_loop(request, event_loop_policy):%0A    old_loop = event_loop_policy.get_event_loop()%0A%0A    loop = event_loop_policy.new_
 event
- 
+_
 loop
- type: %7B%7D%22.format(
+()%0A    event_loop_policy.set_
 even
@@ -1124,16 +1124,14 @@
 loop
-_type))%0A
+(loop)
 %0A   
@@ -1167,16 +1167,63 @@
 p(loop)%0A
+    event_loop_policy.set_event_loop(old_loop)%0A
 %0A%0A@pytes

Install event loop prior to fixture use