package org.dromara.workflow.utils;

import cn.hutool.core.bean.BeanUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.workflow.domain.vo.TaskVo;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.history.HistoricActivityInstanceQuery;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.DeploymentQuery;
import org.flowable.engine.repository.ModelQuery;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;

import java.util.*;

/**
 * 查询工具
 *
 * @author Lion Li
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class QueryUtils {

    private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);

    public static ModelQuery modelQuery() {
        ModelQuery query = PROCESS_ENGINE.getRepositoryService().createModelQuery();
        if (TenantHelper.isEnable()) {
            query.modelTenantId(TenantHelper.getTenantId());
        }
        return query;
    }

    public static ProcessDefinitionQuery definitionQuery() {
        ProcessDefinitionQuery query = PROCESS_ENGINE.getRepositoryService().createProcessDefinitionQuery();
        if (TenantHelper.isEnable()) {
            query.processDefinitionTenantId(TenantHelper.getTenantId());
        }
        return query;
    }

    public static DeploymentQuery deploymentQuery() {
        DeploymentQuery query = PROCESS_ENGINE.getRepositoryService().createDeploymentQuery();
        if (TenantHelper.isEnable()) {
            query.deploymentTenantId(TenantHelper.getTenantId());
        }
        return query;
    }

    public static DeploymentQuery deploymentQuery(String deploymentId) {
        return deploymentQuery().deploymentId(deploymentId);
    }

    public static DeploymentQuery deploymentQuery(List<String> deploymentIds) {
        return deploymentQuery().deploymentIds(deploymentIds);
    }

    public static HistoricTaskInstanceQuery hisTaskInstanceQuery() {
        HistoricTaskInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricTaskInstanceQuery();
        if (TenantHelper.isEnable()) {
            query.taskTenantId(TenantHelper.getTenantId());
        }
        return query;
    }

    public static HistoricTaskInstanceQuery hisTaskInstanceQuery(String processInstanceId) {
        return hisTaskInstanceQuery().processInstanceId(processInstanceId);
    }

    public static HistoricTaskInstanceQuery hisTaskBusinessKeyQuery(String businessKey) {
        return hisTaskInstanceQuery().processInstanceBusinessKey(businessKey);
    }

    public static ProcessInstanceQuery instanceQuery() {
        ProcessInstanceQuery query = PROCESS_ENGINE.getRuntimeService().createProcessInstanceQuery();
        if (TenantHelper.isEnable()) {
            query.processInstanceTenantId(TenantHelper.getTenantId());
        }
        return query;
    }

    public static ProcessInstanceQuery instanceQuery(String processInstanceId) {
        return instanceQuery().processInstanceId(processInstanceId);
    }

    public static ProcessInstanceQuery businessKeyQuery(String businessKey) {
        return instanceQuery().processInstanceBusinessKey(businessKey);
    }

    public static ProcessInstanceQuery instanceQuery(Set<String> processInstanceIds) {
        return instanceQuery().processInstanceIds(processInstanceIds);
    }

    public static HistoricProcessInstanceQuery hisInstanceQuery() {
        HistoricProcessInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricProcessInstanceQuery();
        if (TenantHelper.isEnable()) {
            query.processInstanceTenantId(TenantHelper.getTenantId());
        }
        return query;
    }

    public static HistoricProcessInstanceQuery hisInstanceQuery(String processInstanceId) {
        return hisInstanceQuery().processInstanceId(processInstanceId);
    }

    public static HistoricProcessInstanceQuery hisBusinessKeyQuery(String businessKey) {
        return hisInstanceQuery().processInstanceBusinessKey(businessKey);
    }

    public static HistoricProcessInstanceQuery hisBusinessKeyQuery(String businessKey, String processInstanceId) {
        return hisInstanceQuery().processInstanceBusinessKey(businessKey).processInstanceId(processInstanceId);
    }
    public static HistoricProcessInstanceQuery hisInstanceQuery(Set<String> processInstanceIds) {
        return hisInstanceQuery().processInstanceIds(processInstanceIds);
    }

    public static HistoricActivityInstanceQuery hisActivityInstanceQuery() {
        HistoricActivityInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricActivityInstanceQuery();
        if (TenantHelper.isEnable()) {
            query.activityTenantId(TenantHelper.getTenantId());
        }
        return query;
    }

    public static HistoricActivityInstanceQuery hisActivityInstanceQuery(String processInstanceId) {
        return hisActivityInstanceQuery().processInstanceId(processInstanceId);
    }

    public static TaskQuery taskQuery() {
        TaskQuery query = PROCESS_ENGINE.getTaskService().createTaskQuery();
        if (TenantHelper.isEnable()) {
            query.taskTenantId(TenantHelper.getTenantId());
        }
        return query;
    }

    public static TaskQuery taskQuery(String processInstanceId) {
        return taskQuery().processInstanceId(processInstanceId);
    }

    public static TaskQuery taskQuery(Collection<String> processInstanceIds) {
        return taskQuery().processInstanceIdIn(processInstanceIds);
    }

    /**
     * 按照任务id查询当前任务
     *
     * @param taskId 任务id
     */
    public static TaskVo getTask(String taskId) {
        Task task = PROCESS_ENGINE.getTaskService().createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            return null;
        }

        // 获取 HistoryService
        HistoryService historyService = PROCESS_ENGINE.getHistoryService();
        // 1. 查询指定 taskId 和 processInstanceId 的历史任务
        HistoricTaskInstance historicTask = historyService.createHistoricTaskInstanceQuery()
            .taskId(taskId)
            .processInstanceId(task.getProcessInstanceId())
            .singleResult();

        if (historicTask == null) {
            return null; // 未找到匹配的历史任务
        }

        // 2. 查询对应的历史流程实例
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
            .processInstanceId(task.getProcessInstanceId())
            .singleResult();

        // 3. 封装 TaskVo 对象
        TaskVo taskVo = BeanUtil.toBean(historicTask, TaskVo.class);

        if (historicProcessInstance != null) {
            // 设置业务 Key（businessId）
            taskVo.setBusinessKey(historicProcessInstance.getBusinessKey());
        }

        // 4. 判断是否为多实例任务
        taskVo.setMultiInstance(
            WorkflowUtils.isMultiInstance(historicTask.getProcessDefinitionId(), historicTask.getTaskDefinitionKey()) != null
        );

        // 5. 获取业务状态（此处 businessKey 唯一定位业务状态）
        String businessStatus = WorkflowUtils.hisBusinessKeyAndInstanceQuery(
            taskVo.getBusinessKey(),
            task.getProcessInstanceId());// 传入流程实例 ID 进行过滤
        taskVo.setBusinessStatus(businessStatus);

        return taskVo;
    }

    /**
     * 按照任务id查询当前任务
     *
     * @param businessKey 任务id
     */
    public static Map<String, Object> getTaskInfoByBusinessKey(String businessKey) {
        Map<String, Object> map = new HashMap<>();
        Task taskInfo = PROCESS_ENGINE.getTaskService().createTaskQuery()
            .processVariableValueEquals("businessId", businessKey) // 根据流程变量 businessId 查询
            .orderByTaskCreateTime().desc() // 按创建时间降序
            .singleResult();
        log.info("businessKey:{},taskInfo{}", businessKey, taskInfo);
        if (taskInfo == null) {
            return null;
        }
        map.put("taskId", taskInfo.getId());
        map.put("processInstanceId", taskInfo.getProcessInstanceId());
        return map;
    }
}
