"""General fixtures for pytest."""

from pathlib import Path

import pytest
from ldap3 import Server, Connection, MOCK_SYNC, SchemaInfo

from lumi2 import create_app


@pytest.fixture
def app():
    """Returns the lumi2 flask app with a testing configuration."""

    app = create_app({
        'TESTING': True,
        'LDAP_BIND_USER_DN': 'cn=admin,dc=example,dc=com',
        'LDAP_BIND_USER_PASSWORD': 'test',
        'LDAP_BASE_DN': 'dc=example,dc=com',
        'LDAP_USERS_OU': 'ou=users,dc=example,dc=com',
        'LDAP_GROUPS_OU': 'ou=groups,dc=example,dc=com',
        'LDAP_USER_OBJECT_CLASS': 'inetOrgPerson',
        'LDAP_GROUP_OBJECT_CLASS': 'groupOfUniqueNames',
    })

    return app


@pytest.fixture
def client(app):
    """Returns a flask test client."""

    return app.test_client()


@pytest.fixture
def runner(app):
    """Returns a flask test CLI runner."""

    return app.test_cli_runner()


@pytest.fixture
def connection_empty_dit():
    """Returns a bound connection to a mock LDAP server whose DIT is empty.

    Returns
    -------
    ldap3.Connection
        An active and bound connection to a mock LDAP server.
    """

    dir_path = Path(__file__).absolute().parent
    schema_path = dir_path / "ldap_mock_server_schema.json"
    entries_path = dir_path / "ldap_mock_server_entries.json"

    server = Server('mockserver')
    schema_info = SchemaInfo.from_file(str(schema_path))
    server.attach_schema_info(schema_info)

    connection = Connection(
        server,
        user='cn=admin,dc=example,dc=com',
        password='admin',
        client_strategy=MOCK_SYNC,
    )

    # Add admin entry for simple binding
    connection.strategy.add_entry(
        'cn=admin,dc=example,dc=com',
        {'userPassword': 'admin', 'sn': 'admin'}
    )

    connection.bind()

    yield connection

    connection.unbind()


@pytest.fixture
def connection():
    """Returns a bound connection to a mock LDAP server whose DIT is populated.

    The server's DIT contains the following entries:
    * dc=example,dc=com
    ├── * ou=users
    │   ├── * uid=alice
    │   └── * uid=bobbuilder
    └── * ou=groups
        ├── * cn=employees
        └── * cn=admins

    Both users are of type 'inetOrgPerson' and have the following attributes set:
    - uid (username)
    - cn (first name)
    - sn (last name)
    - displayName (nickname)
    - mail (email)
    - jpegPhoto (profile picture)
    - password (sha512 hash of password 'test')

    Both groups are of type 'groupOfUniqueNames'. Alice is a member of both
    groups. Bob is a member of 'employees'.

    Returns
    -------
    ldap3.Connection
        An active and bound connection to the a LDAP server.
    """

    dir_path = Path(__file__).absolute().parent
    schema_path = dir_path / "ldap_mock_server_schema.json"
    entries_path = dir_path / "ldap_mock_server_entries.json"

    server = Server('mockserver')
    schema_info = SchemaInfo.from_file(str(schema_path))
    server.attach_schema_info(schema_info)

    connection = Connection(
        server,
        user='cn=admin,dc=example,dc=com',
        password='admin',
        client_strategy=MOCK_SYNC,
    )

    # Add admin entry for simple binding
    connection.strategy.add_entry(
        'cn=admin,dc=example,dc=com',
        {'userPassword': 'admin', 'sn': 'admin'}
    )
    # Add entries from JSON file
    connection.strategy.entries_from_json(entries_path)

    connection.bind()

    yield connection

    connection.unbind()
