package org.gcube.application.cms.concessioni.plugins;

import com.vdurmont.semver4j.Semver;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.gcube.application.cms.custom.gna.concessioni.model.ProfiledConcessione;
import org.gcube.application.cms.plugins.LifecycleManager;
import org.gcube.application.cms.plugins.implementations.Default3PhaseManager;
import org.gcube.application.cms.plugins.reports.EventExecutionReport;
import org.gcube.application.cms.plugins.reports.Report;
import org.gcube.application.cms.serialization.Serialization;
import org.gcube.application.geoportal.common.model.JSONPathWrapper;
import org.gcube.application.geoportal.common.model.document.Project;
import org.gcube.application.geoportal.common.model.document.access.Access;
import org.gcube.application.geoportal.common.model.document.access.AccessPolicy;
import org.gcube.application.geoportal.common.model.document.filesets.RegisteredFileSet;
import org.gcube.application.geoportal.common.model.legacy.report.ConstraintCheck;

import java.io.IOException;
import java.util.List;

@Slf4j
/** Overrides 3 Phases lifecycle with override of default values
 *
 */
public class ConcessioniLifeCycleManager extends Default3PhaseManager implements LifecycleManager {


    public ConcessioniLifeCycleManager() {
        DESCRIPTOR.setId("GNA-CONCESSIONI-LC");
        DESCRIPTOR.setDescription("GNA Concessioni. This plugin supports custom lifecycle management for the GNA Concessioni UseCase.");
        DESCRIPTOR.setVersion(new Semver("1.0.0"));
    }

    @Override
    public EventExecutionReport setDefault(EventExecutionReport currentReport) {
        EventExecutionReport report =  super.setDefault(currentReport);
        try{
            report.setResultingDocument(setDefaults(report.getTheRequest().getDocument()).getTheDocument());
        }catch (Throwable t){
            log.error("Unable to evaluate defaults for concessione "+currentReport.getTheRequest().getDocument().getId(),t);
            log.debug("Object was {} ",report.getTheRequest().getDocument());
            report.setStatus(Report.Status.ERROR );
            report.getMessages().add("Unable to evaluate defaults : "+t.getMessage());
        }
        return report;
    }


    // STATIC ROUTINES

