package com.qqchen.deploy.backend.workflow.service.impl;

import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.workflow.dto.WorkflowCategoryDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowExecutionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowTriggerTypeDTO;
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraph;
import com.qqchen.deploy.backend.workflow.dto.query.WorkflowDefinitionQuery;
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
import com.qqchen.deploy.backend.workflow.enums.WorkflowDefinitionStatusEnums;
import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository;
import com.qqchen.deploy.backend.workflow.service.IWorkflowDefinitionService;
import com.qqchen.deploy.backend.workflow.service.IWorkflowInstanceService;
import com.qqchen.deploy.backend.workflow.util.BpmnConverter;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.FlowElement;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 工作流定义服务实现
 */
@Slf4j
@Service
public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefinition, WorkflowDefinitionDTO, WorkflowDefinitionQuery, Long> implements IWorkflowDefinitionService {

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private ManagementService managementService;

    @Resource
    private TaskService taskService;

    @Resource
    private HistoryService historyService;

    @Resource
    private IWorkflowDefinitionRepository workflowDefinitionRepository;

    @Resource
    private com.qqchen.deploy.backend.workflow.repository.IWorkflowCategoryRepository workflowCategoryRepository;

    @Resource
    private com.qqchen.deploy.backend.workflow.converter.WorkflowCategoryConverter workflowCategoryConverter;

    @Resource
    private BpmnConverter bpmnConverter;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkflowDefinitionDTO saveWorkflowDesign(WorkflowDefinitionDTO dto) throws Exception {
        WorkflowDefinition definition = super.converter.toEntity(dto);
        workflowDefinitionRepository.save(definition);
        return super.converter.toDto(definition);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Deployment deployWorkflow(WorkflowDefinition workflowDefinition) {
        try {
            // 部署流程
            Deployment deployment = repositoryService.createDeployment()
                .addString(workflowDefinition.getKey() + ".bpmn20.xml", workflowDefinition.getBpmnXml())
                .name(workflowDefinition.getName())
                .deploy();
            log.info("Successfully deployed workflow: {}", workflowDefinition.getName());
            return deployment;
        } catch (Exception e) {
            log.error("Failed to deploy workflow: {}", workflowDefinition.getName(), e);
            throw new RuntimeException("Failed to deploy workflow", e);
        }
    }


    @Override
    public void suspendWorkflow(String processInstanceId) {
        try {
            runtimeService.suspendProcessInstanceById(processInstanceId);
            log.info("Suspended workflow instance: {}", processInstanceId);
        } catch (Exception e) {
            log.error("Failed to suspend workflow instance: {}", processInstanceId, e);
            throw new RuntimeException("Failed to suspend workflow instance", e);
        }
    }

    @Override
    public void resumeWorkflow(String processInstanceId) {
        try {
            runtimeService.activateProcessInstanceById(processInstanceId);
            log.info("Resumed workflow instance: {}", processInstanceId);
        } catch (Exception e) {
            log.error("Failed to resume workflow instance: {}", processInstanceId, e);
            throw new RuntimeException("Failed to resume workflow instance", e);
        }
    }

    @Override
    public WorkflowExecutionDTO getWorkflowExecution(String processInstanceId) {
        try {
            log.info("=== 开始获取工作流执行状态 ===");
            log.info("流程实例ID: {}", processInstanceId);

            // 1. 获取流程实例信息
            ProcessInstance runningInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();

            HistoricProcessInstance historicInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();

            if (historicInstance == null) {
                throw new RuntimeException("Process instance not found: " + processInstanceId);
            }

            // 2. 获取流程定义
            BpmnModel bpmnModel = repositoryService.getBpmnModel(historicInstance.getProcessDefinitionId());
            Process process = bpmnModel.getMainProcess();

            // 3. 获取所有节点（不包括连线）
            List<FlowElement> nodes = process.getFlowElements().stream()
                .filter(element -> !(element instanceof SequenceFlow))
                .collect(Collectors.toList());

            // 4. 获取正在执行的节点
            Set<String> runningNodes = runtimeService.createExecutionQuery()
                .processInstanceId(processInstanceId)
                .list()
                .stream()
                .map(Execution::getActivityId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

            // 5. 获取历史节点
            Map<String, HistoricActivityInstance> historicNodes = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime()
                .asc()
                .list()
                .stream()
                .filter(activity -> !(activity.getActivityType().equals("sequenceFlow")))
                .collect(Collectors.toMap(
                    HistoricActivityInstance::getActivityId,
                    activity -> activity,
                    (existing, replacement) -> existing
                ));

            // 6. 构建执行状态DTO
            WorkflowExecutionDTO executionDTO = new WorkflowExecutionDTO();
            executionDTO.setProcessInstanceId(processInstanceId);
            executionDTO.setProcessDefinitionId(historicInstance.getProcessDefinitionId());
            executionDTO.setProcessDefinitionName(historicInstance.getProcessDefinitionName());
            executionDTO.setBusinessKey(historicInstance.getBusinessKey());
            executionDTO.setStartTime(historicInstance.getStartTime());
            executionDTO.setEndTime(historicInstance.getEndTime());
            executionDTO.setDurationInMillis(historicInstance.getDurationInMillis());

            // 设置流程状态
            if (historicInstance.getEndTime() != null) {
                executionDTO.setStatus(historicInstance.getDeleteReason() == null ?
                    WorkflowNodeInstanceStatusEnums.COMPLETED : WorkflowNodeInstanceStatusEnums.FAILED);
            } else {
                executionDTO.setStatus(runningInstance != null && runningInstance.isSuspended() ?
                    WorkflowNodeInstanceStatusEnums.SUSPENDED : WorkflowNodeInstanceStatusEnums.RUNNING);
            }

            // 7. 构建节点状态列表
            List<WorkflowExecutionDTO.StageDTO> stages = new ArrayList<>();
            boolean hasFailedNode = false;

            for (FlowElement element : nodes) {
                WorkflowExecutionDTO.StageDTO stage = new WorkflowExecutionDTO.StageDTO();
                stage.setId(element.getId());
                stage.setName(element.getName());
                stage.setType(element.getClass().getSimpleName());

                // 如果已经有节点失败，后续节点都是未开始
                if (hasFailedNode) {
                    stage.setStatus(WorkflowNodeInstanceStatusEnums.NOT_STARTED);
                    stages.add(stage);
                    continue;
                }

                // 判断节点状态
                if (runningNodes.contains(element.getId())) {
                    // 正在执行的节点
                    stage.setStatus(WorkflowNodeInstanceStatusEnums.RUNNING);
                } else {
                    // 查找历史记录
                    HistoricActivityInstance historicActivity = historicNodes.get(element.getId());
                    if (historicActivity != null) {
                        stage.setStartTime(historicActivity.getStartTime());
                        stage.setEndTime(historicActivity.getEndTime());

                        if (historicActivity.getEndTime() != null) {
                            if (historicActivity.getDeleteReason() != null) {
                                // 节点失败
                                stage.setStatus(WorkflowNodeInstanceStatusEnums.FAILED);
                                hasFailedNode = true;
                            } else {
                                // 节点完成
                                stage.setStatus(WorkflowNodeInstanceStatusEnums.COMPLETED);
                            }
                        } else {
                            // 有开始时间但没有结束时间，说明正在运行
                            stage.setStatus(WorkflowNodeInstanceStatusEnums.RUNNING);
                        }
                    } else {
                        // 没有历史记录，未开始
                        stage.setStatus(WorkflowNodeInstanceStatusEnums.NOT_STARTED);
                    }
                }

                stages.add(stage);
            }

            // 按开始时间排序
            stages.sort((a, b) -> {
                if (a.getStartTime() == null && b.getStartTime() == null) {
                    return 0;
                }
                if (a.getStartTime() == null) {
                    return 1;
                }
                if (b.getStartTime() == null) {
                    return -1;
                }
                return a.getStartTime().compareTo(b.getStartTime());
            });

            executionDTO.setStages(stages);
            return executionDTO;
        } catch (Exception e) {
            log.error("获取工作流执行状态失败", e);
            throw new RuntimeException("Failed to get workflow execution status", e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disable(Long id) {
        try {
            // 1. 查询流程定义
            WorkflowDefinition definition = workflowDefinitionRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Workflow definition not found: " + id));

            // 2. 查询部署
            List<Deployment> deployments = repositoryService.createDeploymentQuery()
                .processDefinitionKey(definition.getKey())
                .list();

            if (deployments.isEmpty()) {
                // 如果没有部署，直接更新状态
                definition.setStatus(WorkflowDefinitionStatusEnums.DISABLED);
                workflowDefinitionRepository.save(definition);
                return;
            }

            // 3. 查询历史实例
            long historyCount = historyService.createHistoricProcessInstanceQuery()
                .processDefinitionKey(definition.getKey())
                .count();

            if (historyCount == 0) {
                // 如果从未运行过，直接删除部署
                for (Deployment deployment : deployments) {
                    repositoryService.deleteDeployment(deployment.getId(), true);
                }
            } else {
                // 如果有运行历史，则挂起流程定义
                repositoryService.suspendProcessDefinitionByKey(definition.getKey());
            }

            // 4. 更新我们的流程定义状态
            definition.setStatus(WorkflowDefinitionStatusEnums.DISABLED);
            workflowDefinitionRepository.save(definition);

            log.info("Successfully disabled workflow definition: {}, key: {}, hasHistory: {}",
                id, definition.getKey(), historyCount > 0);

        } catch (Exception e) {
            log.error("Failed to disable workflow definition: {}", id, e);
            throw new RuntimeException("Failed to disable workflow definition", e);
        }
    }

    @Override
    public void enable(Long id) {
        WorkflowDefinition definition = workflowDefinitionRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("Workflow definition not found: " + id));
        repositoryService.createDeployment().addString(definition.getKey() + ".bpmn20.xml", definition.getBpmnXml())
            .key(definition.getKey()).name(definition.getName()).deploy();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publishedWorkflowDesign(Long workflowDefinitionId) {
        WorkflowDefinition definition = workflowDefinitionRepository.findById(workflowDefinitionId)
            .orElseThrow(() -> new RuntimeException("Workflow definition not found: " + workflowDefinitionId));
        WorkflowDefinitionGraph graph = definition.getGraph();
        definition.setBpmnXml(bpmnConverter.convertToXml(graph, definition.getKey()));
        Deployment deployment = this.deployWorkflow(definition);
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
        definition.setStatus(WorkflowDefinitionStatusEnums.PUBLISHED);
        definition.setFlowVersion(1);
        definition.setProcessDefinitionId(processDefinition.getId());
        workflowDefinitionRepository.save(definition);
        log.info("Successfully published workflow definition: {}", workflowDefinitionId);
    }

    @Override
    public List<WorkflowCategoryDTO> getWorkflowCategories() {
        // 从数据库查询启用的工作流分类，按排序字段排序
        return workflowCategoryRepository.findAll().stream()
            .filter(category -> category.getEnabled() && !category.getDeleted())
            .sorted((a, b) -> a.getSort().compareTo(b.getSort()))
            .map(workflowCategoryConverter::toDto)
            .collect(Collectors.toList());
    }

    @Override
    public List<WorkflowDefinitionDTO> findPublishedWorkflow() {
        return this.converter.toDtoList(workflowDefinitionRepository.findByStatus(WorkflowDefinitionStatusEnums.PUBLISHED));
    }

}
