from collections.abc import Callable
from typing import Any
from unittest.mock import MagicMock, Mock

import pytest
from ldap3 import Connection
from ldap3.core.exceptions import LDAPSocketOpenError
from pytest import MonkeyPatch

from mex.common.ldap.connector import LDAPConnector

PagedSearchResults = list[list[dict[str, Any]]]
LDAPMocker = Callable[[PagedSearchResults], None]


SAMPLE_PERSON_ATTRS = {
    "company": ["RKI"],
    "department": ["XY"],
    "departmentNumber": ["XY2"],
    "displayName": ["Sample, Sam"],
    "employeeID": ["1024"],
    "givenName": ["Sam"],
    "mail": ["SampleS@mail.tld"],
    "objectGUID": ["{00000000-0000-4000-8000-000000000000}"],
    "ou": ["XY"],
    "sAMAccountName": ["SampleS"],
    "sn": ["Sample"],
}

XY_FUNC_ACCOUNT_ATTRS = {
    "mail": ["XY@mail.tld"],
    "objectGUID": ["{00000000-0000-4000-8000-000000000044}"],
    "sAMAccountName": ["XY"],
    "ou": ["Funktion"],
}

XY2_FUNC_ACCOUNT_ATTRS = {
    "mail": ["XY2@mail.tld"],
    "objectGUID": ["{00000000-0000-4000-8000-000000000045}"],
    "sAMAccountName": ["XY2"],
    "ou": ["Funktion"],
}


@pytest.fixture
def ldap_mocker(monkeypatch: MonkeyPatch) -> LDAPMocker:
    """Patch the LDAP connector to return `SAMPLE_PERSON_ATTRS` from its connection."""

    def mocker(results: PagedSearchResults) -> None:
        def __init__(self: LDAPConnector) -> None:
            self._search_base = "DC=foo"
            self._connection = MagicMock(spec=Connection, extend=Mock())
            self._connection.extend.standard.paged_search = MagicMock(
                side_effect=[
                    [{"attributes": e} for e in entries] for entries in results
                ]
            )

        monkeypatch.setattr(LDAPConnector, "__init__", __init__)

    return mocker


@pytest.fixture(autouse=True)
def skip_ldap_integration_tests_on_connection_error(
    is_integration_test: bool,  # noqa: FBT001
) -> None:
    if is_integration_test:
        try:
            LDAPConnector.get()
        except LDAPSocketOpenError:
            pytest.skip("LDAP unavailable")
