package com.knecon.fforesight.service.layoutparser.internal.api.data.redaction;

import static com.knecon.fforesight.service.layoutparser.internal.api.data.redaction.DocumentStructureProto.DocumentStructure;

import java.awt.geom.Rectangle2D;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

import com.knecon.fforesight.service.layoutparser.internal.api.data.redaction.EntryDataProto.EntryData;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class DocumentStructureWrapper implements Serializable {

    private final DocumentStructure documentStructure;


    @Schema(description = "Object containing the extra field names, a table has in its properties field.")
    public static class TableProperties implements Serializable {

        public static final String NUMBER_OF_ROWS = "numberOfRows";
        public static final String NUMBER_OF_COLS = "numberOfCols";

    }

    @Schema(description = "Object containing the extra field names, an Image has in its properties field.")
    public static class ImageProperties implements Serializable {

        public static final String TRANSPARENT = "transparent";
        public static final String IMAGE_TYPE = "imageType";
        public static final String POSITION = "position";
        public static final String ID = "id";

        public static final String REPRESENTATION_HASH = "representationHash";

    }

    @Schema(description = "Object containing the extra field names, a table cell has in its properties field.")
    public static class TableCellProperties implements Serializable {

        public static final String B_BOX = "bBox";
        public static final String ROW = "row";
        public static final String COL = "col";
        public static final String HEADER = "header";

    }

    @Schema(description = "Object containing the extra field names, a duplicate paragraph has in its properties field.")
    public static class DuplicateParagraphProperties implements Serializable {

        public static final String UNSORTED_TEXTBLOCK_ID = "utbid";

    }

    public static final String RECTANGLE_DELIMITER = ";";


    public static Rectangle2D parseRectangle2D(String bBox) {

        List<Float> floats = Arrays.stream(bBox.split(RECTANGLE_DELIMITER))
                .map(Float::parseFloat)
                .toList();
        return new Rectangle2D.Float(floats.get(0), floats.get(1), floats.get(2), floats.get(3));
    }


    public static double[] parseRepresentationVector(String representationHash) {

        String[] stringArray = representationHash.split("[,\\s]+");
        double[] doubleArray = new double[stringArray.length];
        for (int i = 0; i < stringArray.length; i++) {
            doubleArray[i] = Double.parseDouble(stringArray[i]);
        }

        return doubleArray;
    }


    public EntryData get(List<Integer> tocId) {

        if (tocId.isEmpty()) {
            return documentStructure.getRoot();
        }
        EntryData entry = documentStructure.getRoot().getChildrenList()
                .get(tocId.get(0));
        for (int id : tocId.subList(1, tocId.size())) {
            entry = entry.getChildrenList()
                    .get(id);
        }
        return entry;
    }


    public Stream<EntryData> streamAllEntries() {

        return Stream.concat(Stream.of(documentStructure.getRoot()),
                             documentStructure.getRoot().getChildrenList()
                                     .stream())
                .flatMap(DocumentStructureWrapper::flatten);
    }


    public String toString() {

        return String.join("\n",
                           streamAllEntries().map(EntryData::toString)
                                   .toList());
    }


    private static Stream<EntryData> flatten(EntryData entry) {

        return Stream.concat(Stream.of(entry),
                             entry.getChildrenList()
                                     .stream()
                                     .flatMap(DocumentStructureWrapper::flatten));
    }

}
