package com.knecon.fforesight.service.layoutparser.processor.model.outline;

import static com.knecon.fforesight.service.layoutparser.processor.model.PageBlockType.getHeadlineNumber;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

import org.springframework.stereotype.Service;

import com.knecon.fforesight.service.layoutparser.processor.model.text.TextPageBlock;

import io.micrometer.observation.annotation.Observed;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class OutlineValidationService {

    @Observed(name = "OutlineValidationService", contextualName = "create-toc")
    public TableOfContents createToC(List<TextPageBlock> headlines) {

        List<TableOfContentItem> mainSections = new ArrayList<>();
        Map<Integer, TableOfContentItem> lastItemsPerDepth = new HashMap<>();
        TableOfContentItem last = null;
        TreeSet<Integer> depths = new TreeSet<>();

        for (TextPageBlock current : headlines) {
            int currentDepth = getHeadlineNumber(current.getClassification());
            Integer parentDepth = depths.floor(currentDepth - 1);

            var tocItem = new TableOfContentItem(current);

            if (parentDepth == null) {
                mainSections.add(tocItem);
                lastItemsPerDepth = new HashMap<>();
                depths = new TreeSet<>();

            } else {
                assert last != null;
                int lastDepth = getHeadlineNumber(last.getHeadline().getClassification());

                if (lastDepth < parentDepth) {
                    parentDepth = lastDepth;
                } else if (lastDepth == currentDepth && last.getParent() != null) {
                    parentDepth = getHeadlineNumber(last.getParent().getHeadline().getClassification());
                }

                TableOfContentItem parent = lastItemsPerDepth.get(parentDepth);
                parent.addChild(tocItem);
            }

            last = tocItem;
            lastItemsPerDepth.put(currentDepth, tocItem);
            depths.add(currentDepth);
        }

        return new TableOfContents(mainSections);
    }

}
