package com.activiti6.service.activiti.impl;


import com.activiti6.common.exception.CustomException;
import com.activiti6.common.utils.StringUtils;
import com.activiti6.domain.HttpStatus;
import com.activiti6.domain.MyProcessDefinition;
import com.activiti6.domain.TableDataInfo;
import com.activiti6.mapper.MyFormDataActivitiMapper;
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.history.HistoricProcessInstance;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.repository.DeploymentBuilder;
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.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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
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;

    @Autowired
    HistoryService historyService;

    @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();
    }

    @Autowired
    private MyFormDataActivitiMapper myFormDataActivitiMapper;

    @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)) {
                // 跳过存在流程实例的流程定义
                throw new CustomException("该流程已被使用无法删除!");
            }
            List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().deploymentId(deploymentId).list();
            if (!CollectionUtils.isEmpty(list)) {
                // 跳过存在流程实例的流程定义
                throw new CustomException("该流程存在历史数据无法删除!");
            }
            // true 表示级联删除引用，比如 act_ru_execution 数据
            repositoryService.deleteDeployment(deploymentId, true);
            counter++;
        }
        return counter;
    }
    public TableDataInfo list(String title, Integer pageNum, Integer pageSize) {
        try{
            Thread.sleep(100*3);
        }catch (Exception e){
         throw new RuntimeException("延时异常!");
        }
        int size = 0;
        List<ProcessDefinition> list = null;
        if (StringUtils.isNotEmpty(title)) {
            title = "%" + title + "%";
            size = repositoryService
                    .createProcessDefinitionQuery()
                    .processDefinitionNameLike(title).list().size();
            list = repositoryService
                    .createProcessDefinitionQuery()
                    .processDefinitionNameLike(title)
                    .orderByProcessDefinitionName().asc()
                    .orderByProcessDefinitionVersion().desc()
                    .listPage((pageNum - 1) * pageSize, pageSize);
        } else {
            size = repositoryService
                    .createProcessDefinitionQuery().list().size();
            list = repositoryService
                    .createProcessDefinitionQuery()
                    .orderByProcessDefinitionName().asc()
                    .orderByProcessDefinitionVersion().desc()
                    .listPage((pageNum - 1) * pageSize, pageSize);
        }
        List<MyProcessDefinition> collect = list.stream().map(x -> {
            MyProcessDefinition myProcessDefinition = new MyProcessDefinition();
            myProcessDefinition.setId(x.getId());
            myProcessDefinition.setDeploymentId(x.getDeploymentId());
            myProcessDefinition.setKey(x.getKey());
            myProcessDefinition.setName(x.getName());
            myProcessDefinition.setVersion(x.getVersion());
            myProcessDefinition.setDescription(x.getDescription());
            return myProcessDefinition;
        }).collect(Collectors.toList());
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setRows(collect);
        rspData.setTotal(size);
        return rspData;
    }

    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 BpmnModel get(String id) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(id).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        return bpmnModel;
    }

    public MyProcessDefinition processDefinitionKey(String processDefinitionKey) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey).latestVersion().singleResult();
        if (StringUtils.isNull(processDefinition)) {
            throw new CustomException("流程文件不存在请先上传流程");
        }
        MyProcessDefinition myProcessDefinition = new MyProcessDefinition();
        BeanUtils.copyProperties(processDefinition, myProcessDefinition);
        return myProcessDefinition;
    }
}
