package yangtz.cs.liu.activiti.service.impl;

import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysUserMapper;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.*;
import org.activiti.engine.impl.persistence.entity.TaskEntityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import yangtz.cs.liu.activiti.domain.BizTodoItem;
import yangtz.cs.liu.activiti.domain.HistoricActivity;
import yangtz.cs.liu.activiti.mapper.ProcessMapper;
import yangtz.cs.liu.activiti.service.IBizTodoItemService;
import yangtz.cs.liu.activiti.service.IProcessService;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

import static com.ruoyi.common.utils.SecurityUtils.getUserId;
import static org.apache.commons.lang3.SystemUtils.getUserName;

@Service
public class ProcessServiceImpl implements IProcessService {
    protected final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private IBizTodoItemService bizTodoItemService;
    @Autowired
    private ProcessMapper processMapper;

    private Logger log = LoggerFactory.getLogger(ProcessServiceImpl.class);

    @Override
    public ProcessInstance submitApply(String applyUserId, String businessKey, String itemName, String itemConent, String module, Map<String, Object> variables) {
        // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
        identityService.setAuthenticatedUserId(applyUserId);
        // 启动流程时设置业务 key
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(module, businessKey, variables);
        // 下一节点处理人待办事项
        bizTodoItemService.insertTodoItem(instance.getProcessInstanceId(), itemName, itemConent, module);
        return instance;
    }

    @Override
    public List<Task> findTodoTasks(String userId, String key) {
        List<Task> tasks = new ArrayList<Task>();
        // 根据当前人的ID查询
        List<Task> todoList = taskService
                .createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(userId)
                .list();
        // 根据当前人未签收的任务
        List<Task> unsignedTasks = taskService
                .createTaskQuery()
                .processDefinitionKey(key)
                .taskCandidateUser(userId)
                .list();
        // 合并
        tasks.addAll(todoList);
        tasks.addAll(unsignedTasks);
        return tasks;
    }

    /**
     * 查询待办集合 根据候选人或者处理人查询
     *
     * @param userId
     * @param key
     * @return
     */
    @Override
    public List<Task> findTodoList(String userId, String key) {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();

        Integer start = (pageNum - 1) * pageSize;

        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskCandidateOrAssigned(userId)
                .listPage(start, pageSize);
        return taskList;
    }

    /**
     * 查询个人任务
     */
    @Override
    public List<Task> findAssigneeTasks(String userId, String key) {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();

        Integer start = (pageNum - 1) * pageSize;

        List<Task> list = taskService
                .createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(userId)
                .list();
//                .listPage(start, pageSize);
        return list;
    }

    /**
     * 查询组任务
     *
     * @param userId
     * @param key
     * @return
     */
    @Override
    public List<Task> findCandidateTasks(String userId, String key) {

        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();

        Integer start = (pageNum - 1) * pageSize;

        List<Task> list = taskService
                .createTaskQuery()
                .processDefinitionKey(key)
                .taskCandidateUser(userId)
                .listPage(start, pageSize);
        return list;
    }

    @Override
    public List<HistoricTaskInstance> findDoneTasks(String userId, String key) {

        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();

        Integer start = (pageNum - 1) * pageSize;

        List<HistoricTaskInstance> list = historyService
                .createHistoricTaskInstanceQuery()
                .processDefinitionKey(key)
                .taskAssignee(userId)
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .list();
//                .listPage(start, pageSize);
        return list;
    }

