package nckd.jimin.jyyy.hr.hrmp.hbpm.task;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import kd.bos.algo.DataSet;
import kd.bos.algo.Row;
import kd.bos.context.RequestContext;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.db.DB;
import kd.bos.db.DBRoute;
import kd.bos.exception.KDException;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.orm.util.CollectionUtils;
import kd.bos.schedule.executor.AbstractTask;
import kd.bos.util.StringUtils;
import kd.hr.haos.business.servicehelper.AdminOrgQueryServiceHelper;
import kd.sdk.plugin.Plugin;
import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 2025-04-16 Tyx
 * 组织变动数据同步MDM
 * 1.组织名称变化/组织调整时，需要把该组织下所有岗位及人员也传给MDM
 * 2.其余变化时，只需要传递组织信息，岗位人员不需要
 * 2025-06-14 Tyx
 * 去除只变化排序码的情况，MDM中不需要排序码，避免MDM生成伪版本
 */
public class SyncAdminOrgTask extends AbstractTask implements Plugin {

    private static final Log log = LogFactory.getLog(SyncAdminOrgTask.class);
    private static String changeOperDetail_entity = "haos_changeoperdetail";
    private static String adminOrgDetail_entity = "haos_adminorgdetail";
    private static String orgChgRecord_entity = "homs_orgchgrecord";
    private static String orgChgRecord_e_entity = "orgchgentry";
    private static String startTime = "";
    private static String endTime = "";



