package com.admanager;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
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 ADLdapConnector implements AutoCloseable {

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

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

    /**
     * 匿名连接AD域
     */
    public void connect() throws NamingException {
        Hashtable<String, String> 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("java.naming.ldap.version", "3");
        env.put("com.sun.jndi.ldap.connect.timeout", "5000"); // 5秒连接超时
        env.put("com.sun.jndi.ldap.read.timeout", "10000");   // 10秒读取超时

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

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

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

        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        if (attributes != null && attributes.length > 0) {
            controls.setReturningAttributes(attributes);
        }

        List<SearchResult> results = new ArrayList<>();
        NamingEnumeration<SearchResult> searchResults = ldapContext.search(searchBase, filter, controls);

        while (searchResults.hasMore()) {
            results.add(searchResults.next());
        }

        return results;
    }

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

    private void checkConnected() throws NamingException {
        if (ldapContext == null) {
            throw new NamingException("未连接到AD域，请先调用connect方法");
        }
    }

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

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

        try (ADLdapConnector connector = new ADLdapConnector(domain, ldapUrl)) {
            // 匿名连接AD域
            connector.connect();

            // 搜索用户 (注意: 匿名访问可能权限有限)
            List<SearchResult> results = connector.search(
                    "(objectClass=user)",
                    new String[]{"cn", "mail", "telephoneNumber"});

            // 输出结果
            for (SearchResult result : results) {
                System.out.println("DN: " + result.getNameInNamespace());
                Attributes attrs = result.getAttributes();

                System.out.println("CN: " + getAttribute(attrs, "cn"));
                System.out.println("Mail: " + getAttribute(attrs, "mail"));
                System.out.println("Tel: " + getAttribute(attrs, "telephoneNumber"));
                System.out.println("----------------------");
            }

        } catch (NamingException e) {
            System.err.println("AD操作失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private static String getAttribute(Attributes attrs, String attrName) {
        try {
            Attribute attr = attrs.get(attrName);
            return attr != null ? attr.get().toString() : "N/A";
        } catch (NamingException e) {
            return "Error: " + e.getMessage();
        }
    }
}
