package com.yifu.cloud.plus.v1.yifu.common.ldap.util;

import com.unboundid.ldap.sdk.*;
import com.unboundid.ldap.sdk.controls.SubentriesRequestControl;
import com.yifu.cloud.plus.v1.yifu.common.ldap.entity.PersonVo;
import com.yifu.cloud.plus.v1.yifu.common.ldap.mapper.PersonAttributesMapper;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.LdapTemplate;

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

import static org.springframework.ldap.query.LdapQueryBuilder.query;

@Log4j2
public class LdapUtil {

	@Autowired
	private LdapTemplate ldapTemplate;

	private static LdapContext ctx = null;

	private static Control[] connCtls = null;

	/**** 定义LDAP的基本连接信息 ******/
	// LDAP的连接地址（ldap://ip:port/）port默认为389
	private static String URL = "ldap://192.168.1.65:389/";
	// LDAP的根DN
	private static String BASEDN = "dc=worfu,dc=com";
	// LDAP的连接账号（身份认证管理平台添加的应用账号，应用账号格式：uid=?,ou=?,dc=????）
	private static String PRINCIPAL = "cn=admin,dc=worfu,dc=com";
	// LDAP的连接账号的密码（身份认证管理平台添加的应用账号的密码）
	private static String PASSWORD = "yifu123456!";


	/**
	 * @return List<SearchResultEntry>
	 * @author huyc
	 * @date 2022-06-14 17:56
	 * @description get请求获取指定对象信息
	 **/
	public List<SearchResultEntry> getAllPersonNamesWithTraditionalWay() {
		List<SearchResultEntry> result = new ArrayList<SearchResultEntry>();
		try {
			LDAPConnection connection = new LDAPConnection("192.168.1.65", 389, "cn=admin,dc=worfu,dc=com", "yifu123456!");
			SearchRequest searchRequest = new SearchRequest("ou=安徽皖信人力资源管理有限公司,ou=wanxin,dc=worfu,dc=com", SearchScope.SUB, "(objectclass=*)");
			searchRequest.addControl(new SubentriesRequestControl());
			SearchResult searchResult = connection.search(searchRequest);
			for (SearchResultEntry entry : searchResult.getSearchEntries()) {
				result.add(entry);
			}
		} catch (LDAPException e) {
			e.printStackTrace();
		}
		return result;
	}

	public List<PersonVo> getAllPersons() {
		List<PersonVo> list = ldapTemplate.search(query()
				.where("objectclass").is("posixAccount"), new PersonAttributesMapper());
		return list;
	}

	// 校验用户名密码的方法
	public Boolean authenticate(String usr, String pwd) {
		boolean valide = false;
		if (pwd == null || pwd == "")
			return false;
		if (ctx == null) {
			getCtx();
		}
		String userDN = getUserDN(usr);
		if ("".equals(userDN) || userDN == null) {
			return false;
		}
		try {
			ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
			ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, pwd);
			ctx.reconnect(connCtls);
			valide = true;
			closeCtx();
		} catch (AuthenticationException e) {
			log.error(userDN + " is not authenticated");
			valide = false;
		} catch (NamingException e) {
			log.error(userDN + " is not authenticated");
			valide = false;
		}
		return valide;
	}

	public static void getCtx() {
		if (ctx != null) {
			return;
		}
		Hashtable<String, String> env = new Hashtable<String, String>();
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		env.put(Context.PROVIDER_URL, URL + BASEDN);
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
		env.put(Context.SECURITY_PRINCIPAL, PRINCIPAL);
		env.put(Context.SECURITY_CREDENTIALS, PASSWORD);
		try {
			// 链接ldap
			ctx = new InitialLdapContext(env, connCtls);
		} catch (NamingException e) {
			e.printStackTrace();
		}
	}

	public static void closeCtx() throws NamingException {
		if (ctx != null)
			ctx.close();
	}

	public static String getUserDN(String uid) {
		String userDN = "";
		try {
			SearchControls constraints = new SearchControls();
			constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
			NamingEnumeration<?> en = ctx.search("", "uid=" + uid, constraints);
			while (en != null && en.hasMoreElements()) {
				Object obj = en.nextElement();
				if (obj instanceof javax.naming.directory.SearchResult) {
					javax.naming.directory.SearchResult si = (javax.naming.directory.SearchResult) obj;
					userDN += si.getName();
					userDN += "," + BASEDN;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return userDN;
	}
}
