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

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.gcube.application.cms.sdi.faults.SDIInteractionException;
import org.gcube.application.cms.sdi.model.CrossReferencedLayer;
import org.gcube.application.geoportal.common.model.configuration.Index;
import org.gcube.application.geoportal.common.model.document.filesets.sdi.GCubeSDILayer;
import org.gcube.application.geoportal.common.model.rest.DatabaseConnection;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;

import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


@Slf4j
public class PostgisIndexer {



    public static final String INDEX_TYPE="GIS-CENTROIDS";


    public static void init() throws ClassNotFoundException {

            Class.forName("org.postgresql.Driver");
            Class.forName("org.postgis.DriverWrapper");

    };

    @NonNull
    SDIManagerWrapper manager;
    @NonNull
    UseCaseDescriptor useCaseDescriptor;

    @NonNull
    DatabaseConnection connectionParameters;

    PostgisDBManagerI dbManager=null;
    PostgisTable table = null;
    GCubeSDILayer indexLayer = null;
    String indexName = null;

    private List<CrossReferencedLayer> crossReferenceableLayers= new ArrayList<>();


    public PostgisIndexer(SDIManagerWrapper manager, UseCaseDescriptor useCaseDescriptor,
                          DatabaseConnection postgisConnection) throws SQLException {
        log.info("POSTGIS Index for {} Connecting to {} ", useCaseDescriptor.getId(),postgisConnection);
        this.connectionParameters=postgisConnection;
        dbManager=new PostgisDBManager(DriverManager.
                getConnection(connectionParameters.getUrl(),
                        connectionParameters.getUser(),
                        connectionParameters.getPwd()));
        this.manager=manager;
        this.useCaseDescriptor = useCaseDescriptor;

    }




    public void initIndex(String indexName, List<PostgisTable.Field> fields, String workspace,String storeName) throws SQLException, SDIInteractionException {
        log.info("Check/init index for {} ", useCaseDescriptor.getId());
        table = new PostgisTable(indexName,fields, PostgisTable.GeometryType.POINT);
        log.trace("Index Postgis Table is {} ",table);
        log.debug("Create if missing..");
        // Check if table exists
        dbManager.create(table);

        log.debug("Checking/ registering index layer in GS ");
        this.indexName = indexName;
        indexLayer = manager.configureCentroidLayer(indexName,workspace,storeName,table,connectionParameters);

        // TODO Additional layers
        // Create layer
        // register cross related layers
    }

    HashMap<String,GCubeSDILayer> crossReferenced = new HashMap<>();


    public Index getIndexConfiguration(){
        Index toReturn = new Index(INDEX_TYPE);
        // SDI Layers
        toReturn.put("layer",indexLayer);
        toReturn.put("indexName",indexName);
        try {
            toReturn.put("records", dbManager.count(table));
        }catch (SQLException e) {
            log.warn("Unable to count records for index " + indexName, e);
        }
        toReturn.put("crossReferencedLayers",crossReferenced);
        return toReturn;
    }


    public void insert(Document toInsertRecord)throws SDIInteractionException {
        log.info("Inserting {} in index {}",toInsertRecord,table.getTablename());
        try {
            PreparedStatement ps = dbManager.prepareInsertStatement(table, false, true);
            table.fillObjectsPreparedStatement(toInsertRecord, ps);
            ps.execute();
        }catch (Throwable t ){
            log.error("Unable to insert {} into {} ",toInsertRecord,table.getTablename(),t);
            throw new SDIInteractionException("Unable to insert record in postgis index "+table.getTablename(),t);
        }
    }

    public void removeByFieldValue(PostgisTable.Field field, String id) throws SDIInteractionException {
        log.info("Deleting {}={} from index {}",field.getName(), id,table.getTablename());
        try {
            dbManager.deleteByFieldValue(table,field,id);
        }catch (Throwable t ){
            log.error("Unable to delete {}={} from index {}",field.getName(), id,table.getTablename(),t);
            throw new SDIInteractionException("Unable to delete record in postgis index "+table.getTablename(),t);
        }
    }


}
