package com.knecon.fforesight.service.layoutparser.processor.services.classification;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.springframework.stereotype.Service;

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

@Service
public class ListItemClassificationService {

    public static final int LIST_IDENTIFIER_SEARCH_RADIUS = 3;


    public List<ListIdentifier> findConfirmedListIdentifiers(int currentIndex, List<AbstractBlockOnPage> allBlocks) {

        List<ListIdentifier> listIdentifiers = extractListIdentifiers(allBlocks.get(currentIndex));
        if (listIdentifiers.isEmpty()) {
            return Collections.emptyList();
        }
        if (listIdentifiers.size() > 1 && ListIdentifier.isInOrder(listIdentifiers)) {
            return listIdentifiers;
        }

        int start = Math.max(0, currentIndex - LIST_IDENTIFIER_SEARCH_RADIUS);
        int end = Math.min(allBlocks.size(), currentIndex + LIST_IDENTIFIER_SEARCH_RADIUS);

        List<ListIdentifier> identifiersBehind = new ArrayList<>();
        if (start < currentIndex) {
            identifiersBehind.addAll(allBlocks.subList(start, currentIndex)
                                             .stream()
                                             .map(this::extractListIdentifiers)
                                             .flatMap(Collection::stream)
                                             .toList());
        }
        if (!identifiersBehind.isEmpty()) {
            listIdentifiers.add(0, identifiersBehind.get(identifiersBehind.size() - 1));
            if (ListIdentifier.isInOrder(listIdentifiers)) {
                return listIdentifiers;
            }
            listIdentifiers.remove(0);
        }
        List<ListIdentifier> identifiersAhead = new ArrayList<>();
        if (currentIndex + 1 < end) {
            identifiersAhead.addAll(allBlocks.subList(currentIndex + 1, end)
                                            .stream()
                                            .map(this::extractListIdentifiers)
                                            .flatMap(Collection::stream)
                                            .toList());
        }
        if (!identifiersAhead.isEmpty()) {
            listIdentifiers.add(identifiersAhead.get(0));
            if (ListIdentifier.isInOrder(listIdentifiers)) {
                return listIdentifiers;
            }
            listIdentifiers.remove(listIdentifiers.size() - 1);
        }
        return Collections.emptyList();

    }


    private List<ListIdentifier> extractListIdentifiers(AbstractBlockOnPage block) {

        List<ListIdentifier> result = new LinkedList<>();
        if (block.block() instanceof TextPageBlock textBlock) {
            List<Word> sequences = textBlock.getWords();
            for (int i = 0; i < sequences.size(); i++) {

                if (i != 0 && sequences.get(i - 1).getXDirAdj() < sequences.get(i).getXDirAdj()) {
                    // is not the start of a line, continue
                    continue;
                }

                Word sequence = sequences.get(i);
                List<Word> wordsAtStartOfLine = new ArrayList<>(3);
                int end = Math.min(sequences.size(), i + 3);
                for (int j = i; j < end; j++) {
                    if (sequences.get(j).intersectsYDirAdj(sequence, 2)) {
                        wordsAtStartOfLine.add(sequences.get(j));
                    } else {
                        break;
                    }
                }

                ListIdentifier.parse(wordsAtStartOfLine, block.page().getPageNumber()).ifPresent(result::add);
            }
        }
        return result;
    }

}
