# /opt/trueconf_bot/utils/ad_search.py
# Универсальный поиск пользователей по нескольким OU в AD.
# Каждая функция принимает user_id/email/логин и ищет по всем OU из AD_BASES.
# Возвращает первую найденную запись (ldap3 Entry) или None.

from ldap3 import Server, Connection, ALL
from ldap3.utils.conv import escape_filter_chars
import config.config as config


def _get_conn():
    """Создать соединение с AD."""
    server = Server(config.AD_SERVER, get_info=ALL)
    return Connection(server, user=config.AD_USER, password=config.AD_PASSWORD, auto_bind=True)


def search_by_login(login: str, attributes: list[str] | None = None) -> list:
    """
    Найти пользователя по sAMAccountName во всех OU из AD_BASES.
    Возвращает список Entry (обычно 0 или 1).
    """
    attrs = attributes or ["cn", "sAMAccountName"]
    conn = _get_conn()
    for base in config.AD_BASES:
        conn.search(
            search_base=base,
            search_filter="({}={})".format("sAMAccountName", login),
            attributes=attrs,
        )
        if conn.entries:
            return list(conn.entries)
    return []


def search_by_user_id(user_id: str, attributes: list[str] | None = None) -> list:
    """
    Найти пользователя по email/UPN/sAMAccountName во всех OU из AD_BASES.
    Возвращает список Entry (обычно 0 или 1).
    """
    attrs = attributes or ["cn", "sAMAccountName", "mail", "userPrincipalName", "extensionAttribute2"]
    safe_id = escape_filter_chars(user_id)
    short_username = user_id.split("@")[0] if "@" in user_id else user_id
    safe_sam = escape_filter_chars(short_username)

    # Строим LDAP filter: (&(objectClass=user)(|(mail=...)(userPrincipalName=...)(sAMAccountName=...)))
    or_parts = [
        "(mail={})".format(safe_id),
        "(userPrincipalName={})".format(safe_id),
        "(userPrincipalName={})".format(short_username + "@sibcem.ru"),
        "(sAMAccountName={})".format(safe_sam),
    ]
    or_filter = "(|{})".format("".join(or_parts))
    search_filter = "(&{}{})".format("(objectClass=user)", or_filter)

    conn = _get_conn()
    for base in config.AD_BASES:
        conn.search(search_base=base, search_filter=search_filter, attributes=attrs)
        if conn.entries:
            return list(conn.entries)
    return []


def search_by_filter(search_filter: str, attributes: list[str]) -> list:
    """
    Найти по произвольному LDAP-фильтру во всех OU из AD_BASES.
    Возвращает список Entry.
    """
    conn = _get_conn()
    for base in config.AD_BASES:
        conn.search(search_base=base, search_filter=search_filter, attributes=attributes)
        if conn.entries:
            return list(conn.entries)
    return []
