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

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.workflow.dto.inputmapping.ApprovalInputMapping;
import com.qqchen.deploy.backend.workflow.dto.outputs.ApprovalOutputs;
import com.qqchen.deploy.backend.workflow.dto.request.ApprovalTaskRequest;
import com.qqchen.deploy.backend.workflow.dto.response.ApprovalTaskDTO;
import com.qqchen.deploy.backend.workflow.model.NodeContext;
import com.qqchen.deploy.backend.workflow.service.IApprovalTaskService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 审批任务服务实现
 *
 * @author qqchen
 * @date 2025-10-23
 */
@Slf4j
@Service
public class ApprovalTaskServiceImpl implements IApprovalTaskService {

    @Resource
    private TaskService taskService;
    
    @Resource
    private ObjectMapper objectMapper;

    @Override
    public List<ApprovalTaskDTO> getMyTasks(String username) {
        log.info("查询用户 {} 的待办任务", username);
        
        List<Task> tasks = taskService.createTaskQuery()
                .taskAssignee(username)
                .orderByTaskCreateTime()
                .desc()
                .list();

        return tasks.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<ApprovalTaskDTO> getTasksByProcessInstance(String processInstanceId) {
        log.info("查询流程实例 {} 的所有任务", processInstanceId);
        
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .orderByTaskCreateTime()
                .desc()
                .list();

        return tasks.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public ApprovalTaskDTO getTaskById(String taskId) {
        log.info("查询任务详情: {}", taskId);
        
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();

        if (task == null) {
            throw new BusinessException(ResponseCode.DATA_NOT_FOUND);
        }

        return convertToDTO(task);
    }

    @Override
    @Transactional
    public void completeTask(ApprovalTaskRequest request) {
        log.info("处理审批任务: taskId={}, result={}", request.getTaskId(), request.getResult());

        // 检查任务是否存在
        Task task = taskService.createTaskQuery()
                .taskId(request.getTaskId())
                .singleResult();

        if (task == null) {
            throw new BusinessException(ResponseCode.DATA_NOT_FOUND);
        }

        // ✅ 获取节点ID并更新 NodeContext
        String nodeId = task.getTaskDefinitionKey();
        
        // 读取现有 NodeContext
        Object nodeDataObj = taskService.getVariable(task.getId(), nodeId);
        NodeContext<ApprovalInputMapping, ApprovalOutputs> nodeContext;
        if (nodeDataObj instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> nodeDataMap = (Map<String, Object>) nodeDataObj;
            nodeContext = NodeContext.fromMap(nodeDataMap, 
                ApprovalInputMapping.class, ApprovalOutputs.class, objectMapper);
        } else {
            nodeContext = new NodeContext<>();
        }
        
        // 创建临时审批数据（稍后由 ApprovalExecutionListener 完善）
        ApprovalOutputs tempOutputs = new ApprovalOutputs();
        tempOutputs.setApprovalResult(request.getResult());
        tempOutputs.setApprover(task.getAssignee());
        tempOutputs.setApprovalTime(LocalDateTime.now());
        tempOutputs.setApprovalComment(request.getComment());
        
        // 暂时设置为 outputs（ApprovalExecutionListener 会完善）
        nodeContext.setOutputs(tempOutputs);
        
        // 保存回流程变量
        taskService.setVariable(task.getId(), nodeId, nodeContext.toMap(objectMapper));
        
        // 5. 添加任务评论（供历史查询）
        if (request.getComment() != null) {
            taskService.addComment(request.getTaskId(), task.getProcessInstanceId(), request.getComment());
        }

        // 6. 完成任务（触发 ApprovalExecutionListener）
        // ApprovalExecutionListener 会：
        // - 读取上面设置的变量
        // - 自动装配其他上下文信息（approvalDuration、allApprovers 等）
        // - 构建完整的 ApprovalOutputs 对象
        // - 以 nodeId 为 key 存储到流程变量
        taskService.complete(request.getTaskId());
        
        log.info("审批任务完成: taskId={}, result={}", request.getTaskId(), request.getResult());
    }

    /**
     * 转换 Task 为 DTO
     */
    private ApprovalTaskDTO convertToDTO(Task task) {
        ApprovalTaskDTO dto = new ApprovalTaskDTO();
        dto.setTaskId(task.getId());
        dto.setTaskName(task.getName());
        dto.setTaskDescription(task.getDescription());
        dto.setProcessInstanceId(task.getProcessInstanceId());
        dto.setProcessDefinitionId(task.getProcessDefinitionId());
        dto.setAssignee(task.getAssignee());

        if (task.getCreateTime() != null) {
            dto.setCreateTime(LocalDateTime.ofInstant(
                    task.getCreateTime().toInstant(), 
                    ZoneId.systemDefault()));
        }

        if (task.getDueDate() != null) {
            dto.setDueDate(LocalDateTime.ofInstant(
                    task.getDueDate().toInstant(), 
                    ZoneId.systemDefault()));
        }

        // 获取任务变量
        Map<String, Object> variables = taskService.getVariables(task.getId());
        if (variables != null) {
            dto.setApprovalTitle((String) variables.get("approvalTitle"));
            dto.setApprovalContent((String) variables.get("approvalContent"));
            dto.setApprovalMode((String) variables.get("approvalMode"));
            dto.setCandidateGroups((String) variables.get("candidateGroups"));
            dto.setAllowDelegate((Boolean) variables.get("allowDelegate"));
            dto.setAllowAddSign((Boolean) variables.get("allowAddSign"));
            dto.setRequireComment((Boolean) variables.get("requireComment"));
        }

        return dto;
    }
}

