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

import com.qqchen.deploy.backend.deploy.converter.DeployRecordConverter;
import com.qqchen.deploy.backend.deploy.dto.DeployRecordDTO;
import com.qqchen.deploy.backend.deploy.dto.DeployRecordFlowGraphDTO;
import com.qqchen.deploy.backend.deploy.entity.DeployRecord;
import com.qqchen.deploy.backend.deploy.entity.Team;
import com.qqchen.deploy.backend.deploy.entity.Application;
import com.qqchen.deploy.backend.deploy.entity.Environment;
import com.qqchen.deploy.backend.deploy.enums.DeployRecordStatusEnums;
import com.qqchen.deploy.backend.deploy.query.DeployRecordQuery;
import com.qqchen.deploy.backend.deploy.repository.IDeployRecordRepository;
import com.qqchen.deploy.backend.deploy.repository.ITeamRepository;
import com.qqchen.deploy.backend.deploy.repository.IApplicationRepository;
import com.qqchen.deploy.backend.deploy.repository.IEnvironmentRepository;
import com.qqchen.deploy.backend.deploy.service.IDeployRecordService;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.workflow.dto.WorkflowNodeInstanceDTO;
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
import com.qqchen.deploy.backend.workflow.entity.WorkflowNodeInstance;
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowNodeInstanceRepository;
import com.qqchen.deploy.backend.workflow.util.FlowableUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.RepositoryService;
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraph;
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraphNode;
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraphEdge;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 部署记录服务实现
 *
 * @author qqchen
 * @since 2025-11-02
 */
