package com.qqchen.deploy.backend.workflow.listener;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.workflow.dto.event.ApprovalCompletedEvent;
import com.qqchen.deploy.backend.workflow.dto.inputmapping.ApprovalInputMapping;
import com.qqchen.deploy.backend.workflow.dto.outputs.ApprovalOutputs;
import com.qqchen.deploy.backend.workflow.enums.ApprovalResultEnum;
import com.qqchen.deploy.backend.workflow.enums.NodeExecutionStatusEnum;
import com.qqchen.deploy.backend.workflow.model.NodeContext;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowCategoryRepository;
import com.qqchen.deploy.backend.workflow.utils.WorkflowUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * 审批节点结束监听器
 * 在 UserTask 结束时自动装配上下文信息并构建 ApprovalOutputs
 *
 * @author qqchen
 * @since 2025-10-23
 */
@Slf4j
@Component("approvalEndExecutionListener")
public class ApprovalEndExecutionListener extends BaseExecutionListener {

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private HistoryService historyService;

    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Resource
    private IWorkflowInstanceRepository workflowInstanceRepository;

    @Resource
    private IWorkflowDefinitionRepository workflowDefinitionRepository;

    @Resource
    private IWorkflowCategoryRepository workflowCategoryRepository;

    @Override
    public void notify(DelegateExecution execution) {
        String nodeId = execution.getCurrentActivityId();
        NodeContext<ApprovalInputMapping, ApprovalOutputs> nodeContext = null;
        
        try {
            log.info("ApprovalExecutionListener: Building outputs for node: {}", nodeId);

            // 1. 读取 NodeContext（统一使用 NodeContext，与 BaseNodeDelegate 保持一致）
            nodeContext = WorkflowUtils.readNodeContext(execution, nodeId, ApprovalInputMapping.class, ApprovalOutputs.class, objectMapper);
            if (nodeContext == null) {
                return;
            }

            // 2. 检查并获取 outputs
            ApprovalOutputs outputs = nodeContext.getOutputs();
            if (outputs == null) {
                log.warn("Outputs not found in NodeContext for node: {}, skipping", nodeId);
                return;
            }

            // 3. 自动装配上下文信息（丰富 outputs）
            enrichApprovalOutputs(execution, nodeId, outputs);

            // 4. 更新并保存 NodeContext（与 BaseNodeDelegate 保持一致）
            nodeContext.setOutputs(outputs);
            WorkflowUtils.saveNodeContext(execution, nodeId, nodeContext, objectMapper);
            
            log.info("Stored approval outputs for node: {}, result: {}", nodeId, outputs.getApprovalResult());

            // 5. 发布审批完成事件
            publishApprovalCompletedEvent(execution, nodeId, outputs);

        } catch (Exception e) {
            log.error("Failed to build approval outputs for node: {}", nodeId, e);
            
            // ❌ 根据 continueOnFailure 配置决定行为
            boolean continueOnFailure = WorkflowUtils.getContinueOnFailure(
                nodeContext != null ? nodeContext.getInputMapping() : null
            );
            
            if (continueOnFailure) {
                // ⚠️ 非阻断模式：记录失败但流程继续
                log.warn("⚠️ Approval listener failed (continue mode enabled by config): {}", e.getMessage());
                handleFailure(execution, nodeId, e);
            } else {
                // ❌ 阻断模式：终止流程（默认行为）
                log.error("❌ Approval listener failed (terminate mode, default): {}", e.getMessage());
                terminateWorkflow(e);
            }
        }
    }


    /**
     * 自动装配 ApprovalOutputs（丰富 outputs 的上下文信息）
     */
    private void enrichApprovalOutputs(DelegateExecution execution, String nodeId, ApprovalOutputs outputs) {
        // 1. 审批用时（从任务历史计算）
        Long duration = calculateApprovalDuration(execution, nodeId);
        if (duration != null) {
            outputs.setApprovalDuration(duration);
        }

        // 2. 节点执行状态（审批节点无论通过还是拒绝，都是成功完成）
        // 只有当审批过程中发生系统异常时，才应该标记为失败（FAILED）
        if (outputs.getStatus() == null) {
            outputs.setStatus(NodeExecutionStatusEnum.SUCCESS);
        }
    }

