package com.jvm_bloggers.core.mailing;

import com.google.common.base.Strings;
import com.jvm_bloggers.core.blogpost_redirect.LinkGenerator;
import com.jvm_bloggers.core.utils.UriUtmComponentsBuilder;
import com.jvm_bloggers.entities.blog.Blog;
import com.jvm_bloggers.entities.blog.BlogType;
import com.jvm_bloggers.entities.blog_post.BlogPost;
import com.jvm_bloggers.entities.metadata.MetadataKeys;
import com.jvm_bloggers.entities.metadata.MetadataRepository;
import com.jvm_bloggers.entities.newsletter_issue.NewsletterIssue;
import io.vavr.collection.List;
import io.vavr.collection.Map;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.stringtemplate.v4.ST;

import java.util.Comparator;

import static com.jvm_bloggers.core.utils.UriUtmComponentsBuilder.DEFAULT_UTM_CAMPAING;
import static com.jvm_bloggers.core.utils.UriUtmComponentsBuilder.DEFAULT_UTM_SOURCE;
import static com.jvm_bloggers.utils.HtmlEmptinessChecker.isEmpty;
import static io.vavr.collection.List.empty;

@Component
@NoArgsConstructor
public class BlogSummaryMailGenerator {

    private static final int DAYS_IN_THE_PAST = 7;
    private static final char TEMPLATE_DELIMITER = '$';
    private static final String UTM_MEDIUM = "newsletter";

    private static final String NEW_LINE = "<br/>";

    private MetadataRepository metadataRepository;
    private LinkGenerator linkGenerator;

    @Autowired
    public BlogSummaryMailGenerator(
        MetadataRepository metadataRepository,
        LinkGenerator linkGenerator
    ) {
        this.metadataRepository = metadataRepository;
        this.linkGenerator = linkGenerator;
    }

    public String prepareMailContent(NewsletterIssue newsletterIssue) {
        String greeting = prepareGreetingSection(newsletterIssue.getIssueNumber());
        String heading = newsletterIssue.getHeading();
        String mainSection = prepareMainSectionWithBlogs(newsletterIssue);
        String varia = newsletterIssue.getVaria();
        String signature = getValueForSection(MetadataKeys.MAILING_SIGNATURE);

        return appendNewLinesIfNotEmpty(greeting, 2)
            + appendNewLinesIfNotEmpty(heading, 2)
            + appendNewLinesIfNotEmpty(mainSection, 2)
            + prepareVariaSection(varia, 2)
            + NEW_LINE + signature;
    }

    private String prepareGreetingSection(Long issueNumber) {
        String templateContent = getValueForSection(MetadataKeys.MAILING_GREETING);
        ST template = new ST(templateContent, TEMPLATE_DELIMITER, TEMPLATE_DELIMITER);
        template.add("currentIssueLink", linkGenerator.generateIssueLink(issueNumber));
        return template.render();
    }

    private String getValueForSection(String key) {
        return metadataRepository.findByName(key).getValue();
    }

    private String appendNewLinesIfNotEmpty(String text, int numberOfNewLines) {
        if (isEmpty(text)) {
            return "";
        } else {
            return text + StringUtils.repeat(NEW_LINE, numberOfNewLines);
        }
    }

    private String prepareVariaSection(String variaContent, int numberOfNewLines) {
        if (isEmpty(variaContent)) {
            return "";
        } else {
            return "Varia:" + NEW_LINE + variaContent
                + StringUtils.repeat(NEW_LINE, numberOfNewLines);
        }
    }

    private String prepareMainSectionWithBlogs(NewsletterIssue newsletterIssue) {
        List<Blog> blogsAddedSinceLastNewsletter = List.ofAll(newsletterIssue.getNewBlogs());
        List<BlogPost> newApprovedPosts = List.ofAll(newsletterIssue.getBlogPosts());

        Map<BlogType, List<BlogPost>> newBlogPostsByType = newApprovedPosts
            .groupBy(it -> it.getBlog().getBlogType());

        List<BlogPost> newPostsFromPersonalBlogs =
            newBlogPostsByType.getOrElse(BlogType.PERSONAL, empty());
        List<BlogPost> newPostsFromCompanies =
            newBlogPostsByType.getOrElse(BlogType.COMPANY, empty());
        List<BlogPost> newVideoPosts =
            newBlogPostsByType.getOrElse(BlogType.VIDEOS, empty());

        String templateContent = getValueForSection(MetadataKeys.MAILING_TEMPLATE);
        ST template = new ST(templateContent, TEMPLATE_DELIMITER, TEMPLATE_DELIMITER);
        template.add("days", DAYS_IN_THE_PAST);
        template.add("newPosts",
            postsToMailItems(newPostsFromPersonalBlogs, newsletterIssue.getIssueNumber()).toJavaArray()
        );
        template.add("newPostsFromCompanies",
            postsToMailItems(newPostsFromCompanies, newsletterIssue.getIssueNumber()).toJavaList()
        );
        template.add("newlyAddedBlogs",
            blogsToMailItems(blogsAddedSinceLastNewsletter, newsletterIssue.getIssueNumber())
        );
        template.add(
            "newVideoPosts", postsToMailItems(newVideoPosts, newsletterIssue.getIssueNumber()).toJavaList()
        );
        return template.render();
    }

    private List<BlogPostForMailItem> postsToMailItems(List<BlogPost> newPosts, long issueNumber) {
        return newPosts
            .sorted(Comparator.comparing(b -> b.getBlog().getAuthor()))
            .map(blogPost ->
            BlogPostForMailItem.builder()
                .from(blogPost)
                .withIssueNumber(issueNumber)
                .withUrl(linkGenerator.generateRedirectLinkFor(blogPost.getUid()))
                .build()
        );
    }

    private List<Blog> blogsToMailItems(List<Blog> blogs, long issueNumber) {
        return blogs
            .filter(blog -> !Strings.isNullOrEmpty(blog.getUrl()))
            .map(blog -> {
                blog.setUrl(urlWithUtmParameters(blog.getUrl(), issueNumber));
                return blog;
            });
    }

    private String urlWithUtmParameters(String url, long issueNumber) {
        return UriUtmComponentsBuilder.fromHttpUrl(url)
            .withSource(DEFAULT_UTM_SOURCE)
            .withMedium(UTM_MEDIUM)
            .withCampaign(String.format("%s#%s", DEFAULT_UTM_CAMPAING, issueNumber))
            .build();
    }

}

@@ -524,16 +524,17 @@
 rIssue;%0A
+%0A
 import i
@@ -588,16 +588,17 @@
 on.Map;%0A
+%0A
 import l
@@ -618,24 +618,25 @@
 onstructor;%0A
+%0A
 import org.a
@@ -4526,24 +4526,41 @@
 sueNumber())
+%0A                
 .toJavaArray
@@ -4562,16 +4562,16 @@
 Array()%0A
-
         
@@ -4924,16 +4924,28 @@
 oPosts%22,
+%0A           
  postsTo
@@ -5305,16 +5305,20 @@
         
+    
 BlogPost
@@ -5355,16 +5355,20 @@
         
+    
 .from(bl
@@ -5375,16 +5375,20 @@
 ogPost)%0A
+    
         
@@ -5437,24 +5437,28 @@
             
+    
 .withUrl(lin
@@ -5520,32 +5520,36 @@
                 
+    
 .build()%0A       
@@ -5541,16 +5541,20 @@
 build()%0A
+    
         

Fix formatting in BlogSummaryMailGenerator