package uk.ac.ebi.atlas.experimentpage.baseline;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.springframework.ui.Model;
import uk.ac.ebi.atlas.experimentpage.ExperimentPageService;
import uk.ac.ebi.atlas.experimentpage.context.BaselineRequestContext;
import uk.ac.ebi.atlas.model.AssayGroup;
import uk.ac.ebi.atlas.model.OntologyTerm;
import uk.ac.ebi.atlas.model.experiment.baseline.BaselineExperiment;
import uk.ac.ebi.atlas.model.experiment.summary.AssayGroupSummaryBuilder;
import uk.ac.ebi.atlas.resource.AtlasResourceHub;
import uk.ac.ebi.atlas.tracks.TracksUtil;
import uk.ac.ebi.atlas.utils.HeatmapDataToJsonService;
import uk.ac.ebi.atlas.web.ApplicationProperties;
import uk.ac.ebi.atlas.web.BaselineRequestPreferences;
import uk.ac.ebi.atlas.web.GenesNotFoundException;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BaselineExperimentPageService extends ExperimentPageService {

    private final TracksUtil tracksUtil;
    private final BaselineProfilesHeatMapWranglerFactory baselineProfilesHeatMapWranglerFactory;
    private final AnatomogramFactory anatomogramFactory;

    public BaselineExperimentPageService(BaselineProfilesHeatMapWranglerFactory baselineProfilesHeatMapWranglerFactory,
                                         ApplicationProperties applicationProperties,
                                         AtlasResourceHub atlasResourceHub,
                                         TracksUtil tracksUtil,
                                         HeatmapDataToJsonService heatmapDataToJsonService) {
        super(atlasResourceHub, heatmapDataToJsonService, applicationProperties);
        this.anatomogramFactory = new AnatomogramFactory();
        this.baselineProfilesHeatMapWranglerFactory = baselineProfilesHeatMapWranglerFactory;
        this.tracksUtil = tracksUtil;
    }

    public void prepareRequestPreferencesAndHeaderData(BaselineExperiment experiment, BaselineRequestPreferences preferences, Model model,
                                                       HttpServletRequest request) {
        // not sure if I still need atlasHost, old comment:
        // this is currently required for the request requestPreferences filter  drop-down multi-selection box
        model.addAttribute("atlasHost", applicationProperties.buildAtlasHostURL(request));
        model.addAllAttributes(experiment.getAttributes());
        model.addAllAttributes(headerAttributes(experiment));
    }

    public JsonObject populateModelWithHeatmapData(BaselineExperiment experiment, BaselineRequestPreferences preferences,
                                             Model model, HttpServletRequest request, boolean isWidget) {
        JsonObject result = new JsonObject();

        BaselineRequestContext requestContext = new BaselineRequestContext(preferences, experiment);
        List<AssayGroup> dataColumnsToReturn = requestContext.getDataColumnsToReturn();

        /*From here on preferences are immutable, variables not required for request-preferences.jsp*/
        model.addAttribute("geneQuery", preferences.getGeneQuery().toUrlEncodedJson());
        model.addAllAttributes(experiment.getAttributes());

        //model.addAttribute("queryFactorName", experiment.getExperimentalFactors().getFactorDisplayName(preferences.getQueryFactorType()));
        //model.addAttribute("serializedFilterFactors", preferences.getSerializedFilterFactors());

        model.addAttribute("enableEnsemblLauncher", !isWidget&& !requestContext.getDataColumnsToReturn().isEmpty()
                && tracksUtil.hasBaselineTracksPath(experiment.getAccession(),
                requestContext.getDataColumnsToReturn().iterator().next().getId()));

        BaselineProfilesHeatMapWrangler heatMapResults = baselineProfilesHeatMapWranglerFactory.create
                (request, preferences,experiment);

        result.add("columnHeaders",
                constructColumnHeaders(dataColumnsToReturn,requestContext, experiment));

        result.add("columnGroupings",new JsonArray());

        try {
            result.add("profiles", heatMapResults.getJsonProfiles());
            //TODO remove me after old heatmap goes away, the new heatmap handles no data gracefully
            if(heatMapResults.getJsonProfiles().get("rows").getAsJsonArray().size() == 0 ){
                return heatmapDataToJsonService.jsonError("No genes found matching query: '" + preferences.getGeneQuery() + "'");
            }

            result.add("jsonCoexpressions", heatMapResults.getJsonCoexpressions());

            // Optional<JsonObject> geneSets = heatMapResults.getJsonProfilesAsGeneSets();
            result.add("jsonGeneSetProfiles", new JsonArray());
                /* We decided to disable the feature because it has a performance cost and isn't
                very useful..
                TODO remove (or make more useful)
                geneSets.isPresent()
                ? viewModelAsJson(geneSets.get())
                : "null");*/
        } catch (GenesNotFoundException e){
            return heatmapDataToJsonService.jsonError("No genes found matching query: '" + preferences.getGeneQuery() + "'");
        }

        Set<OntologyTerm> ontologyTerms = new HashSet<>();
        for(AssayGroup dataColumnDescriptor: dataColumnsToReturn){
            ontologyTerms.addAll(requestContext.ontologyTermsForColumn(dataColumnDescriptor));
        }

        result.add("anatomogram", anatomogramFactory.get(requestContext.getQueryFactorType(),
                experiment.getSpecies(), ontologyTerms));

        model.addAttribute("isWidget", isWidget);

        for(Map.Entry<String, JsonElement> e: payloadAttributes(experiment, preferences).entrySet()){
            result.add(e.getKey(), e.getValue());
        }
        model.addAttribute("downloadProfilesURL", downloadURL(preferences.getGeneQuery(), request));
        result.add("config", heatmapDataToJsonService.configAsJsonObject(request, model.asMap()));

        return result;
    }

    private JsonArray constructColumnHeaders(List<AssayGroup> dataColumnsToReturn, BaselineRequestContext
            baselineRequestContext,
            BaselineExperiment
            experiment){
        JsonArray result = new JsonArray();

        for(AssayGroup dataColumnDescriptor: dataColumnsToReturn){
            JsonObject o = new JsonObject();
            o.addProperty("assayGroupId", dataColumnDescriptor.getId());
            o.addProperty("factorValue", baselineRequestContext.displayNameForColumn(dataColumnDescriptor));
            o.add("factorValueOntologyTermId",
                    OntologyTerm.jsonForHeaders(baselineRequestContext.ontologyTermsForColumn(dataColumnDescriptor)));
            o.add("assayGroupSummary",
                    new AssayGroupSummaryBuilder()
                    .forAssayGroup(experiment.getDataColumnDescriptor(dataColumnDescriptor.getId()))
                    .withExperimentDesign(experiment.getExperimentDesign())
                    .build().toJson());
            result.add(o);
        }


        return result;}


}
@@ -2668,32 +2668,83 @@
 ment experiment,
