package com.yeejoin.amos.patrol.business.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.DepartmentBo;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.privilege.model.DepartmentModel;
import com.yeejoin.amos.patrol.business.constants.XJConstant;
import com.yeejoin.amos.patrol.business.dao.mapper.*;
import com.yeejoin.amos.patrol.business.entity.mybatis.RiskJudgmentFillRecordBo;
import com.yeejoin.amos.patrol.business.entity.mybatis.RiskJudgmentItemBo;
import com.yeejoin.amos.patrol.business.entity.mybatis.RiskJudgmentTaskBo;
import com.yeejoin.amos.patrol.business.entity.mybatis.RiskSourceBo;
import com.yeejoin.amos.patrol.business.service.intfc.IRiskJudgmentTaskService;
import com.yeejoin.amos.patrol.business.util.RandomUtil;
import com.yeejoin.amos.patrol.business.util.StringUtil;
import com.yeejoin.amos.patrol.common.enums.*;
import com.yeejoin.amos.patrol.common.remote.RemoteWorkFlowService;
import com.yeejoin.amos.patrol.core.async.AsyncTask;
import com.yeejoin.amos.patrol.core.util.DateUtil;
import com.yeejoin.amos.patrol.feign.RemoteSecurityService;
import org.assertj.core.util.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.typroject.tyboot.core.foundation.context.RequestContext;

import java.util.*;

@Service("iSpcRiskJudgmentTaskService")
public class RiskJudgmentTaskServiceImpl implements IRiskJudgmentTaskService {

    private final Logger logger = LoggerFactory.getLogger(RiskJudgmentTaskServiceImpl.class);

    @Autowired
    private RiskJudgmentTaskMapper riskJudgmentTaskMapper;

    @Autowired
    private RiskSourceMapper riskSourceMapper;

    @Autowired
    private RiskJudgmentItemMapper riskJudgmentItemMapper;

    @Autowired
    private RiskJudgmentFillRecordMapper riskJudgmentFillRecordMapper;

    @Autowired
    private RiskFactorMapper riskFactorMapper;

    @Autowired
    private LatentDangerMapper latentDangerMapper;

    @Autowired
    private TaskworkMapper taskworkMapper;

    @Autowired
    private RemoteSecurityService remoteSecurityService;

    @Autowired
    private RemoteWorkFlowService remoteWorkFlowService;

    @Autowired
    private AsyncTask asyncTask;

    private static final String permissionType = "activitiItem";

    @Override
    public void initRiskJudgmentTask(Date date) {
        List<CompanyBo> companyBoList = remoteSecurityService.listCompanyTree();
        if (CollectionUtils.isEmpty(companyBoList)) {
            return;
        }
        List<CompanyBo> companyBos = Lists.newArrayList();
        writeCompany(companyBoList, companyBos);
        Map<String, String> deptWorkflowMap = buildDeptWorkflowMap(RequestContext.getToken(), RequestContext.getProduct(), RequestContext.getAppKey());
        for (CompanyBo c : companyBos) {
            List<DepartmentBo> departmentBos = Lists.newArrayList();
            String companyId = c.getSequenceNbr().toString();
            List<DepartmentBo> list = remoteSecurityService.getDepartmentTreeByCompanyId(companyId);
            writeDepartment(list, departmentBos);
            if (CollectionUtils.isEmpty(departmentBos)) {
                continue;
            }
            JSONObject body = new JSONObject();
            String businessKey = RandomUtil.buildOrderNo();
            body.put("processDefinitionKey", WorkFlowDefinitionKeyEnum.风险研判评审.getProcessDefinitionKey());
            body.put("businessKey", businessKey);
            body.put("companyId", c.getSequenceNbr());
            JSONObject startJson = remoteWorkFlowService.startWithAppKey(body);
            if (startJson == null) {
                logger.error(c.getCompanyName() + "启动风险研判流程失败");
                continue;
            }
            JSONObject dataList = startJson.getJSONObject("dataList");
            String instanceId = dataList.getJSONObject("historicInstance").getString("id");
            JSONArray taskInstances = dataList.getJSONArray("taskInstances");
            Map<String, JSONObject> taskDefinitionKeyMap = buildTaskDefinitionKeyMap(taskInstances);
            for (DepartmentBo departmentBo : departmentBos) {
                JSONObject taskInstance = getTaskInstanceByDeptCode(departmentBo.getDepartmentCode(), taskDefinitionKeyMap, deptWorkflowMap);
                if (taskInstance != null) {
                    List<RiskJudgmentItemBo> items = riskJudgmentItemMapper.listAllItemByDepartmentCode(departmentBo.getDepartmentCode());
                    if (CollectionUtils.isEmpty(items)) {
                        logger.error("初始化风险研判任务失败,检查项表未配置该部门，部门编号===================>" + departmentBo.getSequenceNbr());
                        continue;
                    }
                    boolean success = initRiskJudgment(taskInstance, departmentBo, date, items, c.getOrgCode(), companyId, instanceId, businessKey);
                    if (!success) {
                        logger.error("初始化风险研判任务失败，部门编号===================>" + departmentBo.getSequenceNbr());
                    }
                }
            }
        }
    }