@Slf4j
@Service
public class DeployRecordServiceImpl extends BaseServiceImpl<DeployRecord, DeployRecordDTO, DeployRecordQuery, Long>
    implements IDeployRecordService {

    @Resource
    private IDeployRecordRepository deployRecordRepository;

    @Resource
    private DeployRecordConverter deployRecordConverter;

    @Resource
    private IWorkflowInstanceRepository workflowInstanceRepository;

    @Resource
    private IWorkflowNodeInstanceRepository workflowNodeInstanceRepository;

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private ITeamRepository teamRepository;

    @Resource
    private IApplicationRepository applicationRepository;

    @Resource
    private IEnvironmentRepository environmentRepository;

    @Override
    @Transactional
    public DeployRecordDTO createDeployRecord(Long workflowInstanceId, String businessKey, Long teamApplicationId, Long teamId, Long applicationId, Long environmentId, String deployBy, String deployRemark) {
        // 检查是否已存在
        DeployRecord existing = deployRecordRepository.findByWorkflowInstanceIdAndDeletedFalse(workflowInstanceId).orElse(null);

        if (existing != null) {
            log.warn("部署记录已存在: workflowInstanceId={}", workflowInstanceId);
            return deployRecordConverter.toDto(existing);
        }

        // 创建新记录
        DeployRecord record = new DeployRecord();
        record.setWorkflowInstanceId(workflowInstanceId);
        record.setBusinessKey(businessKey);
        record.setTeamApplicationId(teamApplicationId);
        record.setTeamId(teamId);
        record.setApplicationId(applicationId);
        record.setEnvironmentId(environmentId);
        record.setDeployBy(deployBy);
        record.setDeployRemark(deployRemark);
        record.setStatus(DeployRecordStatusEnums.CREATED);
        record.setStartTime(LocalDateTime.now());

        DeployRecord saved = deployRecordRepository.save(record);
        log.info("创建部署记录成功: id={}, workflowInstanceId={}, applicationId={}, environmentId={}", saved.getId(), workflowInstanceId, applicationId, environmentId);

        return deployRecordConverter.toDto(saved);
    }

    @Override
    @Transactional
    public void syncStatusFromWorkflowInstance(WorkflowInstance instance, WorkflowInstanceStatusEnums status) {
        DeployRecord record = deployRecordRepository
            .findByWorkflowInstanceIdAndDeletedFalse(instance.getId())
            .orElse(null);

        if (record == null) {
            log.warn("部署记录不存在，无法同步状态: workflowInstanceId={}", instance.getId());
            return;
        }

        // 如果当前状态已经是终态（特别是审批被拒绝的REJECTED），不应该被覆盖
        if (isFinalState(record.getStatus())) {
            log.debug("部署记录已处于终态，跳过同步: id={}, workflowInstanceId={}, currentStatus={}, workflowStatus={}",
                record.getId(), instance.getId(), record.getStatus(), status);
            // 只更新时间，不更新状态
            if (instance.getEndTime() != null && record.getEndTime() == null) {
                record.setEndTime(instance.getEndTime());
                deployRecordRepository.save(record);
            }
            return;
        }

        // 转换状态
        DeployRecordStatusEnums deployStatus = DeployRecordStatusEnums.fromWorkflowStatus(status.name());

        // 更新状态和时间
        record.setStatus(deployStatus);
        if (instance.getStartTime() != null && record.getStartTime() == null) {
            record.setStartTime(instance.getStartTime());
        }
        if (instance.getEndTime() != null) {
            record.setEndTime(instance.getEndTime());
        }

        deployRecordRepository.save(record);
        log.debug("同步部署记录状态: id={}, workflowInstanceId={}, status={}",
            record.getId(), instance.getId(), deployStatus);
    }

    @Override
    public DeployRecordDTO findByWorkflowInstanceId(Long workflowInstanceId) {
        return deployRecordRepository
            .findByWorkflowInstanceIdAndDeletedFalse(workflowInstanceId)
            .map(deployRecordConverter::toDto)
            .orElse(null);
    }

    @Override
    @Transactional
    public void updateStatusToPendingApproval(Long workflowInstanceId) {
        DeployRecord record = deployRecordRepository
            .findByWorkflowInstanceIdAndDeletedFalse(workflowInstanceId)
            .orElse(null);

        if (record == null) {
            log.warn("部署记录不存在，无法更新状态: workflowInstanceId={}", workflowInstanceId);
            return;
        }

        // 只有非终态才能更新为待审批
        if (isFinalState(record.getStatus())) {
            log.debug("部署记录已处于终态，跳过更新: workflowInstanceId={}, status={}",
                workflowInstanceId, record.getStatus());
            return;
        }

        record.setStatus(DeployRecordStatusEnums.PENDING_APPROVAL);
        deployRecordRepository.save(record);
        log.debug("部署记录状态已更新为待审批: id={}, workflowInstanceId={}",
            record.getId(), workflowInstanceId);
    }

    @Override
    @Transactional
    public void updateStatusFromApproval(Long workflowInstanceId, boolean approved) {
        DeployRecord record = deployRecordRepository
            .findByWorkflowInstanceIdAndDeletedFalse(workflowInstanceId)
            .orElse(null);

        if (record == null) {
            log.warn("部署记录不存在，无法更新状态: workflowInstanceId={}", workflowInstanceId);
            return;
        }

        // 只有非终态才能更新
        if (isFinalState(record.getStatus())) {
            log.debug("部署记录已处于终态，跳过更新: workflowInstanceId={}, status={}",
                workflowInstanceId, record.getStatus());
            return;
        }

        if (approved) {
            // 审批通过，更新为运行中
            record.setStatus(DeployRecordStatusEnums.RUNNING);
            log.info("部署记录状态已更新为运行中（审批通过）: id={}, workflowInstanceId={}",
                record.getId(), workflowInstanceId);
        } else {
            // 审批被拒绝，更新为审批被拒绝
            record.setStatus(DeployRecordStatusEnums.REJECTED);
            log.info("部署记录状态已更新为审批被拒绝: id={}, workflowInstanceId={}",
                record.getId(), workflowInstanceId);
        }

        deployRecordRepository.save(record);
    }

    @Override
    @Transactional(readOnly = true)
    public DeployRecordFlowGraphDTO getDeployFlowGraph(Long deployRecordId) {
        log.info("查询部署流程图: deployRecordId={}", deployRecordId);

        // ============ 1. 查询基础数据 ============

        // 1.1 查询部署记录
        DeployRecord deployRecord = deployRecordRepository.findById(deployRecordId)
            .orElseThrow(() -> new BusinessException(ResponseCode.NOT_FOUND, new Object[] {"部署记录"}));

        // 1.2 查询工作流实例
        WorkflowInstance workflowInstance = workflowInstanceRepository.findById(deployRecord.getWorkflowInstanceId())
            .orElseThrow(() -> new BusinessException(ResponseCode.NOT_FOUND, new Object[] {"工作流实例"}));

        // 1.3 获取流程图快照
        WorkflowDefinitionGraph graphSnapshot = workflowInstance.getGraphSnapshot();
        if (graphSnapshot == null || graphSnapshot.getNodes() == null) {
            log.warn("工作流实例 {} 的流程图快照为空", workflowInstance.getId());
            return buildEmptyFlowGraphDTO(deployRecord, workflowInstance);
        }

        // 1.4 查询业务上下文信息
        Team team = teamRepository.findById(deployRecord.getTeamId()).orElse(null);
        Application application = applicationRepository.findById(deployRecord.getApplicationId()).orElse(null);
        Environment environment = environmentRepository.findById(deployRecord.getEnvironmentId()).orElse(null);

        // ============ 2. 查询并组装节点执行状态 ============

        // 2.1 查询已执行的节点实例列表
        List<WorkflowNodeInstance> nodeInstances = workflowNodeInstanceRepository.findByWorkflowInstanceId(workflowInstance.getId());

        // 2.2 构建已执行节点的映射（按nodeId索引）
        Map<String, WorkflowNodeInstance> nodeInstanceMap = nodeInstances.stream()
            .collect(Collectors.toMap(WorkflowNodeInstance::getNodeId, instance -> instance, (a, b) -> a));

        // 2.3 从BPMN模型中获取流程元素顺序（用于排序）
        BpmnModel bpmnModel = repositoryService.getBpmnModel(workflowInstance.getProcessDefinitionId());
        Process process = bpmnModel.getMainProcess();
        List<FlowElement> flowElements = FlowableUtils.sortFlowElements(process);

        // 2.4 构建节点ID到流程顺序的映射
        Map<String, Integer> nodeOrderMap = new HashMap<>();
        for (int i = 0; i < flowElements.size(); i++) {
            nodeOrderMap.put(flowElements.get(i).getId(), i);
        }

        // 2.5 遍历流程图中的所有节点，组装节点DTO（包括已执行和未执行的）
        List<WorkflowNodeInstanceDTO> nodeInstanceDTOs = graphSnapshot.getNodes().stream()
            .sorted(Comparator.comparingInt(node -> nodeOrderMap.getOrDefault(node.getId(), Integer.MAX_VALUE)))
            .map(graphNode -> buildNodeInstanceDTO(graphNode, nodeInstanceMap.get(graphNode.getId()), workflowInstance))
            .collect(Collectors.toList());

        // ============ 3. 计算执行统计 ============

        int totalNodeCount = nodeInstanceDTOs.size();
        int executedNodeCount = (int) nodeInstanceDTOs.stream()
            .filter(node -> node.getStatus() != WorkflowNodeInstanceStatusEnums.NOT_STARTED)
            .count();
        int successNodeCount = (int) nodeInstanceDTOs.stream()
            .filter(node -> node.getStatus() == WorkflowNodeInstanceStatusEnums.COMPLETED)
            .count();
        int failedNodeCount = (int) nodeInstanceDTOs.stream()
            .filter(node -> node.getStatus() == WorkflowNodeInstanceStatusEnums.FAILED)
            .count();
        int runningNodeCount = (int) nodeInstanceDTOs.stream()
            .filter(node -> node.getStatus() == WorkflowNodeInstanceStatusEnums.RUNNING)
            .count();

        // ============ 4. 组装完整的DTO ============

        DeployRecordFlowGraphDTO dto = new DeployRecordFlowGraphDTO();

        // 4.1 部署记录基本信息
        dto.setDeployRecordId(deployRecord.getId());
        dto.setBusinessKey(deployRecord.getBusinessKey());
        dto.setDeployStatus(deployRecord.getStatus());
        dto.setDeployBy(deployRecord.getDeployBy());
        dto.setDeployRemark(deployRecord.getDeployRemark());
        dto.setDeployStartTime(deployRecord.getStartTime());
        dto.setDeployEndTime(deployRecord.getEndTime());
        dto.setDeployDuration(calculateDuration(deployRecord.getStartTime(), deployRecord.getEndTime()));

        // 4.2 业务上下文信息
        dto.setApplicationName(application != null ? application.getAppName() : null);
        dto.setApplicationCode(application != null ? application.getAppCode() : null);
        dto.setEnvironmentName(environment != null ? environment.getEnvName() : null);
        dto.setTeamName(team != null ? team.getTeamName() : null);

        // 4.3 工作流实例信息
        dto.setWorkflowInstanceId(workflowInstance.getId());
        dto.setProcessInstanceId(workflowInstance.getProcessInstanceId());
        dto.setWorkflowStatus(workflowInstance.getStatus());
        dto.setWorkflowStartTime(workflowInstance.getStartTime());
        dto.setWorkflowEndTime(workflowInstance.getEndTime());
        dto.setWorkflowDuration(calculateDuration(workflowInstance.getStartTime(), workflowInstance.getEndTime()));

        // 4.4 执行统计信息
        dto.setTotalNodeCount(totalNodeCount);
        dto.setExecutedNodeCount(executedNodeCount);
        dto.setSuccessNodeCount(successNodeCount);
        dto.setFailedNodeCount(failedNodeCount);
        dto.setRunningNodeCount(runningNodeCount);

        // 4.5 流程图数据
        dto.setGraph(graphSnapshot);
        dto.setNodeInstances(nodeInstanceDTOs);

        log.info("获取部署流程图成功: deployRecordId={}, 总节点数={}, 已执行={}, 成功={}, 失败={}, 运行中={}",
            deployRecordId, totalNodeCount, executedNodeCount, successNodeCount, failedNodeCount, runningNodeCount);

        return dto;
    }

    /**
     * 构建节点实例DTO
     *
     * @param graphNode        流程图节点
     * @param nodeInstance     节点实例（可能为null，表示未执行）
     * @param workflowInstance 工作流实例
     * @return 节点实例DTO
     */
    private WorkflowNodeInstanceDTO buildNodeInstanceDTO(
        WorkflowDefinitionGraphNode graphNode,
        WorkflowNodeInstance nodeInstance,
        WorkflowInstance workflowInstance) {

        WorkflowNodeInstanceDTO dto = new WorkflowNodeInstanceDTO();

        if (nodeInstance != null) {
            // ✅ 已执行的节点：使用节点实例的数据
            dto.setId(nodeInstance.getId());
            dto.setNodeId(nodeInstance.getNodeId());
            dto.setNodeName(nodeInstance.getNodeName());
            dto.setNodeType(nodeInstance.getNodeType());
            dto.setStatus(nodeInstance.getStatus());
            dto.setStartTime(nodeInstance.getStartTime());
            dto.setEndTime(nodeInstance.getEndTime());
            dto.setDuration(calculateDuration(nodeInstance.getStartTime(), nodeInstance.getEndTime()));
            dto.setErrorMessage(nodeInstance.getErrorMessage()); // ✅ 包含错误信息
            dto.setProcessInstanceId(nodeInstance.getProcessInstanceId());
            dto.setCreateTime(nodeInstance.getCreateTime());
            dto.setUpdateTime(nodeInstance.getUpdateTime());
        } else {
            // ✅ 未执行的节点：从流程图节点获取基本信息
            dto.setId(null);
            dto.setNodeId(graphNode.getId());
            dto.setNodeName(graphNode.getNodeName());
            dto.setNodeType(graphNode.getNodeType() != null ? graphNode.getNodeType().name() : null);
            dto.setStatus(WorkflowNodeInstanceStatusEnums.NOT_STARTED);
            dto.setStartTime(null);
            dto.setEndTime(null);
            dto.setDuration(null);
            dto.setErrorMessage(null);
            dto.setProcessInstanceId(workflowInstance.getProcessInstanceId());
            dto.setCreateTime(null);
            dto.setUpdateTime(null);
        }

        return dto;
    }

    /**
     * 计算时长（毫秒）
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 时长（毫秒），如果任一时间为 null 则返回 null
     */
    private Long calculateDuration(LocalDateTime startTime, LocalDateTime endTime) {
        if (startTime == null || endTime == null) {
            return null;
        }
        return java.time.Duration.between(startTime, endTime).toMillis();
    }


    /**
     * 构建空的流程图DTO（当流程图快照为空时）
     */
    private DeployRecordFlowGraphDTO buildEmptyFlowGraphDTO(DeployRecord deployRecord, WorkflowInstance workflowInstance) {
        DeployRecordFlowGraphDTO dto = new DeployRecordFlowGraphDTO();

        // 部署记录基本信息
        dto.setDeployRecordId(deployRecord.getId());
        dto.setBusinessKey(deployRecord.getBusinessKey());
        dto.setDeployStatus(deployRecord.getStatus());
        dto.setDeployBy(deployRecord.getDeployBy());
        dto.setDeployRemark(deployRecord.getDeployRemark());
        dto.setDeployStartTime(deployRecord.getStartTime());
        dto.setDeployEndTime(deployRecord.getEndTime());
        dto.setDeployDuration(calculateDuration(deployRecord.getStartTime(), deployRecord.getEndTime()));

        // 工作流实例信息
        dto.setWorkflowInstanceId(workflowInstance.getId());
        dto.setProcessInstanceId(workflowInstance.getProcessInstanceId());
        dto.setWorkflowStatus(workflowInstance.getStatus());
        dto.setWorkflowStartTime(workflowInstance.getStartTime());
        dto.setWorkflowEndTime(workflowInstance.getEndTime());
        dto.setWorkflowDuration(calculateDuration(workflowInstance.getStartTime(), workflowInstance.getEndTime()));

        // 执行统计信息（都为0）
        dto.setTotalNodeCount(0);
        dto.setExecutedNodeCount(0);
        dto.setSuccessNodeCount(0);
        dto.setFailedNodeCount(0);
        dto.setRunningNodeCount(0);

        // 流程图数据（空）
        dto.setGraph(new WorkflowDefinitionGraph());
        dto.setNodeInstances(new ArrayList<>());

        return dto;
    }

    /**
     * 判断是否为终态
     */
    private boolean isFinalState(DeployRecordStatusEnums status) {
        return status == DeployRecordStatusEnums.SUCCESS
            || status == DeployRecordStatusEnums.FAILED
            || status == DeployRecordStatusEnums.REJECTED
            || status == DeployRecordStatusEnums.CANCELLED
            || status == DeployRecordStatusEnums.TERMINATED
            || status == DeployRecordStatusEnums.PARTIAL_SUCCESS;
    }
}

