package com.kingdee.eas.custom.recuritment.task;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.bos.metadata.entity.*;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.eas.custom.beisen.utils.BeisenApiClient;
import com.kingdee.eas.custom.beisen.utils.BeisenParam;
import com.kingdee.eas.custom.beisen.utils.BeisenParamByProperties;
import com.kingdee.eas.custom.beisen.entity.PhaseStatusInfo;
import com.kingdee.eas.hr.ats.AtsUtil;
import com.kingdee.eas.hr.base.EmployeeTypeInfo;
import com.kingdee.eas.hr.base.HRBillStateEnum;
import com.kingdee.eas.util.app.DbUtil;
import com.kingdee.shr.recuritment.*;
import com.kingdee.shr.recuritment.app.OfferConfirmStateEnum;
import com.kingdee.util.DateTimeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.kingdee.bos.*;
import com.kingdee.eas.common.EASBizException;

import java.io.IOException;
import java.lang.String;
import java.text.MessageFormat;
import java.util.*;

public class BeisenTransferPhaseFacadeControllerBean extends AbstractBeisenTransferPhaseFacadeControllerBean {
    private static Logger logger = Logger.getLogger(BeisenTransferPhaseFacadeControllerBean.class);
    private Map<String, PhaseStatusInfo> phaseStatus = Maps.newHashMap();
    //待录用报批单据状态
    private static Set hireApprovalBillStatusSet = new HashSet<>();
    //待录用报批招聘状态
    private static Set hireApprovalResumeStateSet = new HashSet<>();
    //录用终止报批招聘状态
    private static Set hireTerminationResumeStateSet = new HashSet<>();
    //待录用报批招聘状态
    private static Set hireOfferStateSet = new HashSet<>();
    private static Map<String, String> beisenTransferPhaseErrorMap = new HashMap<>();


    private final String RECAPPROVAL1 = "recApproval1";
    private final String RECAPPROVAL2 = "recApproval2";
    private final String OFFER1 = "offer1";
    private final String OFFER2 = "offer2";
    private final String OFFER3 = "offer3";
    private final String OFFER4 = "offer4";
    private final String OFFER5 = "offer5";
    private final String ENROLL1 = "enroll1";
    private final String ENROLL2 = "enroll2";
    private final String ENROLL3 = "enroll3";

    static {
        hireApprovalBillStatusSet.add(HRBillStateEnum.SAVED);//未提交
        hireApprovalBillStatusSet.add(HRBillStateEnum.SUBMITED);//已提交
        hireApprovalBillStatusSet.add(HRBillStateEnum.AUDITING);//审批中
        hireApprovalResumeStateSet.add("0009");//待报批
        hireApprovalResumeStateSet.add("0010");//报批中
        hireTerminationResumeStateSet.add("0012");//终止报批
        hireTerminationResumeStateSet.add("0011");//报批不通过
        hireOfferStateSet.add("0013");//待入职
        hireOfferStateSet.add("0015");//已预入职

        beisenTransferPhaseErrorMap.put("applyDeleteApplyIds", "因在当前职位下被删除而转移失败");
        beisenTransferPhaseErrorMap.put("applicantDeleteApplyIds", "因应聘者被删除而转移失败");
        beisenTransferPhaseErrorMap.put("applicantBlackApplyIds", "因应聘者被拉黑而转移失败");
        beisenTransferPhaseErrorMap.put("applicantLockedApplyIds", "因应聘者被锁定而转移失败");
        beisenTransferPhaseErrorMap.put("applyStatusChangedApplyIds", "因应聘者阶段状态已发生变化而转移失败");
        beisenTransferPhaseErrorMap.put("applyOtherReasonRejectedApplyIds", "因定制功能校验失败而转移失败");
        beisenTransferPhaseErrorMap.put("applyByHunterOrRPOUnAcceptedIds", "因应聘者存在猎头/RPO简历且未被接受而转移失败");
        beisenTransferPhaseErrorMap.put("applyTransferRuleFailedApplyIds", "因应聘者存在不符合准入规则而转移失败");

    }

