package com.patzn.lims.workflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.patzn.lims.core.web.Account;
import com.patzn.lims.core.web.BaseServiceImpl;
import com.patzn.lims.core.web.LoginHelper;
import com.patzn.lims.workflow.ActGeBytearray;
import com.patzn.lims.workflow.ActReProcdef;
import com.patzn.lims.workflow.FlowInfo;
import com.patzn.lims.workflow.mapper.ActReProcdefMapper;
import com.patzn.lims.workflow.service.IActReProcdefService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 工作流解析表 服务类
 * </p>
 *
 * @author patzn
 * @since 2017-10-21
 */
@Service
public class ActReProcdefServiceImpl extends BaseServiceImpl<ActReProcdefMapper, ActReProcdef> implements IActReProcdefService {

    @Autowired
    private TaskService taskService;

    @Override
    public Page<ActReProcdef> page(Page<ActReProcdef> page, ActReProcdef actReProcdef) {
        QueryWrapper<ActReProcdef> ew = new QueryWrapper<>();
        ew.eq("tenant_id_", String.valueOf(LoginHelper.getAccount().getCompanyId()));
        if (null != actReProcdef.getName()) {
            ew.like("name_", actReProcdef.getName());
            actReProcdef.setName(null);
        }
        return page(page, ew);
    }

    @Override
    public List<ActReProcdef> list(ActReProcdef actReProcdef) {
        return list(new QueryWrapper<ActReProcdef>(actReProcdef));
    }

