package com.gtiit.shr.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.util.StringUtil;
import com.gtiit.shr.config.InsertBatchMethod;
import com.gtiit.shr.entity.enums.TaskNameEnum;
import com.gtiit.shr.entity.enums.TaskStatusEnum;
import com.gtiit.shr.entity.enums.TypeEnum;
import com.gtiit.shr.entity.vo.ExceptionRequestVo;
import com.gtiit.shr.mapper.ExceptionRequestVoMapper;
import com.gtiit.shr.service.ADSyncService;
import com.gtiit.shr.utils.ADUtils;
import com.gtiit.shr.utils.FinalParamUtil;
import com.kingdee.shr.api.Response;
import com.kingdee.shr.api.SHRClient;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.annotation.Resource;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


/**
 * AD同步服务实现类
 */
@Service
@Transactional
public class ADSyncServiceImpl implements ADSyncService {
    private static final Logger logger = LoggerFactory.getLogger(ADSyncServiceImpl.class);
    // 定义需要同步的AD域用户字段
    public static final String[] fileds = new String[]{"sAMAccountName", "manager", "givenName", "sn",  "extensionAttribute6", "displayName", "userPrincipalName", "mail", "telephoneNumber", "title", "department", "employeeID", "employeeType", "extensionAttribute3", "extensionAttribute4", "extensionAttribute5","AccountExpirationDate", "extensionAttribute8", "extensionAttribute9",
            "extensionAttribute10", "extensionAttribute11", "extensionAttribute12","extensionAttribute14","extensionAttribute15","Division"};

    @Autowired
    FinalParamUtil finalParamUtil;
    @Autowired
    ADUtils adUtils;
    @Resource
    ExceptionRequestVoMapper exceptionRequestVoMapper;
    public DirContext dc;
    public String sAMAccountName;
    @Value("${api.ad.root}")
    private String root;
    @Value("${api.ad.top}")
    private String top;
    @Value("${api.ad.userPassword}")
    private String userPassword;
    @Value("${scheduled.ad.person.able}")
    private String adcronStatus;
    public String requestParamJson;
    public String responeParamJson;
    public SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");



    @Scheduled(
            cron = "${scheduled.ad.person.cron}"
    )

    public void doSyncUsers() throws Exception {
        if (TaskStatusEnum.ABLE.getValue().equals(this.adcronStatus)) {
            this.synADUserToType((String)null, (String)null, (String)null, TypeEnum.AUTO.getValue());
        }

    }

    // 手动同步AD域用户
    public JSONObject syncADUsers(String startDate, String endDate, String personNumber) throws Exception {
        return this.synADUserToType(startDate, endDate, personNumber, TypeEnum.MANUAL.getValue());
    }