    public BeisenTransferPhaseFacadeControllerBean() throws IOException, BOSException {
        BeisenParamByProperties properties = null;
        try {
            properties = new BeisenParamByProperties();
        } catch (IOException e) {
            logger.error("北森状态转移Facade获取配置文件报错: " + e.getMessage(), e);
            throw e;
        }
        Map<String, String> config = properties.getConfig();
        String phase1 = config.get("phase1");
        String status1A = config.get("status1A");
        String status1B = config.get("status1B");
        String phase2 = config.get("phase2");
        String status2A = config.get("status2A");
        String status2B = config.get("status2B");
        String status2C = config.get("status2C");
        String status2D = config.get("status2D");
        String status2E = config.get("status2E");
        String phase3 = config.get("phase3");
        String status3A = config.get("status3A");
        String status3B = config.get("status3B");
        String status3C = config.get("status3C");
        if (StringUtils.isAnyBlank(
                phase1, phase2, phase3, status1A,
                status1B, status2A, status2B, status2C,
                status2D, status2E, phase3, status3A,
                status3B, status3C)) {
            throw new BOSException("北森阶段状态为空!");
        }
        phaseStatus.put(RECAPPROVAL1, new PhaseStatusInfo(phase1, status1A, "待录用报批"));
        phaseStatus.put(RECAPPROVAL2, new PhaseStatusInfo(phase1, status1B, "录用终止"));
        phaseStatus.put(OFFER1, new PhaseStatusInfo(phase2, status2A, "待发Offer"));
        phaseStatus.put(OFFER2, new PhaseStatusInfo(phase2, status2B, "已发Offer"));
        phaseStatus.put(OFFER3, new PhaseStatusInfo(phase2, status2C, "拒绝Offer"));
        phaseStatus.put(OFFER4, new PhaseStatusInfo(phase2, status2D, "接受Offer"));
        phaseStatus.put(OFFER5, new PhaseStatusInfo(phase2, status2E, "等待入职"));
        phaseStatus.put(ENROLL1, new PhaseStatusInfo(phase3, status3A, "已入职"));
        phaseStatus.put(ENROLL2, new PhaseStatusInfo(phase3, status3B, "取消入职"));
        phaseStatus.put(ENROLL3, new PhaseStatusInfo(phase3, status3C, "已离职"));
    }

