package org.ambraproject.rhino.view.journal;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import org.ambraproject.rhino.model.Article;
import org.ambraproject.rhino.model.ArticleIngestion;
import org.ambraproject.rhino.model.ArticleItem;
import org.ambraproject.rhino.model.ArticleRevision;
import org.ambraproject.rhino.model.Issue;
import org.ambraproject.rhino.model.Journal;
import org.ambraproject.rhino.model.Volume;
import org.ambraproject.rhino.service.ArticleCrudService;
import org.ambraproject.rhino.service.IssueCrudService;
import org.ambraproject.rhino.view.JsonOutputView;
import org.ambraproject.rhino.view.article.ArticleRevisionView;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

public class IssueOutputView implements JsonOutputView {

  public static class Factory {
    @Autowired
    private ArticleCrudService articleCrudService;
    @Autowired
    private IssueCrudService issueCrudService;
    @Autowired
    private ArticleRevisionView.Factory articleRevisionViewFactory;

    public List<ArticleRevisionView> getIssueArticlesView(Issue issue) {
      List<Article> articles = issue.getArticles();
      if (articles == null) return ImmutableList.of();
      return articles.stream()
          .map(articleRevisionViewFactory::getLatestRevisionView)
          .collect(Collectors.toList());
    }

    public IssueOutputView getView(Issue issue) {
      return getView(issue, issueCrudService.getParentVolume(issue));
    }

    public IssueOutputView getView(Issue issue, Volume parentVolume) {
      return new IssueOutputView(issue, parentVolume, this);
    }

    public Optional<IssueOutputView> getCurrentIssueViewFor(Journal journal) {
      return Optional.ofNullable(journal.getCurrentIssue()).map(this::getView);
    }
  }

  private final Issue issue;
  private final Volume parentVolume;
  private final IssueOutputView.Factory factory;

  private IssueOutputView(Issue issue, Volume parentVolume, Factory factory) {
    this.issue = Objects.requireNonNull(issue);
    this.parentVolume = Objects.requireNonNull(parentVolume);
    this.factory = Objects.requireNonNull(factory);
  }

  @Override
  public JsonElement serialize(JsonSerializationContext context) {
    JsonObject serialized = new JsonObject();
    serialized.addProperty("doi", issue.getDoi());
    serialized.addProperty("displayName", issue.getDisplayName());
    serialized.add("parentVolume", context.serialize(VolumeOutputView.getView(parentVolume)));

    JsonElement imageArticle = serialized.get("imageArticle");
    if (imageArticle != null) {
      imageArticle.getAsJsonObject().addProperty("figureImageDoi", getIssueImageFigureDoi());
    }

    return serialized;
  }

  private static final ImmutableSet<String> FIGURE_IMAGE_TYPES = ImmutableSet.of("figure", "table");

  private String getIssueImageFigureDoi() {
    Article imageArticle = issue.getImageArticle();
    ArticleRevision latestArticleRevision = factory.articleCrudService.getLatestRevision(imageArticle).orElseThrow(
        () -> new RuntimeException("Image article has no published revisions. " + imageArticle.getDoi()));
    ArticleIngestion ingestion = latestArticleRevision.getIngestion();
    Collection<ArticleItem> allArticleItems = factory.articleCrudService.getAllArticleItems(ingestion);
    List<ArticleItem> figureImageItems = allArticleItems.stream()
        .filter(item -> FIGURE_IMAGE_TYPES.contains(item.getItemType())).collect(Collectors.toList());
    if (figureImageItems.size() != 1) {
      throw new RuntimeException("Image article does not contain exactly one image file. " + imageArticle.getDoi());
    }
    return figureImageItems.get(0).getDoi();
  }

}
@@ -2790,27 +2790,23 @@
 );%0A%0A    
-JsonElement
+Article
  imageAr
@@ -2817,25 +2817,18 @@
 e = 
-serialized
+issue
 .get
-(%22i
+I
 mage
@@ -2834,17 +2834,17 @@
 eArticle
-%22
+(
 );%0A    i
@@ -2876,17 +2876,38 @@
 %7B%0A      
-i
+JsonObject serializedI
 mageArti
@@ -2913,14 +2913,15 @@
 icle
-.getAs
+ = new 
 Json
@@ -2932,63 +2932,314 @@
 ct()
-.addProperty(%22figureImageDoi%22, getIssueImageFigureDoi()
+;%0A      String figureImageDoi = getIssueImageFigureDoi(factory.articleCrudService, imageArticle);%0A%0A      serializedImageArticle.addProperty(%22doi%22, imageArticle.getDoi());%0A      serializedImageArticle.addProperty(%22figureImageDoi%22, figureImageDoi);%0A      serialized.add(%22imageArticle%22, serializedImageArticle
 );%0A 
@@ -3384,16 +3384,23 @@
 private 
+static 
 String g
@@ -3425,49 +3425,56 @@
 Doi(
-) %7B%0A    Article imageArticle = issue.getI
+ArticleCrudService articleCrudService, Article i
 mage
@@ -3476,27 +3476,27 @@
 imageArticle
-();
+) %7B
 %0A    Article
@@ -3528,24 +3528,16 @@
 ision = 
-factory.
 articleC
@@ -3816,24 +3816,16 @@
 Items = 
-factory.
 articleC

Debug IssueOutputView's imageArticle field