    // 同步AD域用户到指定类型
    private JSONObject synADUserToType(String startDate, String endDate, String personNumber, String type) throws Exception {
        JSONObject result = new JSONObject();
        result.put("code", 200);
        Map<String, String> requestParam = new HashMap();
        requestParam.put("startDate", startDate);
        requestParam.put("endDate", endDate);
        requestParam.put("personNumber", personNumber);
        this.requestParamJson = JSON.toJSONString(requestParam);
        String responeParams = "";
        JSONObject responeParamsJson = null;

        try {
            responeParams = this.getOSFData(this.finalParamUtil.getSynADService(), requestParam).getData().toString();
            responeParamsJson = JSONObject.parseObject(responeParams);
        } catch (Exception var35) {
            result.put("code", "500");
            result.put("msg", "SHR系统请求报错，报错信息为：" + var35.getMessage());
            return result;
        }

        Object code = responeParamsJson.get("code");
        JSONArray datas = responeParamsJson.getJSONArray("data");
        if ("1".equals(code) && datas.size() > 0) {
            try {
                this.dc = this.adUtils.getDirContext();


                Iterator dataIter = datas.iterator();

                while(dataIter.hasNext()) {
                    Object responeParam = dataIter.next();
                    this.responeParamJson = JSON.toJSONString(responeParam);
                    Map<String, String> dataMap = (Map)responeParam;
                    this.sAMAccountName = (String)dataMap.get("sAMAccountName");
                    if (null == this.sAMAccountName) {
                        this.insertLog("同步日志：AD域用户同步失败！原因：【sAMAccountName】属性不能为空！", "否", type);
                    } else {
                        String name = "";
                        String originName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", this.sAMAccountName);
                        if (StringUtils.isEmpty(originName)) {
                            name = "CN=" + this.sAMAccountName + "," + this.root;
                        } else {
                            name = originName;
                        }

                        String managerName = "";
                        String info;
                        String shr_value;
                        String ad_value;
                        String msg;
                        String message;
                        String field;
                        try {
                            Attributes attributes = this.dc.getAttributes(name);
                            StringBuilder sb = new StringBuilder();
                            sb.append("同步日志:AD域用户【").append(this.sAMAccountName).append("】同步，");
                            String[] filedArr = fileds;
                            int arrlen = filedArr.length;
                            boolean isContinue = false;
                            //extensionAttribute8值为
                            Attribute extensionAttribute8 = attributes.get("extensionAttribute8");
                            String  extensionAttribute8Str = extensionAttribute8 != null ? (String)extensionAttribute8.get() : null;
                            //extensionAttribute6值为
                            Attribute extensionAttribute6 = attributes.get("extensionAttribute6");
                            String  extensionAttribute6Str = extensionAttribute6 != null ? (String)extensionAttribute6.get() : null;

                            try {
                                String managerStr = dataMap.get("manager").toString();
                                managerName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", managerStr);
                            } catch (NamingException var38) {
                                sb.append("同步“manager”属性失败，上级负责人【").append(dataMap.get("manager").toString()).append("】在AD域中不存在；");
                            }
                            //202506 针对兼职身份(extensionAttribute6 值为Part Time)且在AD中已有帐号的中国员工(extensionAttribute8 chinese)，
                            //job title 和 department 属性值不变
                            if (  null  != extensionAttribute6Str  && "Part Time".equals(extensionAttribute6Str) &&  null != extensionAttribute8Str &&
                                    "Chinese".equals(extensionAttribute8Str)) {
                                isContinue = true;
                                //15 Part Time 将兼职职位名称同步至 AD的extensionAttribute15
                                Attribute att15 = attributes.get("extensionAttribute15");
                                String titleVal  =  dataMap.get("extensionAttribute15") == null ? "" : (String)dataMap.get("extensionAttribute15") ;
                                if(null == att15 || StringUtil.isEmpty((String)att15.get())){
                                    msg = this.addInformation(name, "extensionAttribute15", titleVal, managerName);
//                                    msg = "新增extensionAttribute15属性成功！";
                                    sb.append(msg);
                                }else{
                                    this.modifyInformation(name, "extensionAttribute15", titleVal, managerName);
                                    msg = "更新extensionAttribute15属性成功！";
                                    sb.append(msg);
                                }

                                //Division 兼职所属部门同步到AD的Division属性
                                Attribute divisionAtt = attributes.get("Division");
                                String departmentVal  = (String)dataMap.get("Division");
                                if(null == divisionAtt || StringUtil.isEmpty((String)divisionAtt.get())){
                                    msg =  addInformation(name, "Division", departmentVal, managerName);
//                                    msg = "新增Division属性成功！";
                                    sb.append(msg);
                                }else{
                                    this.modifyInformation(name, "Division", departmentVal, managerName);
                                    msg = "更新Division属性成功！";
                                    sb.append(msg);
                                }

                                //将用户的manager属性更新到新的AD属性 extensionAttribute14
                                Attribute extensionAttribute14 = attributes.get("extensionAttribute14");
                                String extensionAttribute14Str  = (String)dataMap.get("extensionAttribute14");
                                if(null == extensionAttribute14 || StringUtil.isEmpty((String)extensionAttribute14.get())){
                                    msg =  addInformation(name, "extensionAttribute14", extensionAttribute14Str, managerName);
//                                    msg = "新增extensionAttribute14Str属性成功！";
                                    sb.append(msg);
                                }else{
                                    this.modifyInformation(name, "extensionAttribute14", extensionAttribute14Str, managerName);
                                    msg = "更新extensionAttribute14Str属性成功！";
                                    sb.append(msg);
                                }

                            }

                            for(int  ii = 0; ii < arrlen; ++ii) {
                                field = filedArr[ii];
                                Attribute attribute = attributes.get(field);
                                shr_value = (String)dataMap.get(field);
                                ad_value = attribute != null ? (String)attribute.get() : null;

                                if (("givenName".equals(field) || "displayName".equals(field)) && StringUtil.isNotEmpty(shr_value)) {
                                    shr_value = shr_value.substring(0, 1).toUpperCase() + shr_value.substring(1);
                                }

                                //保留 这些人员AD 中现有的 job title 和 department 属性值不变
                                if(isContinue && ("title".equals(field) || "department".equals(field) || "manager".equals(field)) ) {
                                    continue;
                                }
                                if("extensionAttribute14".equals(field) && "extensionAttribute15".equals(field) && "Division".equals(field)){
                                    continue;
                                }

                                if (StringUtil.isNotEmpty(shr_value) && StringUtil.isNotEmpty(ad_value)) {
                                    if (!shr_value.equals(ad_value)) {
                                        try {
                                            this.modifyInformation(name, field, shr_value, managerName);
                                            msg = "更新“" + field + "”属性成功！";
                                            sb.append(msg);
                                        } catch (NamingException var33) {
                                            message = var33.getMessage();
                                            msg = "更新“" + field + "”属性失败，原因：" + message + "；";
                                            sb.append(msg);
                                        }
                                    }
                                } else if (StringUtil.isEmpty(shr_value) && StringUtil.isNotEmpty(ad_value)) {
                                    try {
                                        if ("telephoneNumber".equals(field)) {
                                            continue;
                                        }

                                        this.removeInformation(name, field, shr_value, managerName);
                                        msg = "删除“" + field + "”属性成功！";
                                        sb.append(msg);
                                    } catch (NamingException var37) {
                                        message = var37.getMessage();
                                        msg = "删除“" + field + "”属性失败，原因：" + message + "；";
                                        sb.append(msg);
                                    }
                                } else if (StringUtil.isNotEmpty(shr_value) && StringUtil.isEmpty(ad_value)) {
                                    try {
                                        msg = addInformation(name, field, shr_value, managerName);
//                                        msg = "新增“" + field + "”属性成功！";
                                        sb.append(msg);
                                    } catch (NamingException var32) {
                                        message = var32.getMessage();
                                        msg = "新增“" + field + "”属性失败，原因：" + message + "；";
                                        sb.append(msg);
                                    }
                                }

                                try {
                                    this.modifyInformation(name, "userAccountControl", "544", managerName);
                                    msg = "添加“userAccountControl”属性成功！";
                                    sb.append(msg);
                                } catch (NamingException var31) {
                                    message = var31.getMessage();
                                    msg = "添加“userAccountControl”属性失败，原因：" + message + ";";
                                    sb.append(msg);
                                }
                            }

                            info = sb.toString();
                            if (info.endsWith("同步，")) {
                                sb.append("数据一致！不用进行更新。");
                            }

                            this.insertLog(sb.toString(), "是", type);
                        } catch (NamingException var39) {
                            try {
                                Attributes attrs = new BasicAttributes(true);
                                attrs.put("objectClass", "user");
                                attrs.put("sAMAccountName", dataMap.get("sAMAccountName"));
                                this.dc.createSubcontext(name, attrs);
                                StringBuilder sb = new StringBuilder();
                                sb.append("同步日志:AD域用户【").append(this.sAMAccountName).append("】新增成功！");

                                String[] filedArr = fileds;
                                int arrlen = filedArr.length;

                                for(int i = 0; i < arrlen; i++) {
                                    String filed = filedArr[i];
                                    shr_value = (String)dataMap.get(filed);
                                    if (!"sAMAccountName".equals(filed) && StringUtil.isNotEmpty((String)dataMap.get(filed))) {
                                        try {
                                            if ("manager".equals(filed)) {
                                                managerName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", shr_value);
                                                msg = addInformation(name, filed, shr_value, managerName);
                                            } else {
                                                msg = addInformation(name, filed, shr_value, managerName);
                                            }
                                            sb.append(msg);

                                        } catch (NamingException var30) {
                                            msg = var30.getMessage();
                                            message = "添加“" + filed + "”属性失败，原因：" + msg + ";";
                                            sb.append(message);
                                        }
                                    }
                                }

                                try {
                                    this.modifyInformation(name, "userAccountControl", "544", managerName);
                                    msg = "添加“userAccountControl”属性成功！";
                                    sb.append(msg);
                                } catch (NamingException var29) {
                                    message = var29.getMessage();
                                    field = "添加“userAccountControl”属性失败，原因：" + message + ";";
                                    sb.append(field);
                                }

                                this.insertLog(sb.toString(), "是", type);
                            } catch (Exception var36) {
                                info = var36.getMessage();
                                this.insertLog("同步日志:AD域用户【" + this.sAMAccountName + "】新增失败！原因：" + info, "否", type);
                            }
                        }
                    }
                }
            } catch (Exception var34) {
                result.put("code", "500");
                result.put("msg", "AD服务器连接失败，失败原因为：" + var34.getMessage());
                return result;
            }finally {
                if (this.dc != null) {
                    try {
                        this.dc.close();
                    } catch (NamingException e) {
                        logger.error("关闭AD连接失败", e);
                    }
                }
            }
            result.put("result", "AD域数据同步完成！");
        } else {
            this.responeParamJson = responeParams;
            this.insertLog("未找到变动记录!", "否", type);
            result.put("code", 500);
            result.put("msg", "未找到变动记录!");
        }

        return result;
    }


