import os
import logging
from ldap3 import Server, Connection, ALL
from typing import List

from ad_api import DEFAULT_LOGGER, log_it


class LdapConnection():
    """
    An Ldap LdapConnection.
    """
    def __init__(self,
                 server: str,
                 username: str,
                 password: str,
                 port: str,
                 use_ssl: bool = False,
                 logger: logging.Logger = None):
        self._logger = logger or DEFAULT_LOGGER,
        self._server = server,
        self._username = username,
        self._password = password,
        self._port = port,
        self._use_ssl = use_ssl
        
    @log_it
    def connect(self):
        self._server_internal = Server(host=self._server, port=int(self._port), use_ssl=self._use_ssl, get_info=ALL)
        self._logger.info(f"Attempting to connect to ldap server {self._server_internal}...")
        self._connection = Connection(server=self._server_internal,
                                      user=self._username,
                                      password=self._password,
                                      # client_strategy=SAFE_SYNC, breaks 4-valued return from search
                                      # no need for thread safety anyway
                                      auto_bind=True,
                                      auto_range=True)
        self._logger.info(f"Connected to {self._server_internal}")
        # Connect to this FQDN with LDAPS
        #
        # 1. ldaps-peroot-ww.pearson.com (must be external DNS server) - AWS Lambda can handle this
        # 2. Need a NAS VPC that has an IP that the ldap service will accept

    @log_it
    def disconnect(self):
        self._logger.info(f"Unbound from {self._server_internal}")
        self._connection.unbind()
    
    @log_it
    def search(self, search_base: str, search_filter: str, attributes: List[str], paged_size: int = 100):
        """AD LDAP3 connection.search command with pagination

        Args:
            search_base (str): ex. 'DC=PEROOT,DC=com'
            search_filter (str): ex. '(&(!(info=*Termination*))(objectClass=user)(objectClass=person)(objectClass=organizationalPerson)(mail=*@pearson.com))'
            attributes (List[str]): ex. ['mail','company']
            paged_size (int, optional): results per page. Defaults to 100.

        Returns:
            [type]: [description]
        """
        search_parameters = {
            'search_base': search_base,
            'search_filter': search_filter,
            'attributes': attributes,
            'paged_size': paged_size
        }
        response = []

        while True:
            self._connection.search(**search_parameters)
            response.extend([x for x in self._connection.entries])
            cookie = self._connection.result['controls']['1.2.840.113556.1.4.319']['value']['cookie']
            if cookie:
                search_parameters['paged_cookie'] = cookie
            else:
                break
        
        return response