    /**
     * 处理异常情况（统一使用 NodeContext，与 BaseNodeDelegate 保持一致）
     */
    private void handleFailure(DelegateExecution execution, String nodeId, Exception e) {
        try {
            NodeContext<ApprovalInputMapping, ApprovalOutputs> nodeContext = 
                WorkflowUtils.readNodeContext(execution, nodeId, ApprovalInputMapping.class, ApprovalOutputs.class, objectMapper);
            if (nodeContext == null) {
                // 如果无法读取 NodeContext，创建新的
                nodeContext = new NodeContext<>();
            }

            // 创建失败状态的 outputs（与 BaseNodeDelegate 的模式一致）
            ApprovalOutputs failureOutputs = nodeContext.getOutputs();
            if (failureOutputs == null) {
                failureOutputs = new ApprovalOutputs();
            }
            failureOutputs.setStatus(NodeExecutionStatusEnum.FAILURE);
            failureOutputs.setMessage("审批节点执行异常: " + e.getMessage());

            nodeContext.setOutputs(failureOutputs);
            WorkflowUtils.saveNodeContext(execution, nodeId, nodeContext, objectMapper);
        } catch (Exception ex) {
            log.error("Failed to set error status for node: {}", nodeId, ex);
        }
    }

    /**
     * 发布审批完成事件
     */
    private void publishApprovalCompletedEvent(DelegateExecution execution, String nodeId, ApprovalOutputs outputs) {
        try {
            String processInstanceId = execution.getProcessInstanceId();
            
            // 查询工作流实例信息
            var workflowInstance = workflowInstanceRepository.findByProcessInstanceId(processInstanceId).orElse(null);
            if (workflowInstance == null) {
                log.warn("工作流实例不存在，无法发布审批完成事件: processInstanceId={}", processInstanceId);
                return;
            }

            // 查询工作流定义获取分类信息
            String workflowCategoryCode = null;
            if (workflowInstance.getWorkflowDefinitionId() != null) {
                var definition = workflowDefinitionRepository.findById(workflowInstance.getWorkflowDefinitionId()).orElse(null);
                if (definition != null && definition.getCategoryId() != null) {
                    var category = workflowCategoryRepository.findById(definition.getCategoryId()).orElse(null);
                    if (category != null) {
                        workflowCategoryCode = category.getCode();
                    }
                }
            }

            ApprovalCompletedEvent event = ApprovalCompletedEvent.builder()
                    .processInstanceId(processInstanceId)
                    .workflowInstanceId(workflowInstance.getId())
                    .nodeId(nodeId)
                    .nodeName(execution.getCurrentFlowElement() != null ? execution.getCurrentFlowElement().getName() : nodeId)
                    .result(outputs.getApprovalResult())
                    .approvalTime(outputs.getApprovalTime())
                    .approver(outputs.getApprover())
                    .comment(outputs.getApprovalComment())
                    .workflowCategoryCode(workflowCategoryCode)
                    .businessKey((String) execution.getVariable("businessKey"))
                    .build();

            eventPublisher.publishEvent(event);
            log.debug("发布审批完成事件: nodeId={}, result={}", nodeId, outputs.getApprovalResult());

        } catch (Exception e) {
            log.error("发布审批完成事件失败: nodeId={}", nodeId, e);
            // 不影响主流程，只记录错误
        }
    }


