package com.mgmtp.aash.modules.msaccessimport.internal.document;

import tools.jackson.databind.JsonNode;
import tools.jackson.databind.node.ArrayNode;
import tools.jackson.databind.node.JsonNodeFactory;
import tools.jackson.databind.node.ObjectNode;
import tools.jackson.databind.node.StringNode;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AccessA12Entity {

    private final ObjectNode json;

    public AccessA12Entity() {
        json = new ObjectNode(JsonNodeFactory.instance);
    }

    public void setValue(String fieldPath, String value) {
        String adaptedFieldPath = fieldPath.substring(1);
        String[] split = adaptedFieldPath.split("/");

        ObjectNode currentNode = json;
        for (int i = 0; i < split.length; i++) {
            if (split.length - 1 > i) {
                currentNode = (ObjectNode) createGroup(currentNode, split[i]);
            } else {
                // Adding a Field
                // Works for Strings and for Int and for Enumerations and for Booleans (somehow)
                // Do not add if blank for avoiding empty values in fields which can't handle them
                if (!value.isBlank()) {
                    currentNode.putIfAbsent(split[i], new StringNode(value));
                }
            }
        }
    }

    private JsonNode createGroup(ObjectNode currentNode, String newNode) {
        // Adding a Group
        currentNode.putIfAbsent(newNode, new ObjectNode(JsonNodeFactory.instance));
        return currentNode.get(newNode);
    }

    /**
     * This method merges the given {@link AccessA12Entity} into this one. For doing it, it is necessary in which
     * fieldPath this `other` entity should be merged. For this, you have to give the fieldPath param. Keep in mind,
     * that the fieldPath-Param should the same at root level with this {@link AccessA12Entity}.
     */
    public void merge(AccessA12Entity other, String fieldPath) {
        String fieldPathToWork = removeBeginningSlash(fieldPath);
        String[] split = fieldPathToWork.split("/");

        ObjectNode currentNode = json;
        for (int i = 0; i < split.length; i++) {
            if (split.length - 1 > i) {
                currentNode = (ObjectNode) createGroup(currentNode, split[i]);
            } else {
                currentNode.putIfAbsent(split[i], new ArrayNode(JsonNodeFactory.instance));
            }
        }
        ((ArrayNode) currentNode.get(split[split.length - 1])).add(other.json);
    }

    /**
     * Like {@link #merge(AccessA12Entity, String)} but for a non-repeatable group: the `other` entity is merged
     * into a nested {@link ObjectNode} at the given fieldPath instead of being appended to an {@link ArrayNode}.
     * Used for 1:1 relationships where the related table contributes a single row to a non-repeatable group.
     */
    public void mergeSingle(AccessA12Entity other, String fieldPath) {
        String fieldPathToWork = removeBeginningSlash(fieldPath);
        String[] split = fieldPathToWork.split("/");

        ObjectNode currentNode = json;
        for (String segment : split) {
            currentNode = (ObjectNode) createGroup(currentNode, segment);
        }
        currentNode.setAll(other.json);
    }

    private String removeBeginningSlash(String fieldPath) {
        if (fieldPath.startsWith("/")) {
            return fieldPath.substring(1);
        }

        return fieldPath;
    }

    public String getJsonString() {
        return json.toString();
    }
}
