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

import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.workflow.converter.WorkflowNodeInstanceConverter;
import com.qqchen.deploy.backend.workflow.dto.WorkflowNodeInstanceDTO;
import com.qqchen.deploy.backend.workflow.dto.query.WorkflowNodeInstanceQuery;
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
import com.qqchen.deploy.backend.workflow.entity.WorkflowNodeInstance;
import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.dto.event.WorkflowNodeInstanceStatusChangeEvent;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowNodeInstanceRepository;
import com.qqchen.deploy.backend.workflow.service.IWorkflowNodeInstanceService;
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.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WorkflowNodeInstanceServiceImpl extends BaseServiceImpl<WorkflowNodeInstance, WorkflowNodeInstanceDTO, WorkflowNodeInstanceQuery, Long> implements IWorkflowNodeInstanceService {

    @Resource
    private IWorkflowNodeInstanceRepository workflowNodeInstanceRepository;

    @Resource
    private WorkflowNodeInstanceConverter workflowNodeInstanceConverter;

    @Resource
    private IWorkflowInstanceRepository workflowInstanceRepository;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkflowNodeInstance updateNodeStatus(String processInstanceId, String executionId, WorkflowNodeInstanceStatusEnums status) {
        WorkflowNodeInstance nodeInstance = workflowNodeInstanceRepository.findByProcessInstanceIdAndExecutionId(processInstanceId, executionId)
            .orElseThrow(() -> new RuntimeException("Node instance not found for processInstanceId: " + processInstanceId + ", executionId: " + executionId));

        nodeInstance.setStatus(status);
        nodeInstance.setUpdateTime(LocalDateTime.now());

        if (status == WorkflowNodeInstanceStatusEnums.COMPLETED ||
            status == WorkflowNodeInstanceStatusEnums.TERMINATED ||
            status == WorkflowNodeInstanceStatusEnums.FAILED) {
            nodeInstance.setEndTime(LocalDateTime.now());
        }

        return workflowNodeInstanceRepository.save(nodeInstance);
    }

    @Override
    public List<WorkflowNodeInstanceDTO> getNodesByProcessInstanceId(String processInstanceId) {
        List<WorkflowNodeInstance> nodes = workflowNodeInstanceRepository.findByProcessInstanceId(processInstanceId);
        return nodes.stream()
            .map(workflowNodeInstanceConverter::toDto)
            .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void saveOrUpdateWorkflowNodeInstance(WorkflowNodeInstanceStatusChangeEvent event) {
        WorkflowNodeInstance nodeInstance = workflowNodeInstanceConverter.eventToEntity(event);
        WorkflowInstance workflowInstance = workflowInstanceRepository.findByProcessInstanceId(nodeInstance.getProcessInstanceId())
            .orElseThrow(() -> new RuntimeException("Node instance not found for processInstanceId: " + nodeInstance.getProcessInstanceId()));
        WorkflowNodeInstance workflowNodeInstance = workflowNodeInstanceRepository.findByProcessInstanceIdAndNodeId(workflowInstance.getProcessInstanceId(), event.getNodeId());
        if (workflowNodeInstance == null) {
            nodeInstance.setWorkflowInstanceId(workflowInstance.getId());
            nodeInstance.setWorkflowDefinitionId(workflowInstance.getWorkflowDefinitionId());
            super.repository.save(nodeInstance);
            return;
        }
        workflowNodeInstance.setEndTime(event.getEndTime());
        workflowNodeInstance.setStatus(event.getStatus());
        super.repository.save(workflowNodeInstance);
    }
}
