package ru.mcs.genealogy.service;

import org.springframework.stereotype.Service;
import ru.mcs.genealogy.dto.TreeNode;
import ru.mcs.genealogy.entity.Person;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

@Service
public class GraphvizTreeService {

    public String generateDOT(Person person) {
        List<TreeNode> treeNodes = buildFullTree(person);
        return buildDOTString(treeNodes);
    }

    private String buildDOTString(List<TreeNode> treeNodes) {
        StringBuilder dot = new StringBuilder();
        dot.append("digraph familyTree {\n");
        dot.append("    rankdir=TB;\n");
        dot.append("    node [shape=box, style=filled, fillcolor=lightblue];\n\n");
//        dot.append("    edge [dir=back];\n\n");

        // Добавляем все узлы
        for (TreeNode node : treeNodes) {
            Person person = node.getPerson();
            dot.append(String.format("    %d [label=\"%s\"];\n",
                    person.getId(),
                    escapeString(person.getFullName())));
        }

        dot.append("\n");

        // Добавляем связи
        for (TreeNode node : treeNodes) {
            Person person = node.getPerson();
            if (person.getFather() != null) {
                dot.append(String.format("    %d -> %d [label=\"отец\"];\n",
                        person.getFather().getId(),
                        person.getId()));
            }
            if (person.getMother() != null) {
                dot.append(String.format("    %d -> %d [label=\"мать\"];\n",
                        person.getMother().getId(),
                        person.getId()));
            }
        }

        dot.append("}\n");
        return dot.toString();
    }

    private String escapeString(String input) {
        return input.replace("\"", "\\\"")
                .replace("\n", "\\n")
                .replace("\r", "\\r");
    }

    public List<TreeNode> buildFullTree(Person person) {
        List<TreeNode> tree = new ArrayList<>();

        if (person != null) {
            // Добавляем предков (отрицательные уровни)
            addAncestors(person, -1, tree);

            // Добавляем выбранного человека (уровень 0)
            tree.add(new TreeNode(person, 0, !person.getAllChildren().isEmpty()));

            // Добавляем потомков (положительные уровни)
            addDescendants(person, 1, tree);
        }

        // Сортируем по уровням для правильного отображения
        tree.sort(Comparator.comparingInt(TreeNode::getLevel));

        return tree;
    }

    private void addAncestors(Person person, int level, List<TreeNode> tree) {
        if (person == null) return;

        // Добавляем отца
        if (person.getFather() != null) {
            tree.add(0, new TreeNode(person.getFather(), level, !person.getFather().getAllChildren().isEmpty()));
            addAncestors(person.getFather(), level - 1, tree);
        }

        // Добавляем мать
        if (person.getMother() != null) {
            tree.add(0, new TreeNode(person.getMother(), level, !person.getMother().getAllChildren().isEmpty()));
            addAncestors(person.getMother(), level - 1, tree);
        }
    }

    private void addDescendants(Person person, int level, List<TreeNode> tree) {
        if (person == null) return;

        for (Person child : person.getAllChildren()) {
            tree.add(new TreeNode(child, level, !child.getAllChildren().isEmpty()));
            addDescendants(child, level + 1, tree);
        }
    }
}