    /**
     * 构建 ApprovalOutputs（弃用，保留以防万一）
     * 自动装配所有上下文信息
     * @deprecated 使用 enrichApprovalOutputs 代替
     */
    @Deprecated
    private ApprovalOutputs buildApprovalOutputs(DelegateExecution execution, String nodeId, Map<String, Object> approvalData) {
        ApprovalOutputs outputs = new ApprovalOutputs();

        // 1. 设置审批结果（从 approvalData 读取）
        String approvalResultStr = (String) approvalData.get("approvalResult");
        try {
            outputs.setApprovalResult(ApprovalResultEnum.valueOf(approvalResultStr));
        } catch (IllegalArgumentException e) {
            log.warn("Invalid approval result: {}, defaulting to REJECTED", approvalResultStr);
            outputs.setApprovalResult(ApprovalResultEnum.REJECTED);
        }

        // 2. 设置审批意见（从 approvalData 读取）
        String comment = (String) approvalData.get("approvalComment");
        outputs.setApprovalComment(comment);

        // 3. 设置审批人（从 approvalData 读取）
        String approver = (String) approvalData.get("approver");
        outputs.setApprover(approver);

        // 4. ⚙️ 自动装配：审批人ID（如果有）
        Object approverUserIdObj = approvalData.get("approverUserId");
        if (approverUserIdObj != null) {
            outputs.setApproverUserId(Long.valueOf(approverUserIdObj.toString()));
        }

        // 5. 设置审批时间（从 approvalData 读取）
        Object approvalTimeObj = approvalData.get("approvalTime");
        if (approvalTimeObj instanceof LocalDateTime) {
            outputs.setApprovalTime((LocalDateTime) approvalTimeObj);
        } else if (approvalTimeObj != null) {
            // 尝试从其他格式转换
            outputs.setApprovalTime(LocalDateTime.now());
        }

        // 6. ⚙️ 自动装配：审批用时（从任务历史计算）
        Long duration = calculateApprovalDuration(execution, nodeId);
        outputs.setApprovalDuration(duration);

        // 7. ⚙️ 自动装配：所有审批人列表（会签/或签场景）
        List<ApprovalOutputs.ApproverInfo> allApprovers = getAllApprovers(execution, nodeId);
        if (allApprovers != null && !allApprovers.isEmpty()) {
            outputs.setAllApprovers(allApprovers);
        }

        // 8. ⚙️ 自动装配：节点执行状态
        outputs.setStatus(NodeExecutionStatusEnum.SUCCESS);

        return outputs;
    }

    /**
     * 计算审批用时（秒）
     */
    private Long calculateApprovalDuration(DelegateExecution execution, String nodeId) {
        try {
            // 查询任务历史
            List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(execution.getProcessInstanceId())
                .taskDefinitionKey(nodeId)
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .list();

            if (!tasks.isEmpty()) {
                HistoricTaskInstance task = tasks.get(0);
                if (task.getCreateTime() != null && task.getEndTime() != null) {
                    long durationMillis = task.getEndTime().getTime() - task.getCreateTime().getTime();
                    return durationMillis / 1000; // 转换为秒
                }
            }
        } catch (Exception e) {
            log.warn("Failed to calculate approval duration", e);
        }

        return null;
    }

    /**
     * 获取所有审批人列表（会签/或签场景）
     */
    private List<ApprovalOutputs.ApproverInfo> getAllApprovers(DelegateExecution execution, String nodeId) {
        try {
            // 查询该节点的所有历史任务
            List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(execution.getProcessInstanceId())
                .taskDefinitionKey(nodeId)
                .finished()
                .list();

            if (tasks.size() > 1) {
                // 多个任务说明是会签/或签场景
                List<ApprovalOutputs.ApproverInfo> approvers = new ArrayList<>();
                for (HistoricTaskInstance task : tasks) {
                    ApprovalOutputs.ApproverInfo info = new ApprovalOutputs.ApproverInfo();
                    info.setUserName(task.getAssignee());

                    // 从任务变量中获取审批结果和意见
                    Map<String, Object> taskVariables = task.getTaskLocalVariables();
                    if (taskVariables != null) {
                        info.setResult((String) taskVariables.get("taskApprovalResult"));
                        info.setComment((String) taskVariables.get("taskApprovalComment"));
                    }

                    if (task.getEndTime() != null) {
                        info.setTime(convertToLocalDateTime(task.getEndTime()));
                    }

                    approvers.add(info);
                }
                return approvers;
            }
        } catch (Exception e) {
            log.warn("Failed to get all approvers", e);
        }

        return null;
    }

    /**
     * Date 转 LocalDateTime
     */
    private LocalDateTime convertToLocalDateTime(Date date) {
        if (date == null) return null;
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

}