    static final Project setDefaults(Project document) throws IOException {
        log.info("Concessione ID {}, setting defaults..",document.getId());
        log.debug("Full concessione is {}",document);
        ProfiledConcessione c=Serialization.convert(document,ProfiledConcessione.class);
       Document doc=c.getTheDocument();
        doc.putIfAbsent(ProfiledConcessione.SOGGETTO,new String[]{"Research Excavation","Archaeology"});

        doc.putIfAbsent(ProfiledConcessione.DESCRIZIONE_CONTENUTO,"Relazione di fine scavo e relativo abstract; selezione di immagini rappresentative;"
                + " posizionamento topografico dell'area indagata, pianta di fine scavo.");

        // Super Section
        // TODO read from UCD
        c.getInfo().getAccess().setLicense(
                ConstraintCheck.defaultFor(c.getInfo().getAccess().getLicense(), "CC0-1.0").evaluate());



        //RELAZIONE
        Document rel = doc.containsKey(ProfiledConcessione.RELAZIONE_SCAVO)?
                Serialization.convert(doc.get(ProfiledConcessione.RELAZIONE_SCAVO), Document.class):new Document();
        log.debug("Concessione {}, managing relazione {}",document.getId(),rel);
        rel.putIfAbsent(ProfiledConcessione.Sections.TITOLO,doc.getString(ProfiledConcessione.NOME)+" relazione di scavo");
        rel.putIfAbsent(ProfiledConcessione.SOGGETTO,doc.get(ProfiledConcessione.SOGGETTO));
        rel.putIfAbsent(RegisteredFileSet.CREATION_INFO,c.getInfo().getCreationInfo());
        rel.putIfAbsent(RegisteredFileSet.ACCESS,c.getInfo().getAccess());
        Access relAccess=Serialization.convert(rel.get(RegisteredFileSet.ACCESS),Access.class);
        relAccess.setLicense(ConstraintCheck.defaultFor(relAccess.getLicense(),"CC-BY-4.0").evaluate());
        relAccess.setPolicy(ConstraintCheck.defaultFor(relAccess.getPolicy(), AccessPolicy.OPEN).evaluate());
        rel.put(RegisteredFileSet.ACCESS,relAccess);
        doc.put(ProfiledConcessione.RELAZIONE_SCAVO,rel);


        //ABSTRACT Relazione
        Document abs=doc.containsKey(ProfiledConcessione.ABSTRACT_RELAZIONE)?
                Serialization.convert(doc.get(ProfiledConcessione.ABSTRACT_RELAZIONE), Document.class):new Document();
        log.debug("Concessione {}, managing abstract relazione {}",document.getId(),abs);
        abs.putIfAbsent(ProfiledConcessione.Sections.TITOLO,doc.getString(ProfiledConcessione.NOME)+" abstract relazione di scavo");
        abs.putIfAbsent(RegisteredFileSet.CREATION_INFO,c.getInfo().getCreationInfo());
        abs.putIfAbsent(RegisteredFileSet.ACCESS,c.getInfo().getAccess());
        Access absAccess=Serialization.convert(abs.get(RegisteredFileSet.ACCESS),Access.class);
        absAccess.setLicense(ConstraintCheck.defaultFor(absAccess.getLicense(),"CC-BY-4.0").evaluate());
        absAccess.setPolicy(ConstraintCheck.defaultFor(absAccess.getPolicy(), AccessPolicy.OPEN).evaluate());
        abs.put(RegisteredFileSet.ACCESS,absAccess);
        doc.put(ProfiledConcessione.ABSTRACT_RELAZIONE,abs);


        //Posizionamento scavo
        if(doc.containsKey(ProfiledConcessione.POSIZIONAMENTO_SCAVO)){
            Document pos = Serialization.convert(doc.get(ProfiledConcessione.POSIZIONAMENTO_SCAVO), Document.class);
            log.debug("Concessione {}, managing posizionamento scavo {}",document.getId(),pos);
            pos.putIfAbsent(ProfiledConcessione.Sections.TITOLO,doc.getString(ProfiledConcessione.NOME)+" posizionamento scavo");
            pos.putIfAbsent(ProfiledConcessione.Sections.ABSTRACT,"Posizionamento topografico georeferenziato dell’area interessata dalle indagini");
            pos.putIfAbsent(ProfiledConcessione.Layers.TOPIC,"Society");
            pos.putIfAbsent(ProfiledConcessione.Layers.SUB_TOPIC,"Archeology");

            pos.putIfAbsent(ProfiledConcessione.PAROLE_CHIAVE_LIBERE,doc.get(ProfiledConcessione.PAROLE_CHIAVE_LIBERE));
            pos.putIfAbsent(ProfiledConcessione.PAREOLE_CHIAVE_ICCD,doc.get(ProfiledConcessione.PAREOLE_CHIAVE_ICCD));

            // BBOX in registered filesets

            pos.put(ProfiledConcessione.RESPONSABILE,doc.get(ProfiledConcessione.RESPONSABILE));

            pos.putIfAbsent(RegisteredFileSet.CREATION_INFO,c.getInfo().getCreationInfo());
            pos.putIfAbsent(RegisteredFileSet.ACCESS,c.getInfo().getAccess());
            Access posAccess=Serialization.convert(rel.get(RegisteredFileSet.ACCESS),Access.class);
            posAccess.setLicense(ConstraintCheck.defaultFor(posAccess.getLicense(),"CC-BY-4.0").evaluate());
            posAccess.setPolicy(ConstraintCheck.defaultFor(posAccess.getPolicy(), AccessPolicy.OPEN).evaluate());
            pos.put(RegisteredFileSet.ACCESS,posAccess);
            doc.put(ProfiledConcessione.POSIZIONAMENTO_SCAVO,pos);
        }

        //IMMAGINI RAPPRESENTATIVE

        JSONPathWrapper wrapper=new JSONPathWrapper(Serialization.write(doc));
        if(doc.containsKey(ProfiledConcessione.IMMAGINI_RAPPRESENTATIVE)) {
            List imgs=wrapper.getByPath("$." + ProfiledConcessione.IMMAGINI_RAPPRESENTATIVE, List.class).get(0);
            log.debug("Concessione {}, found imgs {}",document.getId(),imgs.size());
            for (int i = 0; i <imgs.size() ; i++) {
                Document imgDoc=Serialization.asDocument(imgs.get(i));
                imgDoc.putIfAbsent(ProfiledConcessione.SOGGETTO,doc.get(ProfiledConcessione.SOGGETTO));
                imgDoc.putIfAbsent(RegisteredFileSet.CREATION_INFO,c.getInfo().getCreationInfo());
                imgDoc.putIfAbsent(RegisteredFileSet.ACCESS,c.getInfo().getAccess());
                Access imgAccess=Serialization.convert(imgDoc.get(RegisteredFileSet.ACCESS),Access.class);
                imgAccess.setLicense(ConstraintCheck.defaultFor(imgAccess.getLicense(),"CC-BY-4.0").evaluate());
                imgAccess.setPolicy(ConstraintCheck.defaultFor(imgAccess.getPolicy(), AccessPolicy.OPEN).evaluate());
                imgDoc.put(RegisteredFileSet.ACCESS,imgAccess);
                wrapper.setElement("$."+ProfiledConcessione.IMMAGINI_RAPPRESENTATIVE+"["+i+"]",imgDoc);
            }
        }

        // Layers
        if(doc.containsKey(ProfiledConcessione.PIANTE_FINE_SCAVO)) {
            List piante=wrapper.getByPath("$." + ProfiledConcessione.PIANTE_FINE_SCAVO, List.class).get(0);
            log.debug("Concessione {}, found piante {}",document.getId(),piante.size());
            for (int i = 0; i <piante.size() ; i++) {
                Document piantaDoc=Serialization.asDocument(piante.get(i));
                log.debug("Concessione {}, managing pianta {}",document.getId(),piantaDoc);
                piantaDoc.putIfAbsent(ProfiledConcessione.Sections.TITOLO,doc.getString(ProfiledConcessione.NOME)+" pianta fine scavo");
                piantaDoc.putIfAbsent(ProfiledConcessione.Sections.ABSTRACT,"Planimetria georeferenziata dell'area indagata al termine delle attività");
                piantaDoc.putIfAbsent(ProfiledConcessione.Layers.TOPIC,"Society");
                piantaDoc.putIfAbsent(ProfiledConcessione.Layers.SUB_TOPIC,"Archeology");

                piantaDoc.putIfAbsent(ProfiledConcessione.PAROLE_CHIAVE_LIBERE,doc.get(ProfiledConcessione.PAROLE_CHIAVE_LIBERE));
                piantaDoc.putIfAbsent(ProfiledConcessione.PAREOLE_CHIAVE_ICCD,doc.get(ProfiledConcessione.PAREOLE_CHIAVE_ICCD));

                // BBOX in registered filesets

                piantaDoc.put(ProfiledConcessione.RESPONSABILE,doc.get(ProfiledConcessione.RESPONSABILE));

                piantaDoc.putIfAbsent(RegisteredFileSet.CREATION_INFO,c.getInfo().getCreationInfo());
                piantaDoc.putIfAbsent(RegisteredFileSet.ACCESS,c.getInfo().getAccess());
                Access posAccess=Serialization.convert(rel.get(RegisteredFileSet.ACCESS),Access.class);
                posAccess.setLicense(ConstraintCheck.defaultFor(posAccess.getLicense(),"CC-BY-4.0").evaluate());
                posAccess.setPolicy(ConstraintCheck.defaultFor(posAccess.getPolicy(), AccessPolicy.OPEN).evaluate());
                piantaDoc.put(RegisteredFileSet.ACCESS,posAccess);
                wrapper.setElement("$."+ProfiledConcessione.PIANTE_FINE_SCAVO+"["+i+"]",piantaDoc);
            }
        }

        c.setTheDocument(Serialization.read(wrapper.getValueCTX().jsonString(),Document.class));
        return c;
    }


}
