package com.admanager;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

public class ADLdapAnonymousConnector implements AutoCloseable {

    private LdapContext ldapContext;
    private final String domain;
    private final String ldapUrl;
    private final String baseDn;

    public ADLdapAnonymousConnector(String domain, String ldapUrl) {
        this.domain = domain;
        this.ldapUrl = ldapUrl;
        this.baseDn = convertDomainToDn(domain);
    }

    public void connect() throws NamingException {
        Hashtable<String, Object> env = new Hashtable<>();

        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, ldapUrl);
        env.put(Context.SECURITY_AUTHENTICATION, "none");

        // 重要：添加连接池和超时设置
        env.put("com.sun.jndi.ldap.connect.pool", "true"); // 启用连接池
        env.put("com.sun.jndi.ldap.connect.timeout", "3000");
        env.put("com.sun.jndi.ldap.read.timeout", "5000");

        this.ldapContext = new InitialLdapContext(env, null);
        System.out.println("成功匿名连接到: " + domain);
    }

    public List<SearchResult> search(String filter) throws NamingException {
        return search(baseDn, filter, null);
    }

    public List<SearchResult> search(String searchBase, String filter, String[] attributes)
            throws NamingException {
        checkConnected();

        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        controls.setCountLimit(100); // 限制返回数量

        if (attributes != null) {
            controls.setReturningAttributes(attributes);
        }

        // 使用新上下文避免连接被关闭
        try {
            LdapContext searchContext = (LdapContext) ldapContext.lookup("");
            List<SearchResult> results = new ArrayList<>();
            NamingEnumeration<SearchResult> searchResults =
                    searchContext.search(searchBase, filter, controls);

            while (searchResults.hasMore()) {
                results.add(searchResults.next());
            }
            return results;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    @Override
    public void close() throws NamingException {
        if (ldapContext != null) {
            ldapContext.close();
            ldapContext = null;
            System.out.println("连接已关闭");
        }
    }

    private void checkConnected() throws NamingException {
        if (ldapContext == null) {
            throw new NamingException("未建立连接");
        }
    }

    private static String convertDomainToDn(String domain) {
        return "dc=" + domain.replace(".", ",dc=");
    }

    public static void main(String[] args) {
        String domain = "tlct.com.cn";
        String ldapUrl = "ldap://admserver.tlct.com.cn:389";

        try (ADLdapAnonymousConnector connector = new ADLdapAnonymousConnector(domain, ldapUrl)) {
            connector.connect();

            // 测试查询
            List<SearchResult> users = connector.search("(objectClass=user)");
            System.out.println("找到 " + users.size() + " 个用户");

            for (SearchResult user : users) {
                System.out.println("DN: " + user.getNameInNamespace());
            }

        } catch (NamingException e) {
            System.err.println("操作失败: " + e.getMessage());
            if (e.getRootCause() != null) {
                System.err.println("根本原因: " + e.getRootCause().getMessage());
            }
            e.printStackTrace();
        }
    }
}
