package me.qwq.doghouse.service;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.TextNode;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;

import lombok.extern.slf4j.Slf4j;
import me.qwq.doghouse.cache.CacheConstants;
import me.qwq.doghouse.entity.Comment;
import me.qwq.doghouse.entity.Post;
import me.qwq.doghouse.util.MarkDownUtils;

/**
 * Markdown 渲染服务，大部分实现了缓存
 * @author Doghole
 *
 */
@Service
@Slf4j
public class MarkdownService {
    
    /**
     * 获取用于 SEO 的描述
     * @param post
     * @return
     */
    @Cacheable(value=CacheConstants.Posts.GET_SEO_DESCRIPTION, key="#post.postId")
    public String getSeoDescription(Post post) {
        
        if (StringUtils.isEmpty(post.getDescription())) {
            String html;
            if (StringUtils.isEmpty(post.getPostPreface())) {
                html = renderPostContent(post);
            }
            else {
                html = renderPostPreface(post);
            }
            return getTextContent(html);
        }
        else {
            return post.getDescription();
        }
    }
    
    /**
     * 渲染 post 正文
     * @param post
     * @return
     */
    @Cacheable(value=CacheConstants.Posts.MARKDOWN_CONTENT_RENDERING,
            key="#post.postId")
    public String renderPostContent(Post post) {
        return MarkDownUtils.postContentToHtml(post.getPostContent());
    }
    
    /**
     * 获取正文渲染的 HTML 的 textContent
     * @param post
     * @return
     */
    @Cacheable(value=CacheConstants.Posts.GET_CONTENT_TEXT,
            key="#post.postId")
    public String getPostContentText(Post post) {
        String html = renderPostContent(post);
        return getTextContent(html);
    }
    
    /**
     * 渲染 post 前言
     * @param post
     * @return
     */
    @Cacheable(value=CacheConstants.Posts.MARKDOWN_PREFACE_RENDERING,
            key="#post.postId")
    public String renderPostPreface(Post post) {
        return renderPostPreface(post, "");
    }
    
    /**
     * 获取前言渲染的 HTML 的 textContent
     * @param post
     * @return
     */
    @Cacheable(value=CacheConstants.Posts.GET_PREFACE_TEXT,
            key="#post.postId")
    public String getPostPrefaceText(Post post) {
        String html = renderPostContent(post);
        return getTextContent(html);
    }
    
    
    /**
     * 渲染 post 前言
     * @param post
     * @param replacement 替代
     * @return
     */
    public String renderPostPreface(Post post, String replacement) {
        if (StringUtils.isEmpty(post.getPostPreface())) {
            return MarkDownUtils.postContentToHtml(post.getPostContent(), replacement);
        }
        return MarkDownUtils.postContentToHtml(post.getPostPreface());
    }
    
    /**
     * 渲染 comment
     * @param comment
     * @return
     */
    @Cacheable(value=CacheConstants.Comments.MARKDOWN_CONTENT_RENDERING,
            key="#comment.id", condition="#comment != null")
    public String renderCommentContent(Comment comment) {
        if (comment.isMarkdown()) {
            return MarkDownUtils.commentToHtml(comment.getContent());
        }
        log.warn("Render non-markdown comment {}", comment.getId());
        return null;
    }
    
    /**
     * 获取评论渲染的 HTML 的 textContent, 一般用于禁止复杂格式的场景
     * @param post
     * @return
     */
    @Cacheable(value=CacheConstants.Comments.GET_CONTENT_TEXT,
            key="#comment.id", condition="#comment != null")
    public String getCommentContentText(Comment comment) {
        if (!comment.isMarkdown()) {
            return comment.getContent();
        }
        String html = renderCommentContent(comment);
        return getTextContent(html);
    }
    
    /**
     * Get html textContent without &lt;style> or &lt;script>,
     * replace &lt;img ...> with '[Image]', etc.
     * @param html
     * @return
     */
    private static String getTextContent(String html) {
        Document doc = Jsoup.parseBodyFragment(html);

        doc.select("style,script,iframe").remove();
        doc.select("img").forEach(img -> img.replaceWith(new TextNode("[Image]")));
        doc.select("video").forEach(video -> video.replaceWith(new TextNode("[Video]")));
        doc.select("audio").forEach(audio -> audio.replaceWith(new TextNode("[Audio]")));

        String text = doc.text().trim();

        if (text.length() > 100)
            return text.substring(0, 100) + "...";

        return text;
    }
}
