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

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.workflow.model.NodeContext;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

/**
 * TaskListener 基类
 * 用于 UserTask 的任务创建阶段，统一处理输入映射解析和任务配置
 * 
 * @param <I> 输入映射类型 (InputMapping)
 * @param <O> 输出类型 (Outputs) - 用于类型标识
 *
 * @author qqchen
 * @since 2025-10-23
 */
@Slf4j
public abstract class BaseTaskListener<I, O> implements TaskListener {

    @Autowired
    protected ObjectMapper objectMapper;

    // Flowable 自动注入的字段
    protected Expression nodeId;
    protected Expression configs;
    protected Expression inputMapping;

    private Class<I> inputMappingClass;

    @Override
    public void notify(DelegateTask delegateTask) {
        String currentNodeId = null;
        try {
            // 1. 获取节点ID
            currentNodeId = getFieldValue(nodeId, delegateTask);
            log.info("TaskListener: Creating task for node: {}", currentNodeId);

            // 2. 解析配置和输入映射
            Map<String, Object> configsMap = parseJsonField(configs, delegateTask);
            I inputMappingObj = parseInputMapping(delegateTask);

            // 3. 将节点ID保存到任务局部变量（供 ExecutionListener 使用）
            delegateTask.setVariableLocal("nodeId", currentNodeId);

            // ✅ 4. 初始化 NodeContext（configs + inputMapping）
            NodeContext<I, O> nodeContext = new NodeContext<>();
            nodeContext.setConfigs(configsMap);
            nodeContext.setInputMapping(inputMappingObj);
            delegateTask.setVariable(currentNodeId, nodeContext.toMap(objectMapper));
            log.debug("Initialized NodeContext for: {}", currentNodeId);

            // 5. 执行具体的任务配置逻辑（子类实现）
            configureTask(delegateTask, configsMap, inputMappingObj);

            log.info("Task configuration completed for node: {}", currentNodeId);

        } catch (Exception e) {
            log.error("Failed to configure task for node: {}", currentNodeId, e);
            throw new RuntimeException("Failed to configure task: " + currentNodeId, e);
        }
    }

    /**
     * 配置任务（子类实现）
     * 
     * @param delegateTask  Flowable 任务对象
     * @param configs       节点配置
     * @param inputMapping  输入映射（强类型）
     */
    protected abstract void configureTask(
        DelegateTask delegateTask,
        Map<String, Object> configs,
        I inputMapping
    );

    /**
     * 解析输入映射
     */
    @SuppressWarnings("unchecked")
    protected I parseInputMapping(DelegateTask task) {
        try {
            String inputMappingJson = getFieldValue(inputMapping, task);
            Class<I> inputClass = getInputMappingClass();
            
            if (inputMappingJson == null || inputMappingJson.isEmpty()) {
                return inputClass.getDeclaredConstructor().newInstance();
            }

            return objectMapper.readValue(inputMappingJson, inputClass);
            
        } catch (Exception e) {
            log.error("Failed to parse input mapping", e);
            throw new RuntimeException("Failed to parse input mapping", e);
        }
    }

    /**
     * 通过反射获取 InputMapping 的类型
     */
    @SuppressWarnings("unchecked")
    protected Class<I> getInputMappingClass() {
        if (inputMappingClass == null) {
            Type genericSuperclass = getClass().getGenericSuperclass();
            if (genericSuperclass instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
                inputMappingClass = (Class<I>) parameterizedType.getActualTypeArguments()[0];
            }
        }
        return inputMappingClass;
    }

    protected String getFieldValue(Expression expression, DelegateTask task) {
        if (expression == null) return null;
        Object value = expression.getValue(task);
        return value != null ? value.toString() : null;
    }

    protected Map<String, Object> parseJsonField(Expression expression, DelegateTask task) {
        String jsonStr = getFieldValue(expression, task);
        if (jsonStr == null || jsonStr.isEmpty()) {
            return new HashMap<>();
        }
        try {
            return objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {});
        } catch (Exception e) {
            log.error("Failed to parse JSON field: {}", jsonStr, e);
            return new HashMap<>();
        }
    }
}

