package cn.palmte.work.service;

import cn.palmte.work.bean.ApproveStatusEnum;
import cn.palmte.work.bean.ResponseMsg;
import cn.palmte.work.config.activiti.ActConstant;

import cn.palmte.work.model.*;
import cn.palmte.work.pojo.ActHisTask;
import cn.palmte.work.utils.ActUtil;
import cn.palmte.work.utils.InterfaceUtil;
import com.alibaba.fastjson.JSONObject;
import org.activiti.engine.*;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.jfunc.common.db.QueryHelper;
import top.jfunc.common.db.utils.Pagination;

import java.util.*;


@Service
public class ActTaskDefService {
    private static final Logger logger = LoggerFactory.getLogger(ActTaskDefService.class);
    @Autowired
    private ProjectTaskRecordService projectTaskRecordService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;            //任务管理 与正在执行的任务管理相关的Service
    @Autowired
    private ActTaskDefRepository actTaskDefRepository;
    @Autowired
    private AccountService accountService;
    @Autowired
    Pagination pagination;
    @Autowired
    private ActUtil actUtil;
    @Autowired
    private ProjectInstanceService projectInstanceService;
    @Autowired
    private RuntimeService runtimeService;


    /**
     * 审批任务
     *
     * @param json
     */
    public void completeTask(JSONObject json) {
        String taskId = json.getString("taskId");
        String procInsId = json.getString("procInsId");
        String message = json.getString("message");
        int type = json.getInteger("type");

        completeTask(taskId, procInsId, message, type, "");
    }

    private void completeTask(String taskId, String procInsId, String message, int type, String fileUrl) {
        String userId = InterfaceUtil.getAdminId() + "";
        Authentication.setAuthenticatedUserId(userId);
        taskService.addComment(taskId, procInsId, message);

        Task currentTask = taskService.createTaskQuery().taskId(taskId).singleResult();
        ActTaskDef actTaskDef = findFirstByProcDefIdAndTaskKey(currentTask.getProcessDefinitionId(), currentTask.getTaskDefinitionKey());

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(procInsId).singleResult();
        taskService.setAssignee(taskId, userId);
        if (ActConstant.TASK_TYPE_SINGE == actTaskDef.getTaskType()) {
            handleSinge(processInstance, taskId, type, actTaskDef);
        }


        //保存审批记录
        projectTaskRecordService.saveTaskRecord(Integer.parseInt(processInstance.getBusinessKey()),
                currentTask, type, actTaskDef.getTaskIndex(), message, fileUrl);
    }


    /**
     * 通过流程实列id完成任务
     *
     * @param procInsId
     * @param type
     * @param comment
     */
    public void completeTaskByProcInsId(String procInsId, int type, String comment) {
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(procInsId).list();
        for (Task task : taskList) {
            completeTask(task.getId(), procInsId, comment, type, "");
        }
    }

    /**
     * 预算跳过剩下审批任务直接到执行董事节点
     * @param procInsId
     */
    public ResponseMsg skipTaskByProcInsId(String procInsId, String fileUrl, int approvetype) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(procInsId).singleResult();
        if (!ActConstant.PROCESS_DEFKEY_BUDGET.equals(processInstance.getProcessDefinitionKey())) {
            return ResponseMsg.buildFailedMsg("只有预算审批流程才能执行会签");
        }

        //完成当前任务
        Task task = taskService.createTaskQuery().processInstanceId(procInsId).singleResult();
        if ("执行董事".equals(task.getName())) {
            return ResponseMsg.buildFailedMsg("当前状态不能用会签功能，请使用审批功能。");
        }
        completeTask(task.getId(), procInsId, "申请会签", ApproveStatusEnum.APPROVAL_PASSED.getApproveStatus(), fileUrl);

        //非执行董事节点自动跳过
        task = taskService.createTaskQuery().processInstanceId(procInsId).singleResult();
        while (!"执行董事".equals(task.getName())) {
            completeSkipTask(task, processInstance, "会签，任务自动审批通过", ApproveStatusEnum.APPROVAL_PASSED.getApproveStatus());
            task = taskService.createTaskQuery().processInstanceId(procInsId).singleResult();
        }

