package com.eactive.eai.adapter.handler;

import java.util.Properties;

import org.apache.commons.lang3.StringUtils;

import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.Logger;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;


public class TemplateCodeConvertAdapterErrorMsgHandler extends TemplateAdapterErrorMsgHandler {

    private static final Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);

    /** PropManager 에서 코드 변환 설정을 조회할 프로퍼티 그룹 이름 */
    static final String PROP_GROUP = "AdapterErrorMessageHandler{CODE_CONVERT}";

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Override
    public Object generateNonStandardErrorResponseMessage(
            String inboundAdapterGroupName,
            String inboundAdapterName,
            Properties callProp,
            Object outboundRequestData,
            EAIMessage resEaiMsg) throws Exception {

    	Object responseMsessage = super.generateNonStandardErrorResponseMessage(
                inboundAdapterGroupName,
                inboundAdapterName,
                callProp,
                outboundRequestData,
                resEaiMsg);

    	logger.debug("generateNonStandardErrorResponseMessage - {}", responseMsessage);

    	if (!(responseMsessage instanceof String)) {
    	    return responseMsessage;
    	}

    	String jsonStr = (String) responseMsessage;
    	if (StringUtils.isBlank(jsonStr)) {
    	    return responseMsessage;
    	}

    	Properties props = PropManager.getInstance().getProperties(PROP_GROUP);
    	if (props == null) {
    	    return responseMsessage;
    	}

    	String fieldsKey = inboundAdapterGroupName + ".convert.fields";
    	String fieldsValue = props.getProperty(fieldsKey);
    	if (StringUtils.isBlank(fieldsValue)) {
    	    return responseMsessage;
    	}

    	JsonNode rootNode = OBJECT_MAPPER.readTree(jsonStr);
    	boolean modified = false;

    	for (String rawField : fieldsValue.split(",")) {
    	    String fieldPath = rawField.trim();
    	    if (StringUtils.isBlank(fieldPath)) continue;

    	    String currentValue = getJsonValue(rootNode, fieldPath);
    	    if (currentValue == null) continue;

    	    // key: inboundAdapterGroupName.{fieldPath}.{현재값}  →  폴백: ...{fieldPath}.default
    	    String mappingKey = inboundAdapterGroupName + "." + fieldPath + "." + currentValue;
    	    String newValue = props.getProperty(mappingKey);
    	    if (newValue == null) {
    	        String defaultKey = inboundAdapterGroupName + "." + fieldPath + ".default";
    	        newValue = props.getProperty(defaultKey);
    	    }
    	    if (newValue == null) continue;

    	    setJsonValue(rootNode, fieldPath, newValue);
    	    modified = true;

    	    if (logger.isDebug()) {
    	        logger.debug("code convert: field={}, {} -> {}", fieldPath, currentValue, newValue);
    	    }
    	}

    	if (modified) {
    	    responseMsessage = OBJECT_MAPPER.writeValueAsString(rootNode);
    	}

    	return responseMsessage;
    }

    /**
     * dot 구분 경로로 JsonNode 에서 값을 꺼낸다.
     * 최종 노드가 값 노드(primitive)가 아니면 null 반환.
     */
    private String getJsonValue(JsonNode node, String fieldPath) {
        JsonNode current = node;
        for (String part : fieldPath.split("\\.", -1)) {
            if (current == null || !current.isObject()) return null;
            current = current.get(part);
        }
        if (current == null || current.isNull() || !current.isValueNode()) return null;
        return current.asText();
    }

    /**
     * dot 구분 경로로 ObjectNode 의 최종 필드 값을 newValue 로 교체한다.
     * 중간 경로가 ObjectNode 가 아니면 무시한다.
     */
    private void setJsonValue(JsonNode rootNode, String fieldPath, String newValue) {
        String[] parts = fieldPath.split("\\.", -1);
        JsonNode current = rootNode;
        for (int i = 0; i < parts.length - 1; i++) {
            if (current == null || !current.isObject()) return;
            current = current.get(parts[i]);
        }
        if (current instanceof ObjectNode) {
            ((ObjectNode) current).put(parts[parts.length - 1], newValue);
        }
    }


}