+%0A                                                  
  BaselineRequest
@@ -2764,24 +2764,30 @@
 references,%0A
+      
             
@@ -4307,24 +4307,25 @@
 rofiles());%0A
+%0A
             
@@ -4328,334 +4328,129 @@
     
-//TODO remove me after old heatmap goes away, the new heatmap handles no data gracefully%0A            if(heatMapResults.getJsonProfiles().get(%22rows%22).getAsJsonArray().size() == 0 )%7B%0A                return heatmapDataToJsonService.jsonError(%22No genes found matching query: '%22 + preferences.getGeneQuery() + %22'%22);%0A        
+JsonArray jsonCoexpressions = heatMapResults.getJsonCoexpressions();%0A            if (jsonCoexpressions.size() %3E 0) %7B%0A
     
-%7D%0A%0A
     
@@ -4469,21 +4469,17 @@
 lt.add(%22
-jsonC
+c
 oexpress
@@ -4521,25 +4521,24 @@
 essions());%0A
-%0A
             
@@ -4541,443 +4541,9 @@
     
-// Optional%3CJsonObject%3E geneSets = heatMapResults.getJsonProfilesAsGeneSets();%0A            result.add(%22jsonGeneSetProfiles%22, new JsonArray());%0A                /* We decided to disable the feature because it has a performance cost and isn't%0A                very useful..%0A                TODO remove (or make more useful)%0A                geneSets.isPresent()%0A                ? viewModelAsJson(geneSets.get())%0A                : %22null%22);*/
+%7D
 %0A   
@@ -4657,16 +4657,11 @@
 und 
-matching
+for
  que

Remove legacy heatmap fields; rename coexpressions field to just that, “coexpressions”; only add coexpression data if there are any