        return ResponseMsg.buildSuccessMsg("会签成功", approvetype);
    }


    private void completeSkipTask(Task task, ProcessInstance processInstance, String message, int type) {
        String taskId = task.getId();
        ActTaskDef actTaskDef = findFirstByProcDefIdAndTaskKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());

        Authentication.setAuthenticatedUserId("-1");
        taskService.addComment(taskId, processInstance.getProcessInstanceId(), message);
        taskService.setAssignee(taskId, "-1");

        if (ActConstant.TASK_TYPE_SINGE == actTaskDef.getTaskType()) {
            handleSinge(processInstance, taskId, type, actTaskDef);
        }
    }

    /**
     * 或签处理
     *
     * @param taskId
     * @param processInstance
     * @param type
     * @param actTaskDef
     */
    private void handleSinge(ProcessInstance processInstance, String taskId, int type, ActTaskDef actTaskDef) {
        String procDefKey = actTaskDef.getProcDefKey();
        if (ApproveStatusEnum.APPROVAL_PASSED.getApproveStatus() == type) {
            //审批通过
            taskService.complete(taskId);

            //最后一个任务完成后 更新项目状态为审批通过
            updateProjectPassed(processInstance, actTaskDef, procDefKey);
        } else if (ApproveStatusEnum.APPROVAL_UNPASS.getApproveStatus() == type) {
            //驳回
            String rollbackTaskKey = actTaskDef.getRollbackTaskKey();
            actUtil.jumpToTargetTask(taskId, rollbackTaskKey);

            //驳回后 更新项目状态为审批不通过
            int projectId = Integer.parseInt(processInstance.getBusinessKey());
            projectInstanceService.updateApproveStatus(projectId, procDefKey, ApproveStatusEnum.APPROVAL_UNPASS);
            logger.info("updateProjectUnPassed projectId:{}, proDefKey:{}", projectId, procDefKey);

        }
    }

    /**
     * 最后一个任务完成后 更新项目状态为审批通过
     *
     * @param processInstance
     * @param actTaskDef
     * @param procDefKey
     */
    private void updateProjectPassed(ProcessInstance processInstance, ActTaskDef actTaskDef, String procDefKey) {
        int projectId = Integer.parseInt(processInstance.getBusinessKey());
        if (ActConstant.PROCESS_DEFKEY_SETTLE.equals(procDefKey)) {
            //结算流程 财务总监审批完流程结束
            if ("财务总监".equals(actTaskDef.getTaskName())) {
                logger.info("updateProjectPassed1 projectId:{}, proDefKey:{}", projectId, procDefKey);
                projectInstanceService.updateApproveStatus(projectId, procDefKey, ApproveStatusEnum.APPROVAL_PASSED);
            }
        } else {
            //其余流程 执行董事审批完流程结束
            if ("执行董事".equals(actTaskDef.getTaskName())) {
                logger.info("updateProjectPassed2 projectId:{}, proDefKey:{}", projectId, procDefKey);
                projectInstanceService.updateApproveStatus(projectId, procDefKey, ApproveStatusEnum.APPROVAL_PASSED);
            }
        }

    }

    /**
     * 审批过程任务查询
     *
     * @param procIncId
     * @return
     */
    public List<ActHisTask> hisTaskList(String procIncId) {
        String select = "select ht.PROC_DEF_ID_ as procDefId, ht.PROC_INST_ID_ as procInsId, ht.EXECUTION_ID_ as executionId," +
                "  ht.ID_ as taskId, ht.NAME_ as taskName, " +
                " ht.ASSIGNEE_ as assign, ht.START_TIME_ as startTime, ht.END_TIME_ as endTime, " +
                "ht.DURATION_ as duration, ht.DELETE_REASON_ as deleteReason,  hc.MESSAGE_  AS comments";
        QueryHelper queryHelper = new QueryHelper(select, " ACT_HI_TASKINST ht " +
                " LEFT JOIN ACT_HI_COMMENT hc  on ht.ID_ = hc.TASK_ID_ and hc.type_='comment' ");
        queryHelper.addCondition("ht.PROC_INST_ID_ =?", procIncId);
        queryHelper.addOrderProperty("ht.start_time_", true);
        List<ActHisTask> taskList = pagination.find(queryHelper.getSql(), ActHisTask.class);
        for (ActHisTask actHisTask : taskList) {
            setAssign(actHisTask);

            //办理用时
            String duration = actHisTask.getDuration();
            if (StringUtils.isNotBlank(duration)) {
                Long ztime = Long.parseLong(duration);
                Long day = ztime / (1000 * 60 * 60 * 24);
                Long hour = (ztime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
                Long minute = (ztime % (1000 * 60 * 60 * 24)) % (1000 * 60 * 60) / (1000 * 60);
                Long second = (ztime % (1000 * 60 * 60 * 24)) % (1000 * 60 * 60) % (1000 * 60) / 1000;
                actHisTask.setDuration(day + "天" + hour + "时" + minute + "分" + second + "秒");
            } else {
                actHisTask.setDuration("正在处理。。。");
            }

            if (StringUtils.isNotBlank(actHisTask.getDeleteReason())) {
                actHisTask.setComments("【审核不通过】" + actHisTask.getComments());
            }
        }

        return taskList;
    }


    /**
     * 根据流程定义查询任务
     *
     * @param procDefId
     * @return
     */
    public List<ActTaskDef> findByProcDefId(String procDefId) {
        List<ActTaskDef> list = actTaskDefRepository.findByProcDefId(procDefId);
        for (ActTaskDef actTaskDef : list) {
            candidatesHandle(actTaskDef);
        }
        return list;
    }


    /**
     * 根据流程定义和任务key查询任务
     *
     * @param procDefId
     * @param taskKey
     * @return
     */
    public ActTaskDef findFirstByProcDefIdAndTaskKey(String procDefId, String taskKey) {
        ActTaskDef def = actTaskDefRepository.findFirstByProcDefIdAndTaskKey(procDefId, taskKey);
        candidatesHandle(def);
        return def;
    }


    /**
     * 保存任务配置
     *
     * @param taskDef
     */
    public void saveConfig(ActTaskDef taskDef) {
        ActTaskDef one = actTaskDefRepository.findOne(taskDef.getId());
        one.setCandidateUsers(taskDef.getCandidateUsers());
        one.setCandidateRoles(taskDef.getCandidateRoles());
        one.setRollbackTaskKey(taskDef.getRollbackTaskKey());
        one.setLastUpdatedTime(new Date());

        actTaskDefRepository.save(one);
        logger.info("saveTaskConfig uerId:{}, config:{}", InterfaceUtil.getAdminId(), JSONObject.toJSONString(one));
    }


    /**
     * 查找任务配置的审批人
     *
     * @param procDefId
     * @param procInsId
     * @param taskDefKey
     * @return
     */
    public List<String> findCandidateUsers(String procDefId, String procInsId, String taskDefKey) {
        ActTaskDef taskDef = findFirstByProcDefIdAndTaskKey(procDefId, taskDefKey);
        if (taskDef.getTaskIndex() == ActConstant.TASK_INDEX_FIRST_USER_TASK) {
            //任务驳回到发起节点 审批人设置为发起人
            String startUserId = actUtil.getStartUserId(procInsId);
            List<String> res = new ArrayList<>(1);
            logger.info("findCandidateUsers-0-task:{}, startUserId:{}", taskDef.getTaskName(), startUserId);
            res.add(startUserId);
            return res;
        }

        //去重
        Set<String> res = new HashSet<>();

        //通过人员id查询
        List<String> candidateUserList = taskDef.getCandidateUserList();
        logger.info("findCandidateUsers-1-task:{}, userList:{}", taskDef.getTaskName(), candidateUserList);
        if (!candidateUserList.isEmpty()) {
            res.addAll(candidateUserList);
        }

        //通过角色id查询
        List<String> candidateRoleList = taskDef.getCandidateRoleList();
        logger.info("findCandidateUsers-2-task:{}, roleList:{}", taskDef.getTaskName(), candidateRoleList);
        List<String> list = accountService.getUserIsByRole(candidateRoleList);
        logger.info("findCandidateUsers-3-task:{}, userIdListByRole:{}", taskDef.getTaskName(), list);
        if (!list.isEmpty()) {
            res.addAll(list);
        }

        List<String> resList = new ArrayList<>(res);
        logger.info("findCandidateUsers-4-task:{}, resIds:{}", taskDef.getTaskName(), resList);
        return resList;
    }


    /**
     * 任务审批人列表从sring转成list
     *
     * @param actTaskDef
     */
    private void candidatesHandle(ActTaskDef actTaskDef) {
        String candidateUsers = actTaskDef.getCandidateUsers();
        List<String> userIdList = new ArrayList<>();
        if (StringUtils.isNotBlank(candidateUsers)) {
            userIdList = Arrays.asList(candidateUsers.split("#"));
        }
        actTaskDef.setCandidateUserList(userIdList);

        String candidateRoles = actTaskDef.getCandidateRoles();
        List<String> roleIdList = new ArrayList<>();
        if (StringUtils.isNotBlank(candidateRoles)) {
            roleIdList = Arrays.asList(candidateRoles.split("#"));
        }
        actTaskDef.setCandidateRoleList(roleIdList);
    }


    /**
     * 设置历史任务审批人
     *
     * @param actHisTask
     */
    private void setAssign(ActHisTask actHisTask) {
        if (StringUtils.isNotBlank(actHisTask.getAssign())) {
            if ("-1".equals(actHisTask.getAssign())) {
                actHisTask.setAssign("系统");
                return;
            }

            String userName = accountService.getNameById(Integer.parseInt(actHisTask.getAssign()));
            actHisTask.setAssign(userName);
            return;
        }

        Task task = taskService.createTaskQuery().taskId(actHisTask.getTaskId()).singleResult();
        if (task == null) {
            return;
        }

        if (StringUtils.isNotBlank(task.getAssignee())) {
            actHisTask.setAssign(task.getAssignee());
            return;
        }

        actHisTask.setAssign(actUtil.getAssigneeByIdentityLink(task.getId()));
    }


}