    @Override
    public void bpnm(HttpServletResponse response, boolean xml, String id) {
        ActGeBytearray actGeBytearray;
        if (xml) {
            actGeBytearray = baseMapper.selectBpmnXml(id);
        } else {
            actGeBytearray = baseMapper.selectBpmnPng(id);
        }
        if (null == actGeBytearray) {
            return;
        }
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType(xml ? "text/xml" : "image/png");
            OutputStream stream = response.getOutputStream();
            IOUtils.write(actGeBytearray.getBytes(), stream);
            stream.flush();
            stream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<Map<String, Object>> listTask(Account account, String name) {
        // 设置个人任务 1 组任务 1 都需要执行查询
        return listTask(null, 1, 1, account, name);
    }

    /**
     * <p>
     * 任务分页
     * </p>
     *
     * @param page           分页对象
     * @param countMyTask    我的个人任务总数
     * @param countGroupTask 组任务总数
     * @param account        用户信息
     * @param name           任务名称
     * @return
     */
    private List<Map<String, Object>> listTask(Page<Map<String, Object>> page, int countMyTask,
                                               int countGroupTask, Account account, String name) {
        // 分页偏移量
        long offset = 0;
        // 组任务分页总数 0 不需要使用组任务显示 , 非分页初始化 1 需要查询组任务
        long groupSize = 1;
        if (null != page) {
            groupSize = page.getSize();
            if (page.getCurrent() > 0) {
                offset = (page.getCurrent() - 1) * groupSize;
            }
            // 分页偏移量大于个人任务数量，计算剩余偏移量，设置不查询个人任务
            if (offset >= countMyTask) {
                offset = offset - countMyTask;
                countMyTask = -1;
            }
        }

        /**
         * 分页任务列表
         */
        List<Task> pageTasks = new ArrayList<>();

        /**
         * 个人任务
         */
        if (countMyTask > 0) {
            List<Task> myTasks;
            TaskQuery taskQuery = taskService.createTaskQuery()
                    .taskAssignee(account.getUserIdStr())
                    .includeProcessVariables();
            if (StringUtils.isNotBlank(name)) {
                taskQuery = taskQuery.processVariableValueLike(FlowInfo.FLOW_NAME, "%" + name + "%");
            }
            taskQuery = taskQuery.orderByTaskCreateTime().asc();
            if (null != page) {
                // 个人任务分页逻辑，分页偏移量小于任务总数执行分页
                myTasks = taskQuery.listPage((int) offset, (int) page.getSize());
                int taskCount = (null == myTasks) ? 0 : myTasks.size();
                if (taskCount < page.getSize()) {
                    // 如果个人任务不够显示，计算组任务分页总数
                    groupSize = page.getSize() - taskCount;
                } else {
                    // 个人任务数量足够显示不查询组任务
                    groupSize = 0;
                }
            } else {
                // 普通查询
                myTasks = taskQuery.list();
            }
            if(CollectionUtils.isNotEmpty(myTasks)){
                pageTasks.addAll(myTasks);
            }
        }

        /**
         * 组任务
         */
        List<String> candidateGroups = null;
        if (groupSize > 0) {
            candidateGroups = baseMapper.selectCandidateGroups(account.getCompanyId(), account.getUserIdStr());
        }
        if (CollectionUtils.isNotEmpty(candidateGroups) && countGroupTask > 0) {
            TaskQuery taskQueryGroups = taskService.createTaskQuery()
                    .taskTenantId(account.getCompanyIdStr())
                    .taskCandidateGroupIn(candidateGroups)
                    .includeProcessVariables();
            if (StringUtils.isNotBlank(name)) {
                taskQueryGroups = taskQueryGroups.processVariableValueLike(FlowInfo.FLOW_NAME, "%" + name + "%");
            }
            /*
             * 工作组任务
             */
            taskQueryGroups = taskQueryGroups.orderByTaskCreateTime().asc();
            List<Task> groupTask = null;
            if (null != page) {
                // 组任务分页逻辑
                if (countGroupTask > 0) {
                    groupTask = taskQueryGroups.listPage((int) offset, (int) groupSize);
                }
            } else {
                // 普通查询
                groupTask = taskQueryGroups.list();
            }
            if (CollectionUtils.isNotEmpty(groupTask)) {
                pageTasks.addAll(groupTask);
            }
        }

        /**
         * 处理任务
         */
        return convertFlowTaskInfo(pageTasks);
    }

    /**
     * 任务列表转换为工作流任务信息
     */
    private List<Map<String, Object>> convertFlowTaskInfo(List<Task> taskList) {
        if (CollectionUtils.isEmpty(taskList)) {
            return null;
        }
        List<Map<String, Object>> flowTaskInfoList = new ArrayList<>();
        for (Task task : taskList) {
            Map<String, Object> flowTaskInfo = task.getProcessVariables();
            if (null == flowTaskInfo) {
                // 兼容不存在 Variables 逻辑
                flowTaskInfo = taskService.getVariables(task.getId());
            }
            if (null != flowTaskInfo) {
                flowTaskInfo.put("taskId", task.getId());
                // 是否需要认领
                flowTaskInfo.put("claim", task.getAssignee() != null);
                flowTaskInfoList.add(flowTaskInfo);
            }
        }
        return flowTaskInfoList;
    }

    @Override
    public Page<Map<String, Object>> pageTask(Page<Map<String, Object>> page, Account account, String name) {
        long countMyTask = countMyTask(account, name);
        long countGroupTask = countGroupTask(account, name);
        page.setTotal(countMyTask + countGroupTask);
        return page.setRecords(listTask(page, Integer.valueOf(String.valueOf(countMyTask)),
                Integer.valueOf(String.valueOf(countGroupTask)), account, name));
    }

    @Override
    public long countTask(Account account) {
        return countTask(account, null);
    }

    /**
     * 任务总数
     */
    private long countTask(Account account, String name) {
        return countMyTask(account, name) + countGroupTask(account, name);
    }

    /**
     * 我的个人任务总数
     */
    private long countMyTask(Account account, String name) {
        // 参与者，个人任务查询
        TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(account.getUserIdStr());
        if (StringUtils.isNotBlank(name)) {
            taskQuery = taskQuery.processVariableValueLike(FlowInfo.FLOW_NAME, "%" + name + "%");
        }
        return taskQuery.count();
    }

    /**
     * 组任务总数
     */
    private long countGroupTask(Account account, String name) {
        List<String> candidateGroups = baseMapper.selectCandidateGroups(account.getCompanyId(), account.getUserIdStr());
        if (CollectionUtils.isNotEmpty(candidateGroups)) {
            // 参与者，组任务查询
            TaskQuery taskQueryGroups = taskService.createTaskQuery()
                    .taskTenantId(account.getCompanyIdStr())
                    .taskCandidateGroupIn(candidateGroups)
                    .includeProcessVariables();
            if (StringUtils.isNotBlank(name)) {
                taskQueryGroups = taskQueryGroups.processVariableValueLike(FlowInfo.FLOW_NAME, "%" + name + "%");
            }
            return taskQueryGroups.count();
        }
        return 0;
    }
}
