package com.yeejoin.amos.boot.biz.common.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Sets;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.enums.WorkFlowEnum;
import com.yeejoin.amos.boot.biz.common.service.IWorkflowExcuteService;
import com.yeejoin.amos.boot.biz.common.workflow.feign.WorkflowFeignService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WorkflowExcuteServiceImpl implements IWorkflowExcuteService {

    @Autowired
    WorkflowFeignService workflowFeignService;

    public static String buildOrderNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String newDate = sdf.format(new Date());
        String result = "";
        Random random = new Random();
        for (int i = 0; i < 3; i++) {
            result += random.nextInt(10);
        }
        return newDate + result;
    }

    @Transactional
    @Override
    public String startAndComplete(String key, String condition) throws Exception {
        JSONObject body = new JSONObject();
        String businessKey = buildOrderNo();
        body.put(WorkFlowEnum.BUSINESSKEY.getCode(), businessKey);
        body.put(WorkFlowEnum.processDefinitionKey.getCode(), key);
        JSONObject jsonObject = workflowFeignService.startByVariable(body);
        if (jsonObject == null || jsonObject.getJSONObject(WorkFlowEnum.DATA.getCode()) == null) {
            throw new RuntimeException("启动流程失败");
        }
        if (jsonObject != null) {
            JSONObject instance = jsonObject.getJSONObject(WorkFlowEnum.DATA.getCode());
            if (!excuteTask(instance.getString(WorkFlowEnum.ID.getCode()), condition)) {
                throw new RuntimeException("初始执行任务失败");
            }
        }
        return jsonObject.getJSONObject(WorkFlowEnum.DATA.getCode()).getString(WorkFlowEnum.ID.getCode());
    }

    @Override
    public boolean checkTaskAuth(String processInstanceId, ReginParams userInfo) {
        Map<String, Object> map = checkTaskAuthMap(processInstanceId, userInfo);
        return Boolean.parseBoolean(map.get(WorkFlowEnum.CHECKFLAG.getCode()).toString());
    }

    @Override
    public Map<String, Object> checkTaskAuthMap(String processInstanceId, ReginParams userInfo) {
        // 获取当前登录用户的所有角色
        Set<String> roleNameSet = Sets.newHashSet();
        if (!ValidationUtil.isEmpty(userInfo.getUserModel().getOrgRoles())) {
            userInfo.getUserModel().getOrgRoles().values().forEach(i -> {
                i.forEach(e -> {
                    roleNameSet.add(e.getRoleName());
                });
            });
        }
        String currentLoginUserName = userInfo.getUserModel().getUserName();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put(WorkFlowEnum.CHECKFLAG.getCode(), false);
        JSONObject teskObject = workflowFeignService.getTaskList(processInstanceId);
        if (ObjectUtils.isNotEmpty(teskObject.getJSONArray(WorkFlowEnum.DATA.getCode()))) {
            JSONArray taskDetailArray = teskObject.getJSONArray(WorkFlowEnum.DATA.getCode());
            for (Object obj : taskDetailArray) {
                JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
                if (WorkFlowEnum.制定计划内容.getCode().equals(detail.getString(WorkFlowEnum.NAME.getCode()))
                        || WorkFlowEnum.现场确认.getCode().equals(detail.getString(WorkFlowEnum.NAME.getCode()))) {
                    String groupName = getFristFlowDetail(processInstanceId);
                    if (StringUtils.isNotBlank(groupName) && roleNameSet.contains(groupName)) {
                        map.put(WorkFlowEnum.TASKID.getCode(), detail.getString(WorkFlowEnum.ID.getCode()));
                        map.put(WorkFlowEnum.CHECKFLAG.getCode(), true);
                        map.put(WorkFlowEnum.NAME.getCode(), detail.getString(WorkFlowEnum.NAME.getCode()));
                        return map;
                    }
                }
                JSONObject taskGroupNameObject = workflowFeignService
                        .getTaskGroupName(detail.getString(WorkFlowEnum.ID.getCode()));
                // 获取流程中原本设置的当前节点的执行权限
                JSONArray taskGroupNameDetail = taskGroupNameObject.getJSONArray(WorkFlowEnum.DATA.getCode());
                // 如果拿不到当前任务的执行角色，再去获取当前任务有没有默认的执行人，如果都没有则返回校验失败
                if (ObjectUtils.isEmpty(taskGroupNameDetail)) {
                    JSONObject taskAssignObject = workflowFeignService
                            .getTaskAssign(detail.getString(WorkFlowEnum.ID.getCode()));
                    String assignUser = taskAssignObject.getJSONObject(WorkFlowEnum.DATA.getCode())
                            .getString(WorkFlowEnum.ASSIGN.getCode());
                    if (StringUtils.isNotBlank(assignUser)) {
                        // 如果当前登录人与当前任务的设定人不一定，则直接返回权限校验失败
                        if (!assignUser.contains(currentLoginUserName)) {
                            return map;
                        }
                        map.put(WorkFlowEnum.TASKID.getCode(), detail.getString(WorkFlowEnum.ID.getCode()));
                        map.put(WorkFlowEnum.CHECKFLAG.getCode(), true);
                        map.put(WorkFlowEnum.NAME.getCode(), detail.getString(WorkFlowEnum.NAME.getCode()));
                        map.put(WorkFlowEnum.ASSIGN.getCode(), assignUser);
                        return map;
                    }
                    continue;
                }
                String defaultExecutionRoleProcess = taskGroupNameDetail.getJSONObject(0)
                        .getString(WorkFlowEnum.GROUPID.getCode());

                if (StringUtils.isBlank(defaultExecutionRoleProcess)) {
                    continue;
                }
                // 判断当前登录人的角色是不是与流程中设置的当前任务节点权限一致，一致则执行，不一致则退出
                if (!roleNameSet.contains(defaultExecutionRoleProcess)) {
                    continue;
                }
                map.put(WorkFlowEnum.TASKID.getCode(), detail.getString(WorkFlowEnum.ID.getCode()));
                map.put(WorkFlowEnum.CHECKFLAG.getCode(), true);
                map.put(WorkFlowEnum.NAME.getCode(), detail.getString(WorkFlowEnum.NAME.getCode()));
                map.put(WorkFlowEnum.GROUPNAME.getCode(), defaultExecutionRoleProcess);
            }
        }
        return map;
    }

    @Override
    public boolean excuteTask(String procressId, String condition) throws Exception {
        HashMap<String, Object> conditionMap = new HashMap<String, Object>();
        conditionMap.put(WorkFlowEnum.CONDITION.getCode(), condition);
        JSONObject teskObject = workflowFeignService.getTaskList(procressId);
        if (ObjectUtils.isNotEmpty(teskObject)) {
            JSONArray taskDetailArray = teskObject.getJSONArray(WorkFlowEnum.DATA.getCode());
            for (Object obj : taskDetailArray) {
                JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
                workflowFeignService.pickupAndCompleteTask(detail.getString(WorkFlowEnum.ID.getCode()), conditionMap);
            }
        }
        return true;
    }

    @Override
    public Object setTaskAssign(String processInstanceId, String userId) {
        JSONObject teskObject = workflowFeignService.getTaskList(processInstanceId);
        if (ObjectUtils.isEmpty(teskObject)) {
            throw new RuntimeException("设置任务执行人失败, 任务不存在，请检查processInstanceId" + processInstanceId + "是否正确");
        }
        JSONArray taskDetailArray = teskObject.getJSONArray(WorkFlowEnum.DATA.getCode());
        for (Object obj : taskDetailArray) {
            JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
            JSONObject taskGroupNameObject = workflowFeignService
                    .getTaskGroupName(detail.getString(WorkFlowEnum.ID.getCode()));
            try {
                if (taskGroupNameObject.getJSONArray(WorkFlowEnum.DATA.getCode()) == null
                        || taskGroupNameObject.getJSONArray(WorkFlowEnum.DATA.getCode()).size() < 1) {
                    workflowFeignService.setTaskUser(detail.getString(WorkFlowEnum.ID.getCode()), userId);
                }
            } catch (Exception e) {
                throw new RuntimeException("设置任务执行人失败");
            }
        }
        return true;
    }

    @Override
    public boolean CompleteTask(String processInstanceId, String condition, ReginParams userInfo) {
        Map<String, Object> map = checkTaskAuthMap(processInstanceId, userInfo);
        if (Boolean.parseBoolean(map.get(WorkFlowEnum.CHECKFLAG.getCode()).toString())) {
            HashMap<String, Object> conditionMap = new HashMap<String, Object>();
            conditionMap.put(WorkFlowEnum.CONDITION.getCode(), condition);
            try {
                workflowFeignService.pickupAndCompleteTask(map.get(WorkFlowEnum.TASKID.getCode()).toString(),
                        conditionMap);
            } catch (Exception e) {
                throw new RuntimeException("完成任务失败");
            }
        } else {
            throw new RuntimeException("没有执行权限");
        }
        return true;
    }

    /**
     * 描述： 获取在流程启动时，直接完成的特定任务的执行角色信息。
     * 作用：用来判断当前登录用户在任务回退到启动并完成的哪一步任务的执行权限，以及获取当前登录用户所属角色能够处理的当前任务的列表数据
     *
     * @param processInstanceId
     * @return
     */
    public String getFristFlowDetail(String processInstanceId) {
        try {

            JSONObject historyTaskJsonObject = workflowFeignService
                    .getHistoricTaskForProcessInstanceId(processInstanceId);
            if (ObjectUtils.isEmpty(historyTaskJsonObject.getJSONArray(WorkFlowEnum.DATA.getCode()))) {
                return null;
            }
            JSONObject historyTaskObject = historyTaskJsonObject.getJSONArray(WorkFlowEnum.DATA.getCode())
                    .getJSONObject(0);
            JSONObject detail = workflowFeignService
                    .getHistoricIdentityLinksForTask(historyTaskObject.getString(WorkFlowEnum.ID.getCode()));
            JSONArray resultArray = detail.getJSONArray(WorkFlowEnum.DATA.getCode());
            if (ObjectUtils.isNotEmpty(resultArray)) {
                for (int i = 0; i < resultArray.size(); i++) {
                    JSONObject result = resultArray.getJSONObject(i);
                    if (result.getBooleanValue(WorkFlowEnum.GROUP.getCode())) {
                        return result.getString(WorkFlowEnum.GROUPID.getCode());
                    }
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取当前登录用户所能执行的任务信息列表
     *
     * @param key
     * @param userInfo
     * @return List<map < String, String>> eg: [{ "processInstanceId": "110d3af9-1f5a-11ec-a26e-b07b25133c48"}]
     * @throws Exception
     */
    @Override
    public Object getCurrentUserAllTaskList(String key, ReginParams userInfo) throws Exception {
        // 获取当前登录人的所有角色名
        Set<String> roleNameSet = Sets.newHashSet();
        if (!ValidationUtil.isEmpty(userInfo.getUserModel().getOrgRoles())) {
            userInfo.getUserModel().getOrgRoles().values().forEach(i -> {
                i.forEach(e -> {
                    roleNameSet.add(e.getRoleName());
                });
            });
        }
        JSONObject CurrentUserAllTaskResult = null;
        try {
            //获取该登录用户已经分配到他名下和他对应的角色权限所能执行的任务组
            CurrentUserAllTaskResult = workflowFeignService.getCurrentUserAllTaskList(key);
        } catch (Exception e) {
            throw new RuntimeException("获取当前角色所能执行的任务失败");
        }
        JSONArray allTaskResultList = CurrentUserAllTaskResult.getJSONArray(WorkFlowEnum.DATA.getCode());
        //获取制定计划节点任务的所有可执行任务
        JSONObject SpecifyTask = workflowFeignService.getTaskListForTaskName(WorkFlowEnum.制定计划内容.getCode(), key);
        JSONArray SpecifyTaskArray = SpecifyTask.getJSONArray(WorkFlowEnum.DATA.getCode());
        //判断该执行任务的历史执行节点的角色是否与当前登录用户的角色一致，如果一致就添加到根据用户角色ID和userID所属的任务列表中
        SpecifyTaskArray.stream().forEach(i -> {
            JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(i));
            String groupName = getFristFlowDetail(json.getString(WorkFlowEnum.PROCESSINSTANCEID.getCode()));
            if (StringUtils.isNotBlank(groupName) && roleNameSet.contains(groupName)) {
                allTaskResultList.add(i);
            }
        });
        return allTaskResultList;
    }

    /**
     * 根据工作流获取下一审核人角色下的所有用户ID
     * @return
     */
    @Override
    public List<String> getUserIdsByWorkflow(String procressId, String checkLeaderId) throws Exception {
        List<String> userIds = new ArrayList<>();
        JSONObject teskObject = workflowFeignService.getTaskList(procressId);
        JSONArray taskDetailArray = teskObject.getJSONArray(WorkFlowEnum.DATA.getCode());
        for (Object obj : taskDetailArray) {
            JSONObject detail = JSONObject.parseObject(JSONObject.toJSONString(obj));
            JSONArray informerList = detail.getJSONArray(WorkFlowEnum.INFORMERLIST.getCode());
            if (informerList.size() > 0) {
                userIds = informerList.stream().map(item -> {
                    JSONObject jsonItem = (JSONObject) item;
                    return jsonItem.getString("userId");
                }).collect(Collectors.toList());
            } else {
                userIds.add(checkLeaderId);
            }
        }
        return userIds;
    }
}