    private JSONObject getTaskInstanceByDeptCode(String departmentCode, Map<String, JSONObject> taskDefinitionKeyMap,
                                                 Map<String, String> deptWorkflowMap) {
        return taskDefinitionKeyMap.get(deptWorkflowMap.get(departmentCode));
    }

    private Map<String, String> buildDeptWorkflowMap(String token, String product, String appKey) {
        Map<String, String> deptWorkflowMap = Maps.newHashMap();
        JSONArray deptWorkflowArray = remoteSecurityService.listDictionaryByDictCode(token, product, appKey, XJConstant.DEPT_WF_MAP_DIC_CODE);
        for (int i = 0; i < deptWorkflowArray.size(); i++) {
            JSONObject deptWorkJson = deptWorkflowArray.getJSONObject(i);
            deptWorkflowMap.put(deptWorkJson.getString("dictDataKey"), deptWorkJson.getString("dictDataValue"));
        }
        return deptWorkflowMap;
    }

    private Map<String, JSONObject> buildTaskDefinitionKeyMap(JSONArray arr) {
        Map<String, JSONObject> map = Maps.newHashMap();
        for (int i = 0; i < arr.size(); i++) {
            JSONObject object = arr.getJSONObject(i);
            map.put(object.getString("taskDefinitionKey"), object);
        }
        return map;
    }

    private boolean initRiskJudgment(JSONObject taskInstance, DepartmentBo departmentBo, Date date, List<RiskJudgmentItemBo> items, String orgCode, String companyId, String instanceId, String businessKey) {
        try {
            RiskJudgmentTaskBo riskJudgmentTaskBo = new RiskJudgmentTaskBo();
            String currentFlowTaskId = taskInstance.getString("id");
            String taskDefinitionKey = taskInstance.getString("taskDefinitionKey");
            // 获取该departmentBo部门具有研判审批权限的用户ID
            String reviewUserIds = getUserIds(taskDefinitionKey, companyId, departmentBo.getSequenceNbr().toString());
            riskJudgmentTaskBo.setBusinessKey(businessKey);
            riskJudgmentTaskBo.setFlowInstanceId(instanceId);
            riskJudgmentTaskBo.setTaskStatus(RiskJudgmentStatusEnum.未开始.getCode());
            riskJudgmentTaskBo.setTaskDefinitionKey(taskDefinitionKey);
            riskJudgmentTaskBo.setCurrentFlowTaskId(currentFlowTaskId);
            riskJudgmentTaskBo.setFlowUserIds(reviewUserIds);
            riskJudgmentTaskBo.setTaskName("风险研判任务");
            riskJudgmentTaskBo.setDepartmentId(departmentBo.getSequenceNbr().toString());
            riskJudgmentTaskBo.setTaskDate(date);
            riskJudgmentTaskBo.setOrgCode(orgCode);
            riskJudgmentTaskMapper.save(riskJudgmentTaskBo);
            List<RiskJudgmentFillRecordBo> records = Lists.newArrayList();
            for (RiskJudgmentItemBo item : items) {
                RiskJudgmentFillRecordBo record = new RiskJudgmentFillRecordBo();
                record.setTaskId(riskJudgmentTaskBo.getId());
                record.setItemId(item.getId());
                String selectResultStr = null;
                if (item.getSelectIsNeed().equals(BooleanEnum.YES.getCode())) {
                    StringBuilder selectResult = new StringBuilder();
                    JSONArray arr = JSONArray.parseArray(item.getSelectJson());
                    for (int i = 0; i < arr.size(); i++) {
                        JSONObject jsonObject = arr.getJSONObject(i);
                        if (jsonObject.getBoolean("defaultSelect")) {
                            selectResult.append(jsonObject.getString("id")).append(",");
                        }
                    }
                    if (selectResult.length() > 0) {
                        selectResultStr = selectResult.substring(0, selectResult.length() - 1);
                    }
                }
                record.setSelectResult(selectResultStr);
                Long count = getCount(item.getItemFlag(), departmentBo.getSequenceNbr().toString());
                if (count != null) {//数量回显
                    record.setInputResult(String.valueOf(count));
                }
                String defaultSelectId = getDefaultSelectId(item.getItemFlag(), departmentBo.getSequenceNbr().toString());
                if (defaultSelectId != null) {//作业活动是否可控回显
                    record.setSelectResult(defaultSelectId);
                }
                record.setOrgCode(orgCode);
                records.add(record);
            }
            riskJudgmentFillRecordMapper.saveBatch(records);
        } catch (Exception e) {
            logger.error("风险研判填写记录表初始化失败");
            return false;
        }
        return true;
    }