    @Override
    public void complete(String taskId, String instanceId, String itemName, String itemContent, String module, Map<String, Object> variables, HttpServletRequest request) {
        Enumeration<String> parameterNames = request.getParameterNames();
        String comment = null;          // 批注
        boolean agree = true;
        try {
            while (parameterNames.hasMoreElements()) {
                String parameterName = parameterNames.nextElement();
                if (parameterName.startsWith("p_")) {
                    // 参数结构：p_B_name，p为参数的前缀，B为类型，name为属性名称
                    String[] parameter = parameterName.split("_");
                    if (parameter.length == 3) {
                        String paramValue = request.getParameter(parameterName);
                        Object value = paramValue;
                        if (parameter[1].equals("B")) {
                            value = BooleanUtils.toBoolean(paramValue);
                            agree = (boolean) value;
                        } else if (parameter[1].equals("DT")) {
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                            value = sdf.parse(paramValue);
                        } else if (parameter[1].equals("COM")) {
                            comment = paramValue;
                        }
                        variables.put(parameter[2], value);
                    } else {
                        throw new RuntimeException("invalid parameter for activiti variable: " + parameterName);
                    }
                }
            }
            if (StringUtils.isNotEmpty(comment)) {
                // edit by wj
                identityService.setAuthenticatedUserId(getUserId().toString());
                comment = agree ? "【同意】" + comment : "【拒绝】" + comment;
                taskService.addComment(taskId, instanceId, comment);
            }
            // 被委派人处理完成任务
            // p.s. 被委托的流程需要先 resolved 这个任务再提交。
            // 所以在 complete 之前需要先 resolved
            // resolveTask() 要在 claim() 之前，不然 act_hi_taskinst 表的 assignee 字段会为 null
            taskService.resolveTask(taskId, variables);
            // 只有签收任务，act_hi_taskinst 表的 assignee 字段才不为 null
            taskService.claim(taskId, getUserId().toString());
            taskService.complete(taskId, variables);

            // 更新待办事项状态
            BizTodoItem query = new BizTodoItem();
            query.setTaskId(taskId);
            // 考虑到候选用户组，会有多个 todoitem 办理同个 task
            List<BizTodoItem> updateList = CollectionUtils.isEmpty(bizTodoItemService.selectBizTodoItemList(query)) ? null : bizTodoItemService.selectBizTodoItemList(query);
            for (BizTodoItem update : updateList) {
                // 找到当前登录用户的 todoitem，置为已办
                if (update.getTodoUserId().equals(getUserId().toString())) {
                    update.setIsView("1");
                    update.setIsHandle("1");
                    update.setHandleUserId(getUserId().toString());
                    update.setHandleUserName(getUserName());
                    update.setHandleTime(DateUtils.getNowDate());
                    bizTodoItemService.updateBizTodoItem(update);
                } else {
                    bizTodoItemService.deleteBizTodoItemById(update.getId()); // 删除候选用户组其他 todoitem
                }
            }

            // 下一节点处理人待办事项
            bizTodoItemService.insertTodoItem(instanceId, itemName, itemContent, module);
        } catch (Exception e) {
            logger.error("error on complete task {}, variables={}", new Object[]{taskId, variables, e});
        }
    }

//    @Override
//    public List<HistoricActivity> selectHistoryList(String processInstanceId, HistoricActivity historicActivity) {
////        PageDomain pageDomain = TableSupport.buildPageRequest();
////        Integer pageNum = pageDomain.getPageNum();
////        Integer pageSize = pageDomain.getPageSize();
//        List<HistoricActivity> activityList = new ArrayList<>();
//        HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery();
//        historyService.createHistoricTaskInstanceQuery()
//                .taskAssigneeLike("%zy%");
//        if (StringUtils.isNotBlank(historicActivity.getAssignee())) {
//            query.taskAssignee(historicActivity.getAssignee());
//        }
//        if (StringUtils.isNotBlank(historicActivity.getActivityName())) {
//            query.activityName(historicActivity.getActivityName());
//        }
//        List<HistoricActivityInstance> list = query.processInstanceId(processInstanceId)
//                .activityType("userTask")
//                .finished()
//                .orderByHistoricActivityInstanceStartTime()
//                .desc()
//                .list();
////                .listPage((pageNum - 1) * pageSize, pageNum * pageSize);
//        list.forEach(instance -> {
//            HistoricActivity activity = new HistoricActivity();
//            BeanUtils.copyProperties(instance, activity);
//            String taskId = instance.getTaskId();
//            List<Comment> comment = taskService.getTaskComments(taskId, "comment");
//            if (!CollectionUtils.isEmpty(comment)) {
//                activity.setComment(comment.get(0).getFullMessage());
//            }
//            String userName = userMapper.selectUserNameByUserId(Long.parseLong(instance.getAssignee()));
//            if (StringUtils.isNotEmpty(userName)) {
//                activity.setAssigneeName(userName);
//            }
//            activityList.add(activity);
//        });
//        return activityList;
//    }

