package org.gcube.application.cms.sdi.engine.bboxes;

import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.gcube.application.cms.serialization.Serialization;
import org.gcube.application.geoportal.common.model.JSONPathWrapper;
import org.gcube.application.geoportal.common.model.document.filesets.sdi.GCubeSDILayer;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;

import java.util.List;

@Slf4j
public class BBOXByCoordinatePaths extends BBOXEvaluator{

    @Data
    @ToString
    public static class CoordinatesPathBean{
        private String x;
        private String y;
        private String z;
    }



    public BBOXByCoordinatePaths() {
        super("COORDINATES_PATH");
    }

    @Override
    public boolean isConfigured(Document profileConfiguration) {
        return profileConfiguration.containsKey("coordinatesPath");
    }

    @Override
    public GCubeSDILayer.BBOX evaluate(Document profileConfiguration, UseCaseDescriptor useCaseDescriptor, JSONPathWrapper documentNavigator) {
        List coordsConfig=profileConfiguration.get("coordinatesPath",List.class);
        GCubeSDILayer.BBOX toSet = null;
        for(Object coordsObj:coordsConfig){
            log.debug("UseCaseDescriptor {} : Evaluating coords {} ", useCaseDescriptor.getId(),coordsObj);
            CoordinatesPathBean bean = Serialization.convert(coordsObj,CoordinatesPathBean.class);
            
            // x
            if(bean.getX()!=null)
                // for found
                //TODO MANAGE integers vs double
                for(Object o : documentNavigator.getByPath(bean.getX(),Object.class)) {
                    try{
                        Double x=Double.parseDouble(o.toString());
                        if(toSet == null) toSet = new GCubeSDILayer.BBOX();
                        if (toSet.getMinX()==null || x< toSet.getMinX()) toSet.setMinX(x);
                        if (toSet.getMaxX()==null || x> toSet.getMaxX()) toSet.setMaxX(x);
                    }catch(Throwable t){
                        log.warn("Unable to parse X (Matched value {} from path {}",o,bean.getX(),t);
                    }
                }
            // y
            if(bean.getY()!=null)
                // for found 
                for(Object o : documentNavigator.getByPath(bean.getY(),Object.class)) {
                    try{
                        Double y=Double.parseDouble(o.toString());
                        if(toSet == null) toSet = new GCubeSDILayer.BBOX();
                        if (toSet.getMinY()==null || y< toSet.getMinY()) toSet.setMinY(y);
                        if (toSet.getMaxY()==null || y> toSet.getMaxY()) toSet.setMaxY(y);
                    }catch(Throwable t){
                        log.warn("Unable to parse Y (Matched value {} from path {}",o,bean.getY(),t);
                    }
                }
            // z
            if(bean.getZ()!=null)
                // for found 
                for(Object o : documentNavigator.getByPath(bean.getZ(),Object.class)) {
                    try{
                        Double z=Double.parseDouble(o.toString());
                        if(toSet == null) toSet = new GCubeSDILayer.BBOX();
                        if (toSet.getMinZ()==null || z< toSet.getMinZ()) toSet.setMinZ(z);
                        if (toSet.getMaxZ()==null || z> toSet.getMaxZ()) toSet.setMaxZ(z);
                    }catch(Throwable t){
                        log.warn("Unable to parse Z (Matched value {} from path {}",o,bean.getZ(),t);
                    }
                }
        }
        return toSet;
    }
}