package me.qwq.doghouse.service;

import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.github.yulichang.wrapper.MPJLambdaWrapper;

import lombok.Getter;
import lombok.Setter;
import me.qwq.doghouse.cache.CacheConstants;
import me.qwq.doghouse.cache.CacheEvictionTask;
import me.qwq.doghouse.dao.StatisticsMapper;
import me.qwq.doghouse.entity.Comment;
import me.qwq.doghouse.entity.Post;
import me.qwq.doghouse.enums.CommentStatusEnum;
import me.qwq.doghouse.enums.PostStatusEnum;
import me.qwq.doghouse.enums.PostTypeEnum;
import me.qwq.doghouse.pojo.dto.DailyPostCommentStats;
import me.qwq.doghouse.service.post.PostService;

@Service
public class StatisticsService {
    
    @Autowired
    StatisticsMapper mapper;
    
    @Autowired
    PostService postService;
    
    @Autowired
    CommentService commentService;
    
    @Autowired
    MarkdownService markdownService;

    @CacheEvictionTask
    @Cacheable(value=CacheConstants.Statistics.DAY_SINCE)
    public long daysSince(int year, int month, int dayOfMonth) {
        return ChronoUnit.DAYS.between(
                LocalDate.of(year, month, dayOfMonth),
                LocalDate.now());
    }

    /**
     * 暂用于后台 POST 统计<br>
     * 目前仅针对未删除的、任意状态的 PostTypeEnum.POST 类型，
     * 包括私密、加密、草稿和隐藏
     * @param enums Post 类型
     * @return 文章总数
     */
    @Cacheable(value=CacheConstants.Statistics.TOTAL_RELEASE_POSTS_COUNT)
    public long totalReleasedPostsCount(PostTypeEnum...enums) {
        return postService.count(new MPJLambdaWrapper<Post>()
                .eq(Post::getIsDeleted, false)
                .eq(Post::getPostStatus, PostStatusEnum.RELEASED)
                .in(enums != null && enums.length > 0,
                Post::getType, (Object[])enums));
    }
    /**
     * 获取指定评论状态枚举列表下的所有未删除的评论数量之和
     * @param enums 指定评论状态枚举列表
     * @return
     */
    @Cacheable(value=CacheConstants.Statistics.TOTAL_COMMENTS_COUNT)
    public long totalCommentsCount(CommentStatusEnum...enums) {
        return commentService.count(new MPJLambdaWrapper<Comment>()
                .eq(Comment::getIsDeleted, false)
                .in(enums != null && enums.length > 0,
                Comment::getCommentStatus, (Object[])enums));
    }
    
    /**
     * 获取过去 passDays 日的每日文章和评论数
     * @param passDays
     * @param postType
     * @return
     */
    @CacheEvictionTask
    @Cacheable(value=CacheConstants.Statistics.DAILY_POST_AND_COMMENT_COUNTS)
    public DailyPostCommentStats getPostAndCommentCountsWithDates(Integer passDays, PostTypeEnum postType) {
        Map<String, String> map =
                mapper.getPostAndCommentCountsWithDates(passDays, postType);

        List<String> dates =
                Arrays.asList(map.get("dates").split(","));

        List<Integer> postCounts =
                Arrays.stream(map.get("postCounts").split(","))
                      .map(Integer::valueOf)
                      .toList();

        List<Integer> commentCounts =
                Arrays.stream(map.get("commentCounts").split(","))
                      .map(Integer::valueOf)
                      .toList();

        return new DailyPostCommentStats(dates, postCounts, commentCounts);
    }

    public PostStatistic getPostStatistic(Post post) {
        return new PostStatistic(post);
    }
    
    public PostStatistic getPostStatistic(Post post, String decimalFormat) {
        return new PostStatistic(post, decimalFormat);
    }
    
    public class PostStatistic {

        @Getter
        @Setter
        private DecimalFormat decimalFormat;
        private Post post;
        private Integer words;
        private String readingTime;
        private Integer remains = 0;
        /**
         * 构造器
         * @param post 需要统计的 Post
         */
        public PostStatistic(Post post) {
            this.post = post;
            String html = markdownService.renderPostContent(post);
            // 统计字数
            words = getHtmlWordsCount(html);
            
            // 统计预计阅读时间
            int second = words * 60 / 400, hour = second / 3600;
            second = second % 3600;
            int minute = second / 60;
            second = second % 60;
            
            StringBuilder readingTimeSb = new StringBuilder();
            if (hour != 0) {
                readingTimeSb.append(hour).append(" h ");
            }
            if (minute != 0) {
                readingTimeSb.append(minute).append(" m ");
            }
            if (second != 0) {
                readingTimeSb.append(second).append(" s ");
            }
            readingTime = readingTimeSb.toString().trim();
            
            // 统计剩余字数
            if (!StringUtils.isEmpty(post.getPostPreface())) {
                remains = words;
            }
            else if (post.getPostContent().contains("<!--more-->")) {
                html = post.getPostContent().substring(0, post.getPostContent().indexOf("<!--more-->"));
                remains = words - getHtmlWordsCount(html);
            }
        }
        
        /**
         * 构造器
         * @param post 需要统计的 Post
         * @param decimalFormat 数字格式
         */
        public PostStatistic(Post post, String decimalFormat) {
            this(post);
            this.decimalFormat = new DecimalFormat(decimalFormat);
        }

        /**
         * 获取浏览数
         * @return
         */
        public String getViewCount() {
            if (decimalFormat != null) {
                return decimalFormat.format(post.getPostViews());
            }
            return post.getPostViews().toString();
        }
        
        /**
         * 获取评论数
         * @return
         */
        public String getCommentCount() {
            if (decimalFormat != null) {
                return decimalFormat.format(post.getCommentCount());
            }
            return post.getCommentCount().toString();
        }

        /**
         * 获取词数统计
         * @return
         */
        public String getWordCount() {
            if (decimalFormat != null) {
                return decimalFormat.format(words);
            }
            return words.toString();
        }
        
        /**
         * 获取预计阅读时长
         * @return
         */
        public String getReadingTime() {
            return readingTime;
        }
        
        /**
         * 获取剩余字数
         * @return
         */
        public String getRemains() {
            if (decimalFormat != null) {
                return decimalFormat.format(remains);
            }
            return remains.toString();
        }
        
        /**
         * 统计 html 源码中字数
         * @param string
         * @return
         */
        public Integer getHtmlWordsCount(String string) {
            if (string == null) {
                return 0;
            }
            // 去除 html 标签
            string = string.replaceAll("<[^<]+>", "").replaceAll("[\\n\\t\\s]+", "");
            
            // 中英文分开统计
            String englishString = string.replaceAll("[\u4e00-\u9fa5]", "");
            String[] englishWords = englishString.split("[\\p{P}\\p{S}\\p{Z}\\s]+");
            int chineseWordCount = string.length() - englishString.length();
            int otherWordCount = englishWords.length;
            if (englishWords.length > 0 && englishWords[0].length() < 1) {
                otherWordCount--;
            }
            if (englishWords.length > 1 && englishWords[englishWords.length - 1].length() < 1) {
                otherWordCount--;
            }
            return chineseWordCount + otherWordCount;
        }
    }
}