    /**
     * 同步录用报批状态到北森
     *
     * @param ctx
     * @param billIds
     * @param preponeHours
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected void _syncRecApprovalToBeisen(Context ctx, String billIds, int preponeHours)
            throws BOSException, EASBizException {
        try {
            super._syncRecApprovalToBeisen(ctx, billIds, preponeHours);
            IRecApproval iRecApproval = RecApprovalFactory.getLocalInstance(ctx);
            RecApprovalCollection recApprovalCollection = null;
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add("*");
            sic.add("resumeBaseRec.*");
            sic.add("resumeBaseRec.resumeState.*");
            if (StringUtils.isNotBlank(billIds)) {
                if (billIds.contains("'")) {
                    billIds = billIds.replace("'", "");
                }
                FilterInfo filterInfo = new FilterInfo();
                FilterItemCollection filterItems = filterInfo.getFilterItems();
                filterItems.add(new FilterItemInfo("id", billIds, CompareType.INCLUDE));
                EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
                recApprovalCollection = iRecApproval.getRecApprovalCollection(viewInfo);
                if (recApprovalCollection.isEmpty()) {
                    logger.error("未匹配到录用报批单据，单据id： " + billIds);
                    throw new BOSException("未匹配到录用报批单据");
                }
            } else {
                if (preponeHours <= 0) {
                    preponeHours = 2;
                }
                Date now = new Date();
                Date before = DateTimeUtils.addMinute(now, -preponeHours);
                //查询最近12小时内更新的录用报批
                FilterInfo filterInfo = new FilterInfo();
                FilterItemCollection filterItems = filterInfo.getFilterItems();
                //最后更新时间大于等于
                filterItems.add(new FilterItemInfo("lastUpdateTime", before, CompareType.GREATER_EQUALS));
                //最后更新时间小于等于当前
                filterItems.add(new FilterItemInfo("lastUpdateTime", now, CompareType.LESS_EQUALS));
                EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
                recApprovalCollection = iRecApproval.getRecApprovalCollection(viewInfo);
            }
            if (recApprovalCollection == null || recApprovalCollection.isEmpty()) {
                logger.error("录用报批为空!");
                return;
            }
            //维护录用报批与北森申请id映射关系
            Map<String, String> applyIdRecApprovalMap = new HashMap();
            Map<String, JSONArray> recApprovalMap = new HashMap();
            IOffer iOffer = OfferFactory.getLocalInstance(ctx);
            for (int i = 0; i < recApprovalCollection.size(); i++) {
                RecApprovalInfo recApprovalInfo = recApprovalCollection.get(i);
                String fid = recApprovalInfo.getId().toString();
                //简历基本信息
                ResumeBaseRecInfo resumeBaseRec = recApprovalInfo.getResumeBaseRec();
                String applyId = resumeBaseRec.getString("applyId");
                if (StringUtils.isEmpty(applyId)) {
                    String errorMsg = "北森申请id为空!";
                    logger.error(errorMsg);
                    Set set = new HashSet();
                    set.add(fid);
                    updateTable(ctx, "T_REC_RecApproval", errorMsg, "2", set);
                    continue;
                }
                applyIdRecApprovalMap.put(applyId, fid);
                ResumeStateInfo resumeState = resumeBaseRec.getResumeState();
                String resumeStateNumber = resumeState.getNumber();//招聘状态
                String beisenStatus = null;
                //单据状态
                HRBillStateEnum billState = recApprovalInfo.getBillState();
                if (hireApprovalResumeStateSet.contains(resumeStateNumber)) {
                    //单据状态为未提交/未审批/审批中,招聘需求状态为待报批/报批中 北森录用报批状态为待录用报批
                    beisenStatus = RECAPPROVAL1;
                } else if (hireTerminationResumeStateSet.contains(resumeStateNumber)) {
                    //单据状态为审批不通过,招聘需求状态为终止报批/报批不通过 北森录用报批状态为录用终止
                    beisenStatus = RECAPPROVAL2;
                } else if (HRBillStateEnum.AUDITED.equals(billState) && "0013".equals(resumeStateNumber)) {
                    //单据状态为审批通过,招聘需求状态为待入职,Offer发送状态为空,北森状态为待发Offer
                    try {
                        OfferCollection offerCollection = iOffer.getOfferCollection("where resumeBaseRec ='" + resumeBaseRec.getId() + "'");
                        //offer发送状态
                        String sendState = null;
                        if (!offerCollection.isEmpty()) {
                            OfferInfo offerInfo = offerCollection.get(0);
                            sendState = offerInfo.getSendState();
                        }
                        if (StringUtils.isBlank(sendState) || "待发送".equals(sendState)) {
                            //发送状态为空或待确认,招聘需求状态为待入职 北森录用报批状态为待发Offer
                            beisenStatus = OFFER1;
                        }
                    } catch (BOSException e) {
                        throw new BOSException("获取offer状态报错: " + e.getMessage());
                    }
                }
                if (StringUtils.isNotBlank(beisenStatus)) {
                    if (recApprovalMap.containsKey(beisenStatus)) {
                        recApprovalMap.get(beisenStatus).add(applyId);
                    } else {
                        JSONArray applyIds = new JSONArray();
                        applyIds.add(applyId);
                        recApprovalMap.put(beisenStatus, applyIds);
                    }
                }
            }
            //处理北森状态转移请求
            handleBeisenTransferPhaseQuery(ctx, recApprovalMap, applyIdRecApprovalMap, "T_REC_RecApproval");
        } catch (Exception e) {
            logger.error("录用报批同步北森状态转移报错: " + e.getMessage(), e);
        }
    }

    /**
     * 同步offer状态到北森
     *
     * @param ctx
     * @param billIds
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected void _syncOfferToBeisen(Context ctx, String billIds, int preponeHours) throws BOSException, EASBizException {
        try {
            super._syncOfferToBeisen(ctx, billIds, preponeHours);
            IOffer iOffer = OfferFactory.getLocalInstance(ctx);
            OfferCollection offerCollection = null;
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add("*");
            sic.add("resumeBaseRec.*");
            sic.add("resumeBaseRec.resumeState.*");
            sic.add("person.employeeType.isInCount");
            if (StringUtils.isNotBlank(billIds)) {
                if (billIds.contains("'")) {
                    billIds = billIds.replace("'", "");
                }
                FilterInfo filterInfo = new FilterInfo();
                FilterItemCollection filterItems = filterInfo.getFilterItems();
                filterItems.add(new FilterItemInfo("id", billIds));
                EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
                offerCollection = iOffer.getOfferCollection(viewInfo);
                if (offerCollection.isEmpty()) {
                    logger.error("未匹配到offer单据，单据id： " + billIds);
                    throw new BOSException("未匹配到offer单据");
                }
            } else {
                if (preponeHours <= 0) {
                    preponeHours = 2;
                }
                Date now = new Date();
                Date before = DateTimeUtils.addMinute(now, -preponeHours);
                //查询最近12小时内更新的录用报批
                FilterInfo filterInfo = new FilterInfo();
                FilterItemCollection filterItems = filterInfo.getFilterItems();
                //最后更新时间大于等于
                filterItems.add(new FilterItemInfo("lastUpdateTime", before, CompareType.GREATER_EQUALS));
                //最后更新时间小于等于当前
                filterItems.add(new FilterItemInfo("lastUpdateTime", now, CompareType.LESS_EQUALS));
                EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
                offerCollection = iOffer.getOfferCollection(viewInfo);
            }
            if (offerCollection == null || offerCollection.isEmpty()) {
                logger.error("offer为空!");
                return;
            }
            //维护OfferId与北森申请id映射关系
            Map<String, String> applyIdOfferMap = new HashMap();
            Map<String, JSONArray> offerMap = new HashMap();
            Map<String, JSONArray> recApprovalMap = new HashMap();
            for (int i = 0; i < offerCollection.size(); i++) {
                OfferInfo offerInfo = offerCollection.get(i);
                String fid = offerInfo.getId().toString();
                //简历基本信息
                ResumeBaseRecInfo resumeBaseRec = offerInfo.getResumeBaseRec();
                String applyId = resumeBaseRec.getString("applyId");
                if (StringUtils.isEmpty(applyId)) {
                    String errorMsg = "北森申请id为空!";
                    logger.error(errorMsg);
                    Set set = new HashSet();
                    set.add(fid);
                    updateTable(ctx, "T_REC_Offer", errorMsg, "2", set);
                    continue;
                }
                applyIdOfferMap.put(applyId, fid);
                ResumeStateInfo resumeState = resumeBaseRec.getResumeState();
                String resumeStateNumber = resumeState.getNumber();//招聘状态
                //发送状态
                String sendState = offerInfo.getSendState();
                //确认状态
                OfferConfirmStateEnum confirmState = offerInfo.getConfirmState();
                String beisenStatus = null;
                if ("0013".equals(resumeStateNumber) && (StringUtils.isBlank(sendState) || "待发送".equals(sendState))) {
                    //发送状态为空或待确认,招聘需求状态为待入职 北森录用报批状态为待发Offer
                    beisenStatus = OFFER1;
                } else if ("0013".equals(resumeStateNumber) && "已发送".equals(sendState) && OfferConfirmStateEnum.TOBECONFIRM.equals(confirmState)) {
                    //确认结果待确认,发送状态为已发送,招聘需求状态为待入职 北森录用报批状态为已发Offer
                    beisenStatus = OFFER2;
                } else if ("0013".equals(resumeStateNumber) && "已发送".equals(sendState) && OfferConfirmStateEnum.ACCEPTED.equals(confirmState)) {
                    //确认结果已接受,发送状态为已发送,招聘需求状态为待入职 北森录用报批状态为接受Offer
                    beisenStatus = OFFER4;
                } else if ("0013".equals(resumeStateNumber) && "已发送".equals(sendState) && OfferConfirmStateEnum.REJECTED.equals(confirmState)) {
                    //确认结果已拒绝,发送状态为已发送,招聘需求状态为待入职 北森录用报批状态为拒绝Offer
                    beisenStatus = OFFER3;
                } else if ("0015".equals(resumeStateNumber)) {
                    //招聘需求状态为已预入职 北森录用报批状态为等待入职
                    beisenStatus = OFFER5;
                } else if ("0017".equals(resumeStateNumber)) {
                    //招聘需求状态为已入职 北森录用报批状态为已入职
                    PersonInfo person = offerInfo.getPerson();
                    if (person != null) {
                        EmployeeTypeInfo employeeType = person.getEmployeeType();
                        if (employeeType != null && !employeeType.isIsInCount()) {
                            //如果有审批通过的离职单,则忽略
                            return;
                        }
                    }
                    beisenStatus = ENROLL1;
                } else if ("0016".equals(resumeStateNumber) || "0014".equals(resumeStateNumber)) {
                    //招聘需求状态为放弃入职或终止入职 北森录用报批状态为取消入职
                    beisenStatus = ENROLL2;
                }
                if (StringUtils.isNotBlank(beisenStatus)) {
                    if (recApprovalMap.containsKey(beisenStatus)) {
                        offerMap.get(beisenStatus).add(applyId);
                    } else {
                        JSONArray applyIds = new JSONArray();
                        applyIds.add(applyId);
                        offerMap.put(beisenStatus, applyIds);
                    }
                }
            }
            handleBeisenTransferPhaseQuery(ctx, offerMap, applyIdOfferMap, "T_REC_Offer");
        } catch (Exception e) {
            logger.error("offer同步北森状态转移报错: " + e.getMessage(), e);
        }
    }

    /**
     * 处理北森状态转移请求
     *
     * @param ctx
     * @param recApprovalMap
     * @param applyIdStatusMap 北森状态与申请id
     * @param tableName        数据库表名
     * @throws BOSException
     */
    private void handleBeisenTransferPhaseQuery(
            Context ctx,
            Map<String, JSONArray> recApprovalMap,
            Map<String, String> applyIdStatusMap,
            String tableName
    ) throws BOSException, IOException, EASBizException {
        BeisenApiClient beisenApiClient = BeisenApiClient.getInstance();
        IOffer iOffer = OfferFactory.getLocalInstance(ctx);
        for (String status : recApprovalMap.keySet()) {
            try {
                //申请id
                JSONArray applyIds = recApprovalMap.get(status);
                PhaseStatusInfo phaseStatusInfo = phaseStatus.get(status);
                String statusName = phaseStatusInfo.getStatusName();
                JSONObject params = new JSONObject();
                params.put("applyIds", applyIds);
                params.put("phaseId", phaseStatusInfo.getPhaseId());
                params.put("statusId", phaseStatusInfo.getStatusId());
                logger.error("同步北森状态statusName: " + status);
                logger.error("同步北森状态url: " + BeisenParam.POST_TRANSFERPHASE_URL);
                logger.error("同步北森状态参数: " + params.toJSONString());
                JSONObject response = beisenApiClient.callApi(BeisenParam.POST_TRANSFERPHASE_URL, params);
                logger.error("同步北森状态响应: " + response.toJSONString());
                int code = response.getIntValue("code");
                String message = response.getString("message");
                if (200 == code) {
                    JSONObject data = response.getJSONObject("data");
                    //转移失败数
                    Integer noTransferCount = data.getInteger("noTransferCount");
                    if (noTransferCount > 0) {
                        for (String key : beisenTransferPhaseErrorMap.keySet()) {
                            JSONArray failApplyIds = data.getJSONArray(key);
                            if (!failApplyIds.isEmpty()) {
                                String errorMsg = beisenTransferPhaseErrorMap.get(key);
                                Set fids = new HashSet<>();
                                failApplyIds.forEach((applyid) -> {
                                    fids.add(applyIdStatusMap.get(applyid));
                                    //移除失败的申请id
                                    applyIds.remove(applyid);
                                });
                                updateTable(ctx, tableName, MessageFormat.format("[{0}]状态同步失败: {1}", statusName, errorMsg), "2", fids);
                            }
                        }
                    }
                    if (!applyIds.isEmpty()) {
                        //同步成功的数据,更新offer同步执行状态
                        Set fids = new HashSet<>();
                        for (int i = 0; i < applyIds.size(); i++) {
                            String applyId = applyIds.get(i).toString();
                            fids.add(applyIdStatusMap.get(applyId));
                        }
                        updateTable(ctx, tableName, MessageFormat.format("[{0}]状态同步成功", statusName), "1", fids);
                    }
                } else {
                    Set fids = new HashSet<>();
                    applyIdStatusMap.values().forEach((id) -> {
                        fids.add(id);
                    });
                    updateTable(ctx, tableName, message, "2", fids);
                    updateTable(ctx, tableName, MessageFormat.format("[{0}]状态同步失败: {1}", statusName, message), "2", fids);
                }
                //已入职
                if (ENROLL1.equals(status) && !applyIds.isEmpty()) {
                    //入职成功需要调用北森招聘到岗接口同步
                    JSONObject entryhandleParams = new JSONObject();
                    for (int i = 0; i < applyIds.size(); i++) {
                        String applyId = applyIds.get(i).toString();
                        entryhandleParams.put("applyId", applyIds);
                        String offerId = applyIdStatusMap.get(applyId);
                        OfferInfo offerInfo = iOffer.getOfferInfo(new ObjectUuidPK(offerId));
                        //入职日期
                        Date entryDate = offerInfo.getEntryDate();
                        if (entryDate != null) {
                            String entryDateStr = DateTimeUtils.format(entryDate, "yyyy-MM-dd'T'HH:mm:ss");
                            entryhandleParams.put("entryDate", entryDateStr);
                        }
                        logger.error("北森招聘到岗url" + BeisenParam.POST_ENTRYHANDLE_URL);
                        logger.error("北森招聘到岗参数" + params.toJSONString());
                        JSONObject result = beisenApiClient.callApi(BeisenParam.POST_ENTRYHANDLE_URL, entryhandleParams);
                        logger.error("北森招聘到岗响应" + result.toJSONString());
                        if (result.getInteger("code") != 200) {
                            String errorMessage = result.getString("message");
                            logger.error("北森招聘到岗响应报错: " + errorMessage);
                            updateTable(ctx, tableName, MessageFormat.format("[{0}]状态同步失败: {1}", statusName, errorMessage), "2", AtsUtil.toSet(offerId));
                        } else {
                            updateTable(ctx, tableName, MessageFormat.format("[{0}]状态同步成功", statusName), "1", AtsUtil.toSet(offerId));
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("同步北森状态转移报错: " + e.getMessage(), e);
                throw e;
            }
        }
    }

    /**
     * 更新offer/录用报批表执行结果和状态
     *
     * @param ctx
     * @param tableName
     * @param message
     * @param status
     * @param fids
     * @throws BOSException
     */
    private void updateTable(
            Context ctx,
            String tableName,
            String message,
            String status,
            Set fids
    ) throws BOSException {
        StringBuilder updateSql = new StringBuilder();
        updateSql.append("update ").append(tableName).append(" set CFsyncBeisenResult ='");
        updateSql.append(message).append("' ,CFsyncStatus = '").append(status).append("'");
        updateSql.append(" where fid in (").append(AtsUtil.convertSetToString(fids)).append(")");
        DbUtil.execute(ctx, updateSql.toString());
    }
}