    private String getDefaultSelectId(String itemFlag, String deptId) {
        String defaultSelectId = null;
        Long count = null;
        switch (itemFlag) {
            case "danger_work_control_a"://重大工艺操作
                count = taskworkMapper.countViolateState(TaskworkTypeEnum.重大工艺操作.getCode(), deptId);
                break;
            case "danger_work_control_b"://检维修作业
                count = taskworkMapper.countViolateState(TaskworkTypeEnum.检维修作业.getCode(), deptId);
                break;
            case "danger_work_control_c"://特殊动火作业
                count = taskworkMapper.countViolateState(TaskworkTypeEnum.特殊动火作业.getCode(), deptId);
                break;
            case "danger_work_control_d"://一级动火作业
                count = taskworkMapper.countViolateState(TaskworkTypeEnum.一级动火作业.getCode(), deptId);
                break;
            case "danger_work_control_e"://二级动火作业
                count = taskworkMapper.countViolateState(TaskworkTypeEnum.二级动火作业.getCode(), deptId);
                break;
            case "danger_work_control_f"://进入受限空间作业
                count = taskworkMapper.countViolateState(TaskworkTypeEnum.进入受限空间作业.getCode(), deptId);
                break;
            default:
                break;
        }
        if (count != null && count > 0) {
            defaultSelectId = RiskJudgmentSelectStatusEnum.不可控.getCode();//不可控
        } else if (count != null && count == 0) {
            defaultSelectId = RiskJudgmentSelectStatusEnum.可控.getCode();//可控
        }
        return defaultSelectId;
    }

    private String getUserIds(String path, String companyId, String departmentId) {
        String reviewUserIds = "";
        List<AgencyUserModel> userModels = remoteSecurityService.listUserByMenuCode(permissionType, path);
        if (!CollectionUtils.isEmpty(userModels)) {
            List<String> userIds = Lists.newArrayList();
            for (AgencyUserModel userModel : userModels) {
                String userId = getUserIdIsInDepartmentId(departmentId, userModel, companyId);
                if (userId != null) {
                    userIds.add(userId);
                }
            }
            if (!CollectionUtils.isEmpty(userIds)) {
                reviewUserIds = Joiner.on(",").join(userIds);
            }
        }
        return reviewUserIds;
    }

    private String getUserIdIsInDepartmentId(String departmentId, AgencyUserModel userModel, String companyId) {
        Map<Long, List<DepartmentModel>> companyDepartments = userModel.getCompanyDepartments();
        List<DepartmentModel> departments = companyDepartments.get(Long.valueOf(companyId));
        if (!CollectionUtils.isEmpty(departments)) {
            for (DepartmentModel departmentModel : departments) {
                if (departmentModel.getSequenceNbr().toString().equals(departmentId)) {
                    return userModel.getUserId();
                }
            }
        }
        return null;
    }

    public Long getCount(String flag, String deptId) {
        Long count = null;
        switch (flag) {
            case "other_latent_danger_state_"://安全问题--
                count = latentDangerMapper.countNotFinishByTypeAndDeptId(0, deptId);
                break;
            case "other_latent_danger_state_a"://一般隐患--
                count = latentDangerMapper.countNotFinishByTypeAndDeptId(1, deptId);
                break;
            case "other_latent_danger_state_b"://重大隐患--
                count = latentDangerMapper.countNotFinishByTypeAndDeptId(2, deptId);
                break;
            case "other_latent_danger_state_c"://重大风险-1级
                count = riskFactorMapper.countByLevelCodeAndDeptId(RiskLevelEnum.level_1.getCode(), deptId);
                break;
            case "other_latent_danger_state_d"://较大风险-2级
                count = riskFactorMapper.countByLevelCodeAndDeptId(RiskLevelEnum.level_2.getCode(), deptId);
                break;
            case "other_latent_danger_state_e"://一般风险-3级
                count = riskFactorMapper.countByLevelCodeAndDeptId(RiskLevelEnum.level_3.getCode(), deptId);
                break;
            case "other_latent_danger_state_f"://低风险-4级
                count = riskFactorMapper.countByLevelCodeAndDeptId(RiskLevelEnum.level_4.getCode(), deptId);
                break;
            case "danger_work_control_a"://重大工艺操作
                count = taskworkMapper.countByTypeAndDeptId(TaskworkTypeEnum.重大工艺操作.getCode(), deptId);
                break;
            case "danger_work_control_b"://检维修作业
                count = taskworkMapper.countByTypeAndDeptId(TaskworkTypeEnum.检维修作业.getCode(), deptId);
                break;
            case "danger_work_control_c"://特殊动火作业
                count = taskworkMapper.countByTypeAndDeptId(TaskworkTypeEnum.特殊动火作业.getCode(), deptId);
                break;
            case "danger_work_control_d"://一级动火作业
                count = taskworkMapper.countByTypeAndDeptId(TaskworkTypeEnum.一级动火作业.getCode(), deptId);
                break;
            case "danger_work_control_e"://二级动火作业
                count = taskworkMapper.countByTypeAndDeptId(TaskworkTypeEnum.二级动火作业.getCode(), deptId);
                break;
            case "danger_work_control_f"://进入受限空间作业
                count = taskworkMapper.countByTypeAndDeptId(TaskworkTypeEnum.进入受限空间作业.getCode(), deptId);
                break;
            default:
                break;
        }
        return count;
    }

    private void writeCompany(List<CompanyBo> tree, List<CompanyBo> companyBos) {
        tree.forEach(d -> {
            companyBos.add(d);
            if (!CollectionUtils.isEmpty(d.getChildren())) {
                writeCompany(d.getChildren(), companyBos);
            }
        });
    }

    private void writeDepartment(List<DepartmentBo> tree, List<DepartmentBo> departmentBos) {
        tree.forEach(d -> {
            if (d.getLevel().equals("shop")) {
                departmentBos.add(d);
            }
            if (!CollectionUtils.isEmpty(d.getChildren())) {
                writeDepartment(d.getChildren(), departmentBos);
            }
        });
    }

    @Override
    public void updateRiskJudgmentTaskToOverTime(Date date) {
        String dateStr = DateUtil.formatDatrToStr(date, DateUtil.SHORT_PATTERN);
        RiskJudgmentTaskStatusEnum statusEnum = RiskJudgmentTaskStatusEnum.已超时;
        List<RiskJudgmentTaskBo> taskBos = riskJudgmentTaskMapper.listByDateAndStatus(dateStr, RiskJudgmentTaskStatusEnum.进行中.getCode());
        taskBos.forEach(e -> {
            e.setTaskStatus(statusEnum.getCode());
            try {
                String cdate = DateUtil.formatDatrToStr(e.getTaskDate(), "yyyy年MM月dd日");
                String userIds = e.getFlowUserIds();
                Set<String> userIdSet = Sets.newHashSet(Arrays.asList(userIds.split(",")));
                List<AgencyUserModel> reviewUserModels = remoteSecurityService.listUserByMenuCode(permissionType, e.getTaskDefinitionKey() + "_1");
                List<AgencyUserModel> companyReviewUserModels = remoteSecurityService.listUserByMenuCode(permissionType, "G_9");
                if (!CollectionUtils.isEmpty(reviewUserModels)) {
                    userIdSet.addAll(Lists.transform(reviewUserModels, AgencyUserModel::getUserId));
                }
                if (!CollectionUtils.isEmpty(companyReviewUserModels)) {
                    userIdSet.addAll(Lists.transform(companyReviewUserModels, AgencyUserModel::getUserId));
                }
                DepartmentBo departmentBo = remoteSecurityService.getDepartmentByDeptId(e.getDepartmentId());
                asyncTask.pushRiskJudgmentMessage(this.getNextExecuteUsers(e.getFlowInstanceId()), e.getOrgCode(), e.getTaskName(),
                        cdate, departmentBo.getDepartmentName(),
                        statusEnum.getName(), e.getId(), statusEnum.getCode());
            } catch (Exception ex) {
                logger.error("风险研判推送异常", ex);
            }

        });
        if (taskBos.size() > 0) {
            riskJudgmentTaskMapper.updateBatch(taskBos);
        }
    }