    // 搜索用户，返回用户在AD域中的...
    public String searchUser(DirContext ctx, String searchBase, String searchFilter, String username) throws Exception {
        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(2);
        NamingEnumeration<SearchResult> results = ctx.search(searchBase, searchFilter, new Object[]{username}, searchControls);
        String managerName = "";

        String mangerDN;
        SearchResult searchResult;
        for(mangerDN = ""; results.hasMoreElements(); mangerDN = searchResult.getNameInNamespace()) {
            searchResult = (SearchResult)results.nextElement();
            Attributes attributes = searchResult.getAttributes();
        }

        return mangerDN;
    }


    // 插入同步日志
    private void insertLog(String errorReason, String sucess, String type) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ExceptionRequestVo exceptionRequestVo = new ExceptionRequestVo();
        TaskNameEnum adUuser = TaskNameEnum.ADUSER;
        Date date = new Date();
        exceptionRequestVo.setTaskType(adUuser.getValue());
        exceptionRequestVo.setTaskName(adUuser.getName() + "-" + this.sAMAccountName + "-" + sdf.format(date));
        exceptionRequestVo.setType(type);
        exceptionRequestVo.setExcuteDate(date);
        exceptionRequestVo.setErrorReason(errorReason);
        exceptionRequestVo.setIsSucess(sucess);
        exceptionRequestVo.setRequestParam(this.requestParamJson);
        exceptionRequestVo.setResponeParam(this.responeParamJson);
        this.exceptionRequestVoMapper.insert(exceptionRequestVo);
    }

    // 从SHR系统获取OSF数据
    public Response getOSFData(String OsfName, Map map) throws IOException {
        SHRClient client = new SHRClient();
        return client.executeService(this.finalParamUtil.getShrUrl(), OsfName, map);
    }

    // 添加用户信息到AD域
    public String  addInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
        if ("manager".equals(field)) {
            ModificationItem item = new ModificationItem(1, new BasicAttribute("manager", managerName));
            this.dc.modifyAttributes(name, new ModificationItem[]{item});
        } else {
            BasicAttributes basicAttributes = new BasicAttributes();
            basicAttributes.put(field, fieldValue);
            //为空则不处理
            if(StringUtil.isEmpty(fieldValue)){
                return  "新增"+field + "的值为空不进行处理";
            }
            this.dc.modifyAttributes(name, 1, basicAttributes);
        }
        return  "新增"+field + "的值为"+fieldValue+"已同步成功！";
    }


    // 修改AD域中的用户信息
    public void modifyInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
        if ("manager".equals(field)) {
            ModificationItem item = new ModificationItem(2, new BasicAttribute("manager", managerName));
            this.dc.modifyAttributes(name, new ModificationItem[]{item});
        } else {
            BasicAttributes basicAttributes = new BasicAttributes();
            basicAttributes.put(field, fieldValue);
            //如果为空则删除
            if(StringUtil.isEmpty(fieldValue)){
                this.dc.modifyAttributes(name, 3, basicAttributes);
            }else{
                this.dc.modifyAttributes(name, 2, basicAttributes);
            }
        }

    }


    // 从AD域中移除用户信息
    public void removeInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
        if ("manager".equals(field)) {
            ModificationItem item = new ModificationItem(3, new BasicAttribute("manager", managerName));
            this.dc.modifyAttributes(name, new ModificationItem[]{item});
        } else {
            BasicAttributes basicAttributes = new BasicAttributes();
            basicAttributes.put(field, fieldValue);
            this.dc.modifyAttributes(name, 3, basicAttributes);
        }

    }

    public long getNTLongTimestamp(Date date) {
        long timestamp = date.getTime();
        timestamp -= 57599875L;
        timestamp *= 10000L;
        timestamp += 116445312000000000L;
        return timestamp;
    }
}
