package me.qwq.doghouse.controller.blog;


import com.rometools.rome.feed.synd.*;
import com.rometools.rome.io.FeedException;
import com.rometools.rome.io.SyndFeedOutput;

import me.qwq.doghouse.controller.common.BaseController;
import me.qwq.doghouse.entity.config.SiteConfig;
import me.qwq.doghouse.entity.Post;
import me.qwq.doghouse.exception.PageNotFoundException;
import me.qwq.doghouse.service.*;
import me.qwq.doghouse.service.post.PostService;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * Feed
 *
 * @author Doghole
 * @date 2021/12/23
 */
@Controller
public class FeedController extends BaseController {

    public final static String ATOM_1_0 = "atom_1.0";
    public final static String RSS_2_0 = "rss_2.0";
    public final static String CATEGORY_PATH = "/category/";
    public final static String COMMA = ",";
    public final static String FEED_PATH = "/feed.xml";
    public final static String TEXT_HTML = "text/html";
    public final static String POST_ENCRYPTED = "加密文章 ";
    public final static String POST_ENCRYPTED_DESCRIPTION = "该文章已加密，请输入密码查看";
    public final static String RSS_LANGUAGE = "zh-cn";
    public final static String SELF = "self";
    public final static String SLASH = "/";
    public final static String UTF8 = "utf-8";
    public final static String MORE = "<!--more-->";
    
    @Autowired
    PostService postService;
    
    @Autowired
    ConfigService configService;
    
    @Autowired
    SiteConfig siteConfig;
    
    @Autowired
    MarkdownService markdownService;
    
    @SuppressWarnings("serial")
    @GetMapping(value=FEED_PATH, produces = "application/xml")
    @ResponseBody
    public String feed() throws FeedException {
        
        if (!siteConfig.getRssOn()) {
            throw new PageNotFoundException();
        }
        final String siteAddr = !siteConfig.getAddress().endsWith(SLASH) ?
                siteConfig.getAddress() : siteConfig.getAddress().substring(0, siteConfig.getAddress().length());
        
        SyndLink rssLink = new SyndLinkImpl() {{
            setHref(new StringBuilder(siteAddr).append(FEED_PATH).toString());
            setRel(SELF);
        }};
        
        SyndLink siteLink = new SyndLinkImpl() {{setHref(siteAddr);}};
        
        List<SyndLink> links = new ArrayList<SyndLink>() {{
            add(rssLink);add(siteLink);
        }};
        
        SyndFeed feed = new SyndFeedImpl();
        feed.setFeedType(ATOM_1_0);
        feed.setCopyright(siteConfig.getCopyright());
        feed.setDescription(siteConfig.getDescription());
        feed.setEncoding(UTF8);
        feed.setLinks(links);
        feed.setLanguage(RSS_LANGUAGE);
        feed.setTitle(siteConfig.getName());

        List<SyndEntry> entries = new ArrayList<>();
        List<Post> posts = postService.getLatestPosts(siteConfig.getRecentSize());
        for (Post post : posts) {
            boolean hasPassword = StringUtils.isNotEmpty(post.getPassword());
            
            SyndEntry entry = new SyndEntryImpl();
            entry.setTitle(hasPassword?POST_ENCRYPTED + post.getPostId():post.getPostTitle());
            // Add content if it's not encrypted
            if (!hasPassword) {
                SyndContent content = new SyndContentImpl();
                content.setType(TEXT_HTML);
                content.setValue(markdownService.renderPostContent(post));
                entry.setContents(new ArrayList<SyndContent>(){{add(content);}});
            }
            
            // Add description if it's present
            if (hasPassword) {
                SyndContent description = new SyndContentImpl();
                description.setType(TEXT_HTML);
                description.setValue(POST_ENCRYPTED_DESCRIPTION);
                entry.setDescription(description);
            }
            else {
                SyndContent description = new SyndContentImpl();
                description.setType(TEXT_HTML);
                description.setValue(markdownService.renderPostPreface(post));
                entry.setDescription(description);
            }
            
            entry.setLink(new StringBuilder(siteAddr).append(post.getLink()).toString());
            entry.setPublishedDate(Date.from(post.getCreateTime().atZone(ZoneId.systemDefault()).toInstant()));
            entry.setUpdatedDate(Date.from(post.getUpdateTime().atZone(ZoneId.systemDefault()).toInstant()));
            
            if (StringUtils.isBlank(post.getPassword()) && StringUtils.isNotBlank(post.getCategoriesName())) {
                List<SyndCategory> categories = new ArrayList<>();
                String[] categoriesFriendlyNames = post.getCategoriesFriendlyName().split(COMMA);
                String[] categoriesNames = post.getCategoriesName().split(COMMA);
                for (int i = 0; i < categoriesFriendlyNames.length; i++) {
                    String cateName = categoriesNames[i],
                           cateFriendlyName = categoriesFriendlyNames[i];
                    try {
                        categories.add(new SyndCategoryImpl() {{
                            this.setLabel(cateFriendlyName);
                            this.setName(cateName);
                            this.setTaxonomyUri(
                                new StringBuilder()
                                    .append(siteAddr)
                                    .append(CATEGORY_PATH)
                                    .append(URLEncoder.encode(cateFriendlyName, UTF8)).toString());
                        }});
                    } catch (UnsupportedEncodingException e) {
                        continue;
                    }
                }
                if (!categories.isEmpty()) {
                    entry.setCategories(categories);
                }
            }
            entries.add(entry);
        }
        feed.setEntries(entries);
        
        SyndFeedOutput output = new SyndFeedOutput();
        return output.outputString(feed);
        
    }
}
