package cn.axzo.workflow.core.engine.cmd;

import cn.axzo.workflow.common.exception.WorkflowEngineException;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.form.api.FormInstance;
import org.flowable.form.api.FormService;
import org.flowable.form.engine.FormEngineConfiguration;
import org.flowable.form.engine.impl.persistence.entity.FormInstanceEntity;
import org.flowable.form.engine.impl.util.CommandContextUtil;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static cn.axzo.workflow.common.code.FormInstanceRespCode.FORM_INSTANCE_DATA_NOT_FOUND;

/**
 * 覆写指定流程最后一次操作的表单中指定 key 的内容
 *
 * @author wangli
 * @since 2025-02-08 10:14
 */
@Slf4j
public class CustomOverrideFormVariablesByLatestInstanceCmd extends AbstractCommand<Void> implements Serializable {
    private static final long serialVersionUID = 1L;
    private final String processInstanceId;
    private final Map<String, Object> formVariables;

    public CustomOverrideFormVariablesByLatestInstanceCmd(String processInstanceId, Map<String, Object> formVariables) {
        this.processInstanceId = processInstanceId;
        this.formVariables = formVariables;
    }

    @Override
    public String paramToJsonString() {
        Map<String, Object> params = new HashMap<>();
        params.put("processInstanceId", processInstanceId);
        params.put("formVariables", formVariables);
        return JSON.toJSONString(params);
    }

    @Override
    public Void executeInternal(CommandContext commandContext) {
        FormEngineConfiguration formEngineConfiguration = CommandContextUtil.getFormEngineConfiguration();
        FormService formService = formEngineConfiguration.getFormService();
        List<FormInstance> formInstances = formService.createFormInstanceQuery().processInstanceId(processInstanceId)
                .orderBySubmittedDate().desc().listPage(0, 1);
        if (CollectionUtils.isEmpty(formInstances)) {
            throw new WorkflowEngineException(FORM_INSTANCE_DATA_NOT_FOUND, processInstanceId);
        }
        FormInstanceEntity formInstance = (FormInstanceEntity) formInstances.get(0);

        ObjectMapper objectMapper = CommandContextUtil.getFormEngineConfiguration().getObjectMapper();

        try {
            JsonNode jsonNode = objectMapper.readTree(formInstance.getFormValueBytes());
            if (Objects.isNull(jsonNode)) {
                return null;
            }
            JsonNode valuesNode = jsonNode.get("values");
            if (Objects.nonNull(valuesNode)) {
                ObjectNode valuesObjectNode = (ObjectNode) valuesNode;

                Iterator<String> fieldIdIterator = valuesNode.fieldNames();
                while (fieldIdIterator.hasNext()) {
                    String fieldId = fieldIdIterator.next();

                    formVariables.forEach((k, v) -> {
                        if (Objects.equals(k, fieldId)) {
                            if (v instanceof Collection) {
                                try {
                                    valuesObjectNode.set(k, new TextNode(objectMapper.writeValueAsString(v)));
                                } catch (JsonProcessingException e) {
                                    throw new RuntimeException(e);
                                }
                            } else {
                                valuesObjectNode.set(k, new TextNode(v.toString()));
                            }
                        }
                    });
                }
            }

            byte[] formValueBytes = objectMapper.writeValueAsBytes(jsonNode);
            log.info("更新后表单内容： {}", new String(formInstance.getFormValueBytes()));
            formInstance.setFormValueBytes(formValueBytes);
            CommandContextUtil.getFormInstanceEntityManager().update(formInstance);
        } catch (Exception e) {
            throw new FlowableException("Error parsing form instance " + formInstance.getId(), e);
        }
        return null;
    }
}