    @Override
    public List<HistoricActivity> selectHistoryList(String processInstanceId, HistoricActivity historicActivity) {
        List<HistoricActivity> activityList = new ArrayList<>();
        HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery();
        if (StringUtils.isNotBlank(historicActivity.getAssignee())) {
            query.taskAssignee(historicActivity.getAssignee());
        }
        if (StringUtils.isNotBlank(historicActivity.getActivityName())) {
            query.activityName(historicActivity.getActivityName());
        }
        //审批历史
        List<HistoricActivityInstance> list = query.processInstanceId(processInstanceId)
                .finished()
                .orderByHistoricActivityInstanceStartTime()
                .desc()
                .list();
        list.forEach(instance -> {
            HistoricActivity activity = new HistoricActivity();
            BeanUtils.copyProperties(instance, activity);
            String taskId = instance.getTaskId();
            //批注
            List<Comment> comment = taskService.getTaskComments(taskId, "comment");
            if (!CollectionUtils.isEmpty(comment)) {
                activity.setComment(comment.get(0).getFullMessage());
            }
            if (StringUtils.isNotEmpty(instance.getAssignee())) {
                String userName = userMapper.selectUserNameByUserId(Long.parseLong(instance.getAssignee()));
                if (StringUtils.isNotEmpty(userName)) {
                    activity.setAssigneeName(userName);
                }
            }
            activityList.add(activity);
        });
        return activityList;
    }

    @Override
    public void delegate(String taskId, String fromUser, String delegateToUser) {
        taskService.delegateTask(taskId, delegateToUser);
        // 更新待办事项
        BizTodoItem updateItem = bizTodoItemService.selectBizTodoItemByCondition(taskId, fromUser);
        if (updateItem != null) {
            SysUser todoUser = userMapper.selectUserByLoginName(delegateToUser);
            updateItem.setTodoUserId(delegateToUser);
            updateItem.setTodoUserName(todoUser.getUserName());
            bizTodoItemService.updateBizTodoItem(updateItem);
        }
    }

    @Override
    public void cancelApply(String instanceId, String deleteReason) {
        // 执行此方法后未审批的任务 act_ru_task 会被删除，流程历史 act_hi_taskinst 不会被删除，并且流程历史的状态为finished完成
        runtimeService.deleteProcessInstance(instanceId, deleteReason);
    }

    @Override
    public void suspendOrActiveApply(String instanceId, String suspendState) {
        if ("1".equals(suspendState)) {
            // 当流程实例被挂起时，无法通过下一个节点对应的任务id来继续这个流程实例。
            // 通过挂起某一特定的流程实例，可以终止当前的流程实例，而不影响到该流程定义的其他流程实例。
            // 激活之后可以继续该流程实例，不会对后续任务造成影响。
            // 直观变化：act_ru_task 的 SUSPENSION_STATE_ 为 2
            runtimeService.suspendProcessInstanceById(instanceId);
        } else if ("2".equals(suspendState)) {
            runtimeService.activateProcessInstanceById(instanceId);
        }
    }

    @Override
    public String findBusinessKeyByInstanceId(String instanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        if (processInstance == null) {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(instanceId)
                    .singleResult();
            return historicProcessInstance.getBusinessKey();
        } else {
            return processInstance.getBusinessKey();
        }
    }

