package com.knecon.fforesight.service.layoutparser.processor.docstrum;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.knecon.fforesight.service.layoutparser.processor.docstrum.model.Character;
import com.knecon.fforesight.service.layoutparser.processor.docstrum.model.Line;
import com.knecon.fforesight.service.layoutparser.processor.docstrum.model.Zone;
import com.knecon.fforesight.service.layoutparser.processor.docstrum.service.LineBuilderService;
import com.knecon.fforesight.service.layoutparser.processor.docstrum.service.NearestNeighbourService;
import com.knecon.fforesight.service.layoutparser.processor.docstrum.service.ReadingOrderService;
import com.knecon.fforesight.service.layoutparser.processor.docstrum.service.SpacingService;
import com.knecon.fforesight.service.layoutparser.processor.docstrum.service.ZoneBuilderService;
import com.knecon.fforesight.service.layoutparser.processor.model.table.CleanRulings;
import com.knecon.fforesight.service.layoutparser.processor.model.text.RedTextPosition;
import com.knecon.fforesight.service.layoutparser.processor.model.text.TextDirection;
import com.knecon.fforesight.service.layoutparser.processor.model.text.TextPositionSequence;
import com.knecon.fforesight.service.layoutparser.processor.visualization.LayoutparsingVisualizations;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class DocstrumSegmentationService {

    private final NearestNeighbourService nearestNeighbourService;
    private final SpacingService spacingService;
    private final LineBuilderService lineBuilderService;
    private final ZoneBuilderService zoneBuilderService;
    private final ReadingOrderService readingOrderService;


    public List<Zone> segmentPage(List<TextPositionSequence> textPositions, boolean xyOrder, CleanRulings usedRulings, LayoutparsingVisualizations visualizations) {

        List<Zone> zones = new ArrayList<>();
        zones.addAll(computeZones(textPositions, usedRulings, visualizations, TextDirection.ZERO));
        zones.addAll(computeZones(textPositions, usedRulings, visualizations, TextDirection.QUARTER_CIRCLE));
        zones.addAll(computeZones(textPositions, usedRulings, visualizations, TextDirection.HALF_CIRCLE));
        zones.addAll(computeZones(textPositions, usedRulings, visualizations, TextDirection.THREE_QUARTER_CIRCLE));

        return readingOrderService.resolve(zones, xyOrder);
    }


    private List<Zone> computeZones(List<TextPositionSequence> textPositions, CleanRulings rulings, LayoutparsingVisualizations visualizations, TextDirection direction) {

        List<RedTextPosition> positions = textPositions.stream()
                .filter(t -> t.getDir() == direction)
                .map(TextPositionSequence::getTextPositions)
                .flatMap(List::stream)
                .toList();

        List<Character> characters = positions.stream()
                .map(Character::new)
                .collect(Collectors.toList());

        nearestNeighbourService.findNearestNeighbors(characters);

        double characterSpacing = spacingService.computeCharacterSpacing(characters);
        double lineSpacing = Math.min(spacingService.computeLineSpacing(characters), 20);

        List<Line> lines = lineBuilderService.buildLines(characters, characterSpacing, lineSpacing, rulings);
        return zoneBuilderService.buildZones(lines, characterSpacing, lineSpacing, rulings);
    }

}