    @Override
    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
        /**
         * 获取调度作业下配置的参数：
         * isAuto : 如果配置为是，则取日志中上一次同步时间至今发生变化的组织信息，为否则优先取以下两个手工配置的时间参数
         * startTime : 手工配置开始时间 yyyy-MM-dd hh24:mi:ss
         * endTime : 手工配置结束时间 yyyy-MM-dd hh24:mi:ss
         */
        try {
            log.info("-------- SyncAdminOrgTask 开始执行同步行政组织 --------");
            //最后调MDM的jsonObject
            JSONObject ob = new JSONObject();
            JSONObject posOb = new JSONObject();
            JSONObject personOb = new JSONObject();
            initDateRange(map);
            HRBaseServiceHelper helper = new HRBaseServiceHelper(orgChgRecord_entity);
            String selectProperties = "adminorg,orgchgentry.changescene.number,orgchgentry.operationtime,orgchgentry.subentryentity.chgpageelement";
            //查出发生过变化的组织
            DynamicObjectCollection changeOperateCol = helper.queryOriginalCollection(selectProperties, this.getQFilters());
            //查询出来为空直接返回
            if(CollectionUtils.isEmpty(changeOperateCol)) {
                log.info("-------- 未查询到变化组织 -------- ");
                SyncUtil.createLog(SyncUtil.v_success, startTime, endTime, "未查询到变化组织", "未调用", SyncUtil.SyncOrg);
            }
            else {
//            Map<String, List<DynamicObject>> changeOperateMap = (Map)changeOperateCol.stream().collect(Collectors.groupingBy(
//                            dyx -> dyx.getString("orgchgentry.changescene.number")
//                    ));
                //按组织ID汇总
                Map<Long, DynamicObject> changeOperateMap = (Map)changeOperateCol.stream().collect(Collectors.toMap((dyx) -> {
                    return dyx.getLong("adminorg");
                }, (dyx) -> {
                    return dyx;
                }, (key1, key2) -> {
                    return key2;
                }));
                log.info("-------- 变化组织数（不去重）：" + changeOperateCol.size() + " --------");
                log.info("-------- 变化组织数（去重）：" + changeOperateMap.keySet().size() + " --------");
                log.info("-------- 变化组织Id：" + changeOperateMap.keySet() + " --------");

                //过滤出上级调整和修改名称的组织
                List<Long> changeOrgIdList = changeOperateCol.stream().filter(dyx -> dyx.get("orgchgentry.changescene.number").equals("1020_S") || dyx.get("orgchgentry.changescene.number").equals("1030_S"))
                        .map(dyx -> dyx.getLong("adminOrg")).collect(Collectors.toList());
                //查询所有下级组织
                List<Map<String, Object>> a = AdminOrgQueryServiceHelper.batchQueryAllSubOrg(changeOrgIdList, new Date());
                //转换成Set
                Set subOrgIdset = a.stream().map(i -> i.get("orgId")).collect(Collectors.toSet());
                //组织历史查询，如果查询时间内发生多次变化，
                //haos_adminorgdetail 组织历史查询 所属表t_haos_adminorg Id与t_org_org一样
                selectProperties = "id,boid,number,name,orglongname,level,nckd_easid,parentorg.id,parentorg.name,parentorg.number,parentorg.nckd_easid,establishmentdate,bsed,enable,adminorgtype.name,disabledate,modifytime,creator.name";
                //合并Set 变化组织的IdSet+更名/调整上级的下级所有组织的IdSet
                Set totalOrgSet = (Set) Stream.concat(subOrgIdset.stream(), changeOperateMap.keySet().stream()).collect(Collectors.toSet());
                QFilter idQFilter = new QFilter("id", "in", totalOrgSet);
                DynamicObject[] orgDyArr = new HRBaseServiceHelper(adminOrgDetail_entity).query(selectProperties, new QFilter[]{idQFilter});
                //处理下长编码/长名称，星瀚内是4VTX1ACRU8A9!4VU/45/K1PJZ!4W5LG9NNW9EW这种格式 -- 直接取行政组织结构里面的长编码
                Map<Long, DynamicObject> bosOrgMap = SyncUtil.initOrgInfo();
                log.info("-------- 查询完组织详细信息数：" + orgDyArr.length + " --------");
                //构建入参
                buildJSON(ob, orgDyArr, changeOperateMap, bosOrgMap);
                //构建岗位入参
                buildPosJSON(posOb, totalOrgSet, bosOrgMap);
                //构建人员入参
                buildPersonJSON(personOb, totalOrgSet, bosOrgMap);
                //获取调用接口地址
                String url = SyncUtil.getUrl("org_url");
                SyncUtil.batchPost(url, ob, SyncUtil.SyncOrg, startTime, endTime);

                //组织下级岗位同步：
                if(posOb.getJSONArray("obj").size() > 0) {
                    url = SyncUtil.getUrl("position_url");
                    SyncUtil.batchPost(url, posOb, SyncUtil.SyncOrg_Position, startTime, endTime);
                }

                //组织下级员工同步：
                if(personOb.getJSONArray("obj").size() > 0) {
                    url = SyncUtil.getUrl("person_url");
                    SyncUtil.batchPost(url, personOb, SyncUtil.SyncOrg_Person, startTime, endTime);
                }
            }
        } catch (ParseException e) {
            SyncUtil.createLog(SyncUtil.v_error, startTime, endTime, e.getMessage(), "未调用", SyncUtil.SyncOrg);
        } catch (IOException e) {
            SyncUtil.createLog(SyncUtil.v_error, startTime, endTime, e.getMessage(), "未调用", SyncUtil.SyncOrg);
        }
    }

    /**
     * 构建最后调用MDM接口的参数
     * @param ob
     */
    public void buildJSON(JSONObject ob, DynamicObject[] orgDyArr, Map<Long, DynamicObject> changeOperateMap, Map<Long, DynamicObject> bosOrgMap) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        JSONArray obj = new JSONArray();
        Map<Long, DynamicObject> costCenterMap = SyncUtil.getCostCenter();
        for(DynamicObject org : orgDyArr) {
            JSONObject data = new JSONObject(true);
            //主体标签 默认JY
            data.put("MAIN_BODY_ID", "JY");
            //主键 EAS老组织用EASID 否则用星瀚ID
            String primary_key = StringUtils.isBlank(org.getString("nckd_easid")) ? org.getPkValue().toString() : org.getString("nckd_easid");
            data.put("ADM_PRIMARY_KEY", primary_key);
            //长编码
            data.put("ADM_LONG_CODE", bosOrgMap.get(org.getLong("id")).getString("structure.longnumber"));
            //组织名称
            data.put("MD_DESCRIPTION", org.getString("name"));
            //上级行政组织ID 看是否有easid 有就传EASID 否则传星瀚ID
            String parent_primary_key = StringUtils.isBlank(org.getString("parentorg.nckd_easid")) ? String.valueOf(org.getLong("parentorg.id")) : org.getString("parentorg.nckd_easid");
            data.put("ADM_PARENT_NUMER", parent_primary_key);
            //上级组织名称
            data.put("ADM_PARENT_NAME", org.getString("parentorg.name"));
            //行政组织长名称 orglongname没值 去平台那边取
            data.put("ADM_LONG_NAME", bosOrgMap.get(org.getLong("id")).getString("structure.fullname"));
            //业务板块 默认11-济煜医药
            data.put("ADM_BUSINESS_SECTOR", "11");
            //级别
            data.put("MD_LEVEL", org.getInt("level"));
            //行政组织类型
            data.put("ADM_TYPE", org.getString("adminorgtype.name"));
            //行政组织旧编码，s-HR中的组织导到星瀚中前面加了JY-，后续新增的使用星瀚的编码规则
            String orgNumber = org.getString("number");
            if(orgNumber.indexOf("JY-") == 0) {
                data.put("ADM_OLD_NUMER", orgNumber.substring(3, orgNumber.length()));
            }
            else {
                data.put("ADM_OLD_NUMER", orgNumber);
            }
            //创建时间 取行政组织的创建时间
            Date createDate = bosOrgMap.get(org.getLong("id")).getDate("createtime");
            data.put("ADM_CREATOR", org.getString("creator.name"));
            data.put("ADM_CREATION_TIME", sdf.format(createDate));
            //最后修改时间
            data.put("ADM_LAST_UPTIME", sdf.format(org.getDate("modifytime")));
            //行政组织是否封存 enable 0-已停用 1-已启用
            int enable = org.getInt("enable");
            if(enable == 0) {
                data.put("ADM_SEALUP", "是");
                //行政组织封存时间
                Date disableDate = org.getDate("disabledate");
                data.put("ADM_STORAGE_TIME", sdf.format(disableDate));
            }
            else {
                data.put("ADM_SEALUP", "否");
                data.put("ADM_STORAGE_TIME", null);
            }
            DynamicObject costCenter = costCenterMap.get(org.getLong("id"));
            if(costCenter == null) {
                //是否成本中心实体组织
                data.put("ADM_ENTITY_COST_CENTER", "否");
                //是否成本中心组织
                data.put("ADM_COST_CENTER", "否");
                //成本中心是否封存
                data.put("ADM_COST_CENTER_SEALUP", "否");
            }
            else {
                data.put("ADM_COST_CENTER", "是");
                if(costCenter.getBoolean("costcenter.isleaf")) {
                    data.put("ADM_ENTITY_COST_CENTER", "是");
                }
                else {
                    data.put("ADM_ENTITY_COST_CENTER", "否");
                }
                int ccEnable = costCenter.getInt("costcenter.enable");
                if(ccEnable == 1) {
                    data.put("ADM_COST_CENTER_SEALUP", "否");
                }
                else {
                    data.put("ADM_COST_CENTER_SEALUP", "是");
                }
            }

            obj.add(data);
        }
        SyncUtil.setJSONArraySorted(obj, "MD_LEVEL");
        ob.put("obj", obj);
    }

    /**
     * 构建职位入参
     * @param ob
     * @param totalOrgSet
     * @param bosOrgMap
     */
    private void buildPosJSON(JSONObject ob, Set totalOrgSet, Map<Long, DynamicObject> bosOrgMap) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String selectFields = "id,adminorg.id,adminorg.name,adminorg.number,adminorg.nckd_easid,parent.name,parent.id,parent.number,number,name,enable,isleader,modifytime,issensitive,nckd_isgxp";
        QFilter filter = new QFilter("adminorg.id", QCP.in, totalOrgSet);
        filter.and("iscurrentversion",QCP.equals,"1");
        DynamicObjectCollection posDyArr = new HRBaseServiceHelper("hbpm_positionhr").queryOriginalCollection(selectFields, new QFilter[]{filter});
        //构造岗位的树形结构
        Map<Long, Integer> levelMap = SyncUtil.initPositionTree();
        JSONArray obj = new JSONArray();
        for(DynamicObject pos : posDyArr) {
            JSONObject data = new JSONObject(true);
            //主体标签
            data.put("MAIN_BODY_ID", "JY");
            //级别
            data.put("MD_LEVEL", levelMap.get(pos.getLong("id")));
            //所属行政组织名称
            data.put("POSI_SUB_DEP_NAME",pos.getString("adminorg.name"));
            //所属行政组织ID 老岗位用EASID 新岗位用星瀚ID
            String parentId = StringUtils.isBlank(pos.getString("adminorg.nckd_easid")) ? pos.getString("adminorg.id") : pos.getString("adminorg.nckd_easid");
            data.put("POSI_SUB_DEP_CODE",parentId);
            //所属行政组织全程 长名称
            data.put("POSI_SUB_DEP_LNAME",bosOrgMap.get(pos.getLong("adminorg.id")).getString("structure.fullname"));
            //汇报岗位名称
            data.put("POSI_REPPOST_NAME",pos.getString("parent.name"));
            //汇报岗位编码
            data.put("POSI_REPPOST_CODE",pos.getString("parent.number"));
            //岗位编码
            data.put("MD_CODE",pos.getString("number"));
            //岗位名称
            data.put("MD_DESCRIPTION",pos.getString("name"));
            //岗位状态 MDM:1-启用，2-禁用；星瀚：1-启用，0-禁用
            int enable = pos.getInt("enable");
            if(enable == 1) {
                data.put("POSI_STATE","1");
            }
            else if(enable == 0){
                data.put("POSI_STATE","2");
            }
            else {
                data.put("POSI_STATE","0");
            }
            //是否负责人职位
            int isLeader = pos.getInt("isleader");
            if(isLeader == 1) {
                data.put("POSI_POSIT_CHARGE","是");
            }
            else {
                data.put("POSI_POSIT_CHARGE","否");
            }
            //是否涉密岗位
            int isSecret = pos.getInt("issensitive");
            if(isSecret == 1) {
                data.put("POSI_IS_SECRET","是");
            }
            else {
                data.put("POSI_IS_SECRET","否");
            }
            //是否GXP
            int isGxp = pos.getInt("nckd_isgxp");
            if(isGxp == 1) {
                data.put("POSI_IS_GXP","是");
            }
            else {
                data.put("POSI_IS_GXP","否");
            }
            //最后更新时间
            data.put("POSI_LAST_UPTIME",sdf.format(pos.getDate("modifytime")));
            obj.add(data);
        }
        //入参排序
        SyncUtil.setJSONArraySorted(obj, "MD_LEVEL");
        ob.put("obj", obj);
    }

    /**
     * 构建人员入参
     * @param personOb
     * @param totalOrgSet
     * @param bosOrgMap
     */
    private void buildPersonJSON(JSONObject personOb, Set totalOrgSet, Map<Long, DynamicObject> bosOrgMap) {
        Map<Long, JSONArray> partTimeMap = SyncUtil.getPartTimeInfo(bosOrgMap);
        StringBuilder sb = SyncUtil.getPersonQuerySql();
        String ids = (totalOrgSet.stream().map(Object::toString).collect(Collectors.joining(","))).toString();
        sb.append(" and org.fid in (").append(ids).append(") ");
        DataSet dataSet = DB.queryDataSet(this.getClass().getName(), DBRoute.of("hr"), sb.toString());
        JSONArray obj = new JSONArray();
        String[] fieldNames = dataSet.getRowMeta().getFieldNames();
        while(dataSet.hasNext()) {
            JSONObject data = new JSONObject(true);
            Row rowData = dataSet.next();
            //循环put数据
            for (String field : fieldNames) {
                data.put(field.toUpperCase(), rowData.get(field));
            }
            //处理组织长名称
            data.put("EMP_W_DEPLNAME", bosOrgMap.get(rowData.getLong("orgid")).getString("structure.fullname"));
            data.put("EMP_W_EMPLOYNUMBER", "test-20250401-0011");

            //处理兼职
            JSONArray partJob = partTimeMap.get(rowData.getLong("PERSONID"));
            if(partJob != null) {
                data.put("partJob", partJob);
            }
            obj.add(data);
        }
        personOb.put("obj", obj);
    }

    /**
     * 根据调度作业上配置的参数初始化时间范围
     * @param map
     */
    public void initDateRange(Map<String, Object> map) throws ParseException {
        boolean isAuto = Boolean.valueOf(map.get("isAuto").toString());
        if(!isAuto) {
            startTime = map.get("startTime").toString();
            endTime = map.get("endTime").toString();
        }
        //取最近一次日志的时间
        else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            startTime = sdf.format(SyncUtil.getLastSyncEndTime(SyncUtil.SyncOrg));
            endTime = sdf.format(new Date());
        }
    }

    /**
     * 构建查询变化组织的过滤条件
     * @return
     */
    public QFilter[] getQFilters() {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            QFilter filter = new QFilter("orgchgentry.operationtime", ">=", sdf.parse(startTime));
            filter.and("orgchgentry.operationtime", "<", sdf.parse(endTime));

            QFilter filter1 = new QFilter("orgchgentry.subentryentity.chgpageelement", QCP.not_equals2, "index");
            filter1.or("orgchgentry.subentryentity.chgpageelement", QCP.is_null, "");

            filter.and(filter1);
            //filter.and("org.otclassify", "=", 1010L);
            //filter.and("adminorg.number", QCP.equals, "JY-20240612-0009");
            log.info("-------- 查询组织变化过滤条件：" + filter.toString() + " --------");
            return new QFilter[]{filter};
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

}