package ru.yandex.webmaster3.storage.sitestructure;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.yandex.webmaster3.core.sitestructure.DoubleSourcedSiteStructure;
import ru.yandex.webmaster3.core.sitestructure.NewSiteStructure;
import ru.yandex.webmaster3.core.sitestructure.NewSiteStructureNode;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author aherman
 */
public class StructureNameUtil {
    private static final Logger log = LoggerFactory.getLogger(StructureNameUtil.class);

    public static long getSiteNodeId(String path) {
        if ("/".equals(path)) {
            return NewSiteStructure.ROOT_NODE_ID;
        }
        // Bug in previous node id computer
        return ("/" + path).hashCode();
    }

    public static long getUserNodeId(String path) {
        return ("user::" + path).hashCode();
    }

    public static <T> String getFullPath(T node, Map<Long, T> nodesMap,
                                         Function<T, Long> parentId, Function<T, String> name, Function<T, Boolean> isRoot) {
        int tries = 50;
        String path = "";
        T currentNode = node;
        if (currentNode == null) {
            return "";
        }
        while (tries-- > 0) {
            if (currentNode == null || isRoot.apply(currentNode)) {
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
                break;
            }
            path = name.apply(currentNode) + path;
            Long pId = parentId.apply(currentNode);
            if (pId == null) {
                break;
            }
            currentNode = nodesMap.get(pId);
        }

        return path;
    }

    public static DoubleSourcedSiteStructure fixUserNodeIds(DoubleSourcedSiteStructure siteStructure) {
        return new DoubleSourcedSiteStructure(
                fixUserNodeIds(siteStructure.getCurStructure()),
                siteStructure.getCurBaseDate(),
                fixUserNodeIds(siteStructure.getNextBaseStructure()),
                siteStructure.getNextBaseDate()
        );
    }

    public static NewSiteStructure fixUserNodeIds(NewSiteStructure siteStructure) {
        if (siteStructure == null) {
            return null;
        }
        List<NewSiteStructureNode> userNodes = siteStructure.getUserDefinedNodes()
                .stream()
                .map(node -> {
                    long nodeId = getNodeId(Collections.emptyMap(), node, true);
                    return node.withFixedNodeId(nodeId);
                }).collect(Collectors.toList());
        return siteStructure.withFixedUserNodes(userNodes);
    }

    private static long getNodeId(Map<Long, NewSiteStructureNode> nodesMap, NewSiteStructureNode node, boolean userNode) {
        String fullPath = StructureNameUtil.getFullPath(node, nodesMap,
                NewSiteStructureNode::getParentNodeId,
                NewSiteStructureNode::getName,
                NewSiteStructureNode::isRoot);
        return userNode ? StructureNameUtil.getUserNodeId(fullPath) : StructureNameUtil.getSiteNodeId(fullPath);
    }
}