    @Override
    public void updateRiskJudgmentTaskToProcess(Date date) {
        String dateStr = DateUtil.formatDatrToStr(date, DateUtil.SHORT_PATTERN);
        RiskJudgmentTaskStatusEnum statusEnum = RiskJudgmentTaskStatusEnum.进行中;
        List<RiskJudgmentTaskBo> taskBos = riskJudgmentTaskMapper.listByDateAndStatus(dateStr, RiskJudgmentTaskStatusEnum.未开始.getCode());
        taskBos.forEach(e -> {
            e.setTaskStatus(statusEnum.getCode());
            try {
                String cdate = DateUtil.formatDatrToStr(e.getTaskDate(), "yyyy年MM月dd日");
                DepartmentBo departmentBo = remoteSecurityService.getDepartmentByDeptId(e.getDepartmentId());
                Set<String> userIds = Sets.newHashSet(Arrays.asList(e.getFlowUserIds().split(",")));
                asyncTask.pushRiskJudgmentMessage(this.getNextExecuteUsers(e.getFlowInstanceId()), e.getOrgCode(),
                        e.getTaskName(), cdate, departmentBo.getDepartmentName(),
                        statusEnum.getName(), e.getId(), e.getTaskStatus());
            } catch (Exception ex) {
                logger.error("风险研判推送异常", ex);
            }
        });
        if (taskBos.size() > 0) {
            riskJudgmentTaskMapper.updateBatch(taskBos);
        }
    }

    @Override
    public void freshRiskJudgmentLangerCount(Long riskSourceId) {
        RiskSourceBo riskSource = riskSourceMapper.getById(riskSourceId);
        if (riskSource != null && StringUtil.isNotEmpty(riskSource.getBelongDepartmentId())) {
            Long count1 = latentDangerMapper.countNotFinishByTypeAndDeptId(1, riskSource.getBelongDepartmentId());
            Long count2 = latentDangerMapper.countNotFinishByTypeAndDeptId(2, riskSource.getBelongDepartmentId());
            Long count0 = latentDangerMapper.countNotFinishByTypeAndDeptId(0, riskSource.getBelongDepartmentId());
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("departmentId", riskSource.getBelongDepartmentId());
            map.put("inputResult", count1);
            map.put("taskStatus", RiskJudgmentTaskStatusEnum.进行中.getCode());
            map.put("itemFlag", "other_latent_danger_state_a");
            riskJudgmentFillRecordMapper.updateInputResultAndselectResult(map);//更新一般隐患数量
            map.put("inputResult", count2);
            map.put("itemFlag", "other_latent_danger_state_b");
            riskJudgmentFillRecordMapper.updateInputResultAndselectResult(map);//更新重大隐患数量
            map.put("inputResult", count0);
            map.put("itemFlag", "other_latent_danger_state_z");
            riskJudgmentFillRecordMapper.updateInputResultAndselectResult(map);//更新安全问题数量
        }
    }

    @Override
    public void freshRiskJudgmentTaskwork(String deptId) {
        //循环更新riskJudgmentFillRecordMapper 的 select_result and input_result
        Long count = 0L;
        String defaultSelectId = null;
        Map<String, Object> paramMap = new HashMap<String, Object>();
        for (RiskJudgeTaskworkTypeEnum eum : RiskJudgeTaskworkTypeEnum.values()) {
            count = getCount(eum.getIntemFlag(), deptId);//查询条件:  部门  + 类型
            defaultSelectId = getDefaultSelectId(eum.getIntemFlag(), deptId);//查询条件:  部门  + 类型
            paramMap.clear();
            paramMap.put("departmentId", deptId);
            paramMap.put("inputResult", count);
            paramMap.put("selectResult", defaultSelectId);
            paramMap.put("taskStatus", RiskJudgmentTaskStatusEnum.进行中.getCode());
            paramMap.put("itemFlag", eum.getIntemFlag());
            riskJudgmentFillRecordMapper.updateInputResultAndselectResult(paramMap);
        }
    }

    //获取下一节点需要发消息的用户信息
    public  String getNextExecuteUsers(String  instanceId) {
        String informerList= "";
        JSONObject object =  remoteWorkFlowService.getChildNodeDetail(instanceId);
        if(object!=null){
            JSONArray array  = object.getJSONArray("data");
            JSONObject workFlowDetail = array.getJSONObject(0);
            informerList =  workFlowDetail.getString("informerList");
        }
        return informerList;
    }
}
