package com.xjrsoft.module.job;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
import com.xjrsoft.module.oa.utils.SendMessageUtil;
import com.xjrsoft.module.workflow.entity.WorkflowAlertRecord;
import com.xjrsoft.module.workflow.entity.WorkflowSchema;
import com.xjrsoft.module.workflow.service.IWorkflowAlertRecordService;
import com.xjrsoft.module.workflow.service.IWorkflowSchemaService;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 流程未处理提醒申请人
 */
@Component
@Slf4j
public class ProcessTimeoutAlertTask {

    @Autowired
    private HistoryService historyService;

    @Autowired
    private IWorkflowSchemaService schemaService;

    @Autowired
    private IWorkflowAlertRecordService alertRecordService;
    @Scheduled(cron = "0 0 * * * ?")
    public void execute() {
        doExecute();
    }

    public void doExecute(){
        LocalDateTime now = LocalDateTime.now();
        try {
            HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().unfinished();

            List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.list();

            List<String> processIds = historicProcessInstances.stream().map(HistoricProcessInstance::getId).collect(Collectors.toList());

            if(!processIds.isEmpty()){
                //获取所有未完成流程的所有节点
                String uncloseProcessIdStr = processIds.stream()
                        .map(entity -> "'" + entity + "'")
                        .collect(Collectors.joining(","));
                String listWorkflowExtraSql = "select * " +
                        "from xjr_workflow_extra "
                        + "where process_id in (" + uncloseProcessIdStr + ") and end_time is null;";
                List<Map<String, Object>> workflowExtraList = SqlRunnerAdapter.db().selectList(listWorkflowExtraSql);

                JsonParser parser = new JsonParser();
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                Map<String, StringBuilder> message = new HashMap<>();
                List<WorkflowAlertRecord> recordList = new ArrayList<>();
                for (Map<String, Object> el : workflowExtraList) {
                    WorkflowSchema schema = schemaService.getById(el.get("schema_id").toString());
                    JsonObject jsonContent = parser.parse(schema.getJsonContent()).getAsJsonObject();
                    JsonObject timeoutRemidConfig = jsonContent.get("processConfig").getAsJsonObject().get("timeoutRemidConfig").getAsJsonObject();
                    if(!timeoutRemidConfig.get("enabled").getAsBoolean()){
                        continue;
                    }
                    String startUserId = el.get("start_user_id").toString();
                    List<WorkflowAlertRecord> record = alertRecordService.list(
                            new QueryWrapper<WorkflowAlertRecord>().lambda()
                                    .eq(WorkflowAlertRecord::getUserId, Long.parseLong(startUserId))
                                    .eq(WorkflowAlertRecord::getProcessId, Long.parseLong(el.get("process_id").toString()))
                                    .eq(WorkflowAlertRecord::getType, 1)
                                    .orderByDesc(WorkflowAlertRecord::getSendTime)
                    );
                    WorkflowAlertRecord alertRecord = record.get(0);
                    Duration lastBetween = Duration.between(alertRecord.getSendTime(), now);
                    long lasttime = Math.abs(lastBetween.getSeconds());

                    LocalDateTime startTime = LocalDateTime.parse(el.get("start_time").toString(), formatter);
                    Duration between = Duration.between(startTime, now);
                    long abs = Math.abs(between.getSeconds());
                    int hour = timeoutRemidConfig.get("hour").getAsInt() * 60 * 60;
                    int interval = timeoutRemidConfig.get("interval").getAsInt() * 60 * 60;
                    if(abs >= hour && lasttime >= interval){
                        //对未结束的流程节点进行处理，通知下一个节点需要处理的人

                        if(message.containsKey(startUserId)){
                            message.get(startUserId).append(",").append(el.get("process_name").toString());
                        }else {
                            message.put(startUserId, new StringBuilder(el.get("process_name").toString()));
                        }
                        recordList.add(
                                new WorkflowAlertRecord(){{
                                    setProcessId(Long.parseLong(el.get("process_id").toString()));
                                    setUserId(Long.parseLong(startUserId));
                                    setProcessName(el.get("process_name").toString());
                                    setType(1);
                                    setSendTime(now);
                                }}
                        );
                    }
                }
                if(!recordList.isEmpty()){
                    alertRecordService.saveBatch(recordList);
                }

                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowUnapprovedWx(message);
                });
            }
        } catch (Exception e) {
            log.error(e.getMessage(), "定时提醒流程未处理");
        }
    }
}