    /**
     * 办理任务
     *
     * @param taskId
     * @param variables
     */
    @Override
    public void completeTask(String taskId, String instanceId, Map<String, Object> variables) {
        try {
            //批注
            String comment = variables.get("comment").toString();
            //是否通过
            String pass = variables.get("pass").toString();
            //查询个人任务
            TaskEntityImpl task = (TaskEntityImpl) taskService.createTaskQuery()
                    .taskId(taskId)
                    .taskCandidateOrAssigned(getUserId().toString())
                    .singleResult();
            if (StringUtils.isNotNull(task)) {
                // 声明要解决任务
                taskService.resolveTask(taskId, variables);
                //拾取任务
                taskService.claim(taskId, getUserName());
                //设置受理人
                taskService.setAssignee(taskId, getUserId().toString());
                //设置处理人
                identityService.setAuthenticatedUserId(getUserName());
                if (StringUtils.isNotEmpty(comment)) {
                    comment = Boolean.parseBoolean(pass) ? "【同意】" + comment : "【拒绝】" + comment;
                    //批注
                    taskService.addComment(taskId, instanceId, comment);
                }
                //将pass的值改为Boolean类型
                if(Boolean.parseBoolean(pass)){
                    variables.put("pass",true);
                }else {
                    variables.put("pass",false);
                }
                //完成任务
                taskService.complete(taskId, variables);
            }
        } catch (Exception e) {
            log.error("error on complete task {}, variables={}", new Object[]{taskId, variables}, e);
            throw new ServiceException("完成任务失败");
        }
    }


    @Override
    public void completeWxTask(String taskId, String instanceId, String userId, Map<String, Object> variables) {
        try {
            //批注
            String comment = variables.get("comment").toString();
            //是否通过
            String pass = variables.get("pass").toString();
            //查询个人任务
            TaskEntityImpl task = (TaskEntityImpl) taskService.createTaskQuery()
                    .taskId(taskId)
                    .taskCandidateOrAssigned(userId)
                    .singleResult();
            if (StringUtils.isNotNull(task)) {
                // 声明要解决任务
                taskService.resolveTask(taskId, variables);
                //拾取任务
                taskService.claim(taskId, getUserName());
                //设置受理人
                taskService.setAssignee(taskId, userId);
                //设置处理人
                identityService.setAuthenticatedUserId(getUserName());
                if (StringUtils.isNotEmpty(comment)) {
                    comment = Boolean.parseBoolean(pass) ? "【同意】" + comment : "【拒绝】" + comment;
                    //批注
                    taskService.addComment(taskId, instanceId, comment);
                }
                //完成任务
                taskService.complete(taskId, variables);
            }
        } catch (Exception e) {
            log.error("error on complete task {}, variables={}", new Object[]{taskId, variables}, e);
            throw new ServiceException("完成任务失败");
        }
    }

    /**
     * @param taskId
     * @param userId 拾取任务
     * @author lyric
     * @date 2022/10/27 12:56
     */
    @Override
    public void claimTask(String taskId, String userId) {
        taskService.claim(taskId, userId);
    }

    /**
     * @param taskId 归还任务
     * @author lyric
     * @date 2022/10/27 13:40
     */
    @Override
    public void restoreTask(String taskId) {
        taskService.setAssignee(taskId, null);
    }

    /**
     * @param key
     * @param userId
     * @return Integer
     * <p>
     * 查询已办总数
     * @author lyric
     * @date 2022/10/30 11:47
     */
    @Override
    public int getDoneTotal(String key, String userId) {
        return processMapper.selectDoneTotal(key, userId);
    }

    /**
     * @param key
     * @param userId
     * @return int
     * <p>
     * 查询待办总数
     * @author lyric
     * @date 2022/10/30 12:31
     */
    @Override
    public int getTodoTotal(String key, String userId) {
        return processMapper.selectTodoTotal(key, userId);
    }

}
