package com.ruoyi.project.activiti.service.impl;

import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.project.activiti.domain.MyProcessDefinition;
import com.ruoyi.project.activiti.domain.MyTask;
import com.ruoyi.project.activiti.domain.SelectVo;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.*;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
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.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;

@Service
public class ProcessDefinitionServiceImpl  {
    private static final Logger LOGGER = LoggerFactory.getLogger(ProcessDefinitionServiceImpl.class);

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private FormService formService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private IdentityService identityService;

    @Transactional
    public void startProcess(String assignee) {
        runtimeService.startProcessInstanceByKey("oneTaskProcess");
    }

    public List<Task> getTasks(String assignee) {
        return taskService.createTaskQuery().taskAssignee(assignee).list();
    }

    /**
     * 分页查询流程定义文件
     *
     * @return
     */
    public List<ProcessDefinition> listProcessDefinition() {

        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> processDefinitions = processDefinitionQuery.listPage(0, 100);
        return processDefinitions;
    }

    @Transactional
    public void deployProcessDefinition(String filePath) throws FileNotFoundException {
        if (StringUtils.isNotBlank(filePath)) {
            if (filePath.endsWith(".zip")) {
                ZipInputStream inputStream = new ZipInputStream(new FileInputStream(filePath));
                repositoryService.createDeployment()
                        .addZipInputStream(inputStream)
                        .deploy();
            } else if (filePath.endsWith(".bpmn") || filePath.endsWith(".bpmn20.xml")) {
                repositoryService.createDeployment()
                        .addInputStream(filePath, new FileInputStream(filePath))
                        .deploy();
            }
        }
    }

    /**
     * 部署流程文件
     *
     * @param file
     * @throws IOException
     */
    @Transactional
    public void deployProcessDefinition(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        String originalFilename = file.getOriginalFilename();
        DeploymentBuilder deployment = repositoryService.createDeployment();
        deployment.addInputStream(originalFilename, inputStream).deploy();
    }


    @Transactional
    public int deleteProcessDeploymentByIds(List<String> deploymentIds) {
        int counter = 0;
        for (String deploymentId : deploymentIds) {
            List<ProcessInstance> instanceList = runtimeService.createProcessInstanceQuery()
                    .deploymentId(deploymentId)
                    .list();
            if (!CollectionUtils.isEmpty(instanceList)) {
                // 跳过存在流程实例的流程定义
                continue;
            }
            // true 表示级联删除引用,比如 act_ru_execution 数据
            repositoryService.deleteDeployment(deploymentId, true);
            counter++;
        }
        return counter;
    }

    public List<MyProcessDefinition> list(Integer pageNum, Integer pageSize) {
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().listPage((pageNum - 1) * pageSize, pageSize);
        List<MyProcessDefinition> collect = list.stream().map(x -> {
            MyProcessDefinition myProcessDefinition = new MyProcessDefinition();
            myProcessDefinition.setId(x.getDeploymentId());
            myProcessDefinition.setProcessId(x.getId());
            myProcessDefinition.setKey(x.getKey());
            myProcessDefinition.setName(x.getName());
            myProcessDefinition.setVersion(x.getVersion());
            myProcessDefinition.setDescription(x.getDescription());
            return myProcessDefinition;
        }).collect(Collectors.toList());

        return collect;
    }

    public void start() {
        startModel();

       // testUserAndGroup();
    }

    private void testUserAndGroup() {
        User user1 = identityService.newUser("user1");   //初始化用户user1
        user1.setEmail("user1@111.com");
        User user2 = identityService.newUser("user2");
        user2.setEmail("user2@111.com");
        identityService.saveUser(user1);    //将用户保存
        identityService.saveUser(user2);

        Group group1 = identityService.newGroup("group1");   //初始化用户组group1
        identityService.saveGroup(group1);
        Group group2 = identityService.newGroup("group2");
        identityService.saveGroup(group2);

        identityService.createMembership("user1", "group1");    //构建用户与用户组的关系
        identityService.createMembership("user2", "group1");
        identityService.createMembership("user1", "group2");

        User user1_2 = identityService.createUserQuery().userId("user1").singleResult();   //将用户名修改,版本号改为2
        user1_2.setLastName("user1_2");
        identityService.saveUser(user1_2);

        List<User> userList = identityService.createUserQuery().memberOfGroup("group1").listPage(0, 100);//查询用户列表
        for (User user : userList) {    //查询group1组中的所有用户
            LOGGER.info("group1的user : [{}]", ToStringBuilder.reflectionToString(user, ToStringStyle.JSON_STYLE));   //按照json格式输出
        }

        List<Group> groupList = identityService.createGroupQuery().groupMember("user1").listPage(0, 100);
        for (Group group : groupList) {    //查询user1用户所属的组
            LOGGER.info("user1的group : [{}]", ToStringBuilder.reflectionToString(group, ToStringStyle.JSON_STYLE));
        }
    }

    private void startModel() {
        //获取流程定义对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().singleResult();
        //启动运行流程
        ProcessInstance taskService = getTaskService(processDefinition);
        //处理流程
        runProcess(taskService);
    }

    private ProcessInstance getTaskService(ProcessDefinition processDefinition) {
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());
        LOGGER.info("流程启动 {}", processInstance);
        return processInstance;
    }


    private void runProcess(ProcessInstance processInstance) {
        //部署结束继续输入
        while (processInstance != null && !processInstance.isEnded()) {
            Scanner scanner = new Scanner(System.in);
            List<Task> list = taskService.createTaskQuery().list();
            for (Task task : list) {
                LOGGER.info("待处理任务[{}]", task.getName());
                //获取表单数据
                TaskFormData taskFormData = formService.getTaskFormData(task.getId());
                List<FormProperty> formProperties = taskFormData.getFormProperties();
                Map<String, Object> inparms = new HashMap<String, Object>();
                String s = null;
                for (FormProperty formProperty : formProperties) {
                    String name = formProperty.getName();
                    LOGGER.info("请输入[{}]", name);
                    s = scanner.nextLine();
                    inparms.put(formProperty.getId(), s);
                    LOGGER.info("你输入的是[{}]", s);
                }
                //将参数提交到userTask的表单中
                taskService.complete(task.getId(), inparms);
                //同步流程状态
                processInstance = runtimeService
                        .createProcessInstanceQuery()
                        .processInstanceId(processInstance.getId())
                        .singleResult();
            }
            LOGGER.info("待处理任务数[{}]", list.size());

        }

    }

    public List<SelectVo> select() {
        List<SelectVo> collect=new ArrayList<>();
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
        if(!StringUtils.isNull(list)){
            collect = list.stream().map(x -> {
                SelectVo selectVo = new SelectVo();
                int version = x.getVersion();
                String id = x.getId();
                selectVo.setText(x.getName()+" v"+version);
                selectVo.setValue(id);
                return  selectVo;
            }).collect(Collectors.toList());
        }
        return collect;
    }

    public BpmnModel get(String id) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(id).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        return bpmnModel;
    }
}