package com.pcloud.book.applet.biz.impl;

import com.google.common.collect.Lists;
import com.pcloud.book.applet.biz.AppletRecordStatisBiz;
import com.pcloud.book.applet.dao.AppletRecordStatisDao;
import com.pcloud.book.applet.dto.ReadBookWeekStatisDTO;
import com.pcloud.book.applet.entity.AppletRecordStatisReport;
import com.pcloud.book.applet.dao.AppletRecordStatisReportDao;
import com.pcloud.book.applet.biz.AppletRecordStatisReportBiz;
import com.pcloud.book.consumer.reader.ReaderConsr;
import com.pcloud.book.util.common.CommonUtils;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.NumberUtil;
import com.pcloud.common.utils.ResponseHandleUtil;
import com.pcloud.common.utils.cache.redis.JedisClusterUtils;
import com.pcloud.facade.shareimage.dto.HtmlDto;
import com.pcloud.facade.shareimage.facade.Htm2ImgService;
import com.pcloud.readercenter.wechat.dto.Wechat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.pcloud.book.applet.contants.AppletConstants;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * 个人阅读报告总结(AppletRecordStatisReport)表服务实现类
 *
 * @author makejava
 * @since 2020-12-11 16:22:46
 */
@Service("appletRecordStatisReportBiz")
public class AppletRecordStatisReportBizImpl implements AppletRecordStatisReportBiz {

    private static final Logger LOGGER = LoggerFactory.getLogger(AppletRecordStatisReportBizImpl.class);

    @Autowired
    private AppletRecordStatisReportDao appletRecordStatisReportDao;
    @Autowired
    private AppletRecordStatisBiz appletRecordStatisBiz;
    @Autowired
    private AppletRecordStatisDao appletRecordStatisDao;
    @Autowired
    private ReaderConsr readerConsr;
    @Autowired
    private Htm2ImgService htm2ImgService;

    @Override
    @ParamLog("通过ID查询单条数据")
    public AppletRecordStatisReport getById(Long id) {
        return appletRecordStatisReportDao.getById(id);
    }

    @Override
    @ParamLog("查询多条数据")
    public PageBeanNew getList(Integer currentPage, Integer numPerPage) {
        PageBeanNew pageBeanNew = appletRecordStatisReportDao.listPageNew(new PageParam(currentPage, numPerPage), null, "getList");
        List recordList = pageBeanNew.getRecordList();
        if (ListUtils.isEmpty(recordList)){
            return pageBeanNew;
        }
        // 加载其它数据
        
        return pageBeanNew;
    }

    @Override
    @ParamLog("新增")
    public Long insert(AppletRecordStatisReport appletRecordStatisReport) {
        appletRecordStatisReportDao.insert(appletRecordStatisReport);
        return appletRecordStatisReport.getId();
    }

    @Override
    @ParamLog("修改")
    public void update(AppletRecordStatisReport appletRecordStatisReport) {
        if(appletRecordStatisReport == null || !NumberUtil.isNumber(appletRecordStatisReport.getId())){
            throw BizException.PARAM_IS_NULL;
        }
        appletRecordStatisReportDao.update(appletRecordStatisReport);
    }

    @Override
    @ParamLog("删除")
    public void deleteById(Long id) {
        appletRecordStatisReportDao.deleteById(id);
    }

    @Override
    public AppletRecordStatisReport getReadReport4Week(Long wechatUserId, String mondayDate) {
        if(mondayDate == null){
            throw new BizException(BizException.PARAM_IS_NULL.getCode(),"mondayDate不能为空");
        }
        Date monday = DateUtils.getDateFromString(mondayDate, "yyyy-MM-dd");
        // 校准周一
        monday = CommonUtils.getWeekStart(monday);
        Date sunday = DateUtils.addDay(monday, 6);
        Date thisMonday = CommonUtils.getWeekStart();
        if(monday.compareTo(thisMonday) > -1 || monday.compareTo(AppletConstants.APPLET_RECORD_STATIS_REPORT_START_DATE) == -1){
            AppletRecordStatisReport report = new AppletRecordStatisReport();
            report.setBeginDate(monday);
            report.setEndDate(sunday);
            report.setScore(BigDecimal.ZERO);
            return report;
            // throw new BizException(BizException.PARAM_IS_NULL.getCode(), "未找到该周的报告");
        }
        // 直接获取本周分数结果
        AppletRecordStatisReport thisWeekReport = appletRecordStatisReportDao.getByWechatUserId(wechatUserId, monday);
        if(thisWeekReport != null){
            return thisWeekReport;
        }
        // 计算本周分数结果
        BigDecimal score = getReportScore(wechatUserId, monday, sunday);
        if(BigDecimal.ZERO.compareTo(score) == 0){
            AppletRecordStatisReport report = new AppletRecordStatisReport();
            report.setBeginDate(monday);
            report.setEndDate(sunday);
            report.setScore(BigDecimal.ZERO);
            return report;
        }

        // 上周的统计结果
        AppletRecordStatisReport prevWeekReport = appletRecordStatisReportDao.getByWechatUserId(wechatUserId, DateUtils.addDay(monday, -7));
        BigDecimal prevWeekScore = BigDecimal.ZERO.setScale(1);
        // 分数不为空，并且大于0
        if(prevWeekReport != null && prevWeekReport.getScore() != null && BigDecimal.ZERO.compareTo(prevWeekReport.getScore()) == -1){
            prevWeekScore = prevWeekReport.getScore();
        }

        AppletRecordStatisReport report = new AppletRecordStatisReport();
        report.setWechatUserId(wechatUserId);
        report.setBeginDate(monday);
        report.setEndDate(sunday);
        report.setScore(score);
        report.setCompareScore(score.subtract(prevWeekScore).setScale(1));
        report.setCompareUserRatio(getCompareUserRatio(score));
        appletRecordStatisReportDao.insert(report);
        return report;
    }

    private BigDecimal getReportScore(Long wechatUserId, Date monday, Date sunday) {
        /**
         * 满分 10 分
         * 1.阅读新书达到 10 本
         * 2.阅读书达到 10 本
         * 3.点击应用作品 10 次
         * 4.点击资讯 10 次
         * 5.点击社群 10 个（暂时排除）
         */
        // 总分10分，每个规则占比25%
        BigDecimal totalScore = BigDecimal.valueOf(10.00);
        BigDecimal ratio = BigDecimal.valueOf(0.25);
        BigDecimal score = BigDecimal.ZERO;

        // 1.阅读新书达到 10 本；2.阅读书达到 10 本
        ReadBookWeekStatisDTO readBookWeekStatisDTO = appletRecordStatisBiz.getReadBookWeekStatisDTO(wechatUserId, monday, sunday);
        // 3.点击应用作品 10 次
        Integer appProductClickCount = appletRecordStatisDao.getBookSourceTotalClickCount(wechatUserId, monday);
        // 4.点击资讯 10 次
        Integer newsClickCount = appletRecordStatisDao.getBookNewsTotalClickCount(wechatUserId, monday);

        score = score.add(totalScore.multiply(ratio).multiply(new BigDecimal(getCount(readBookWeekStatisDTO.getReadBookCount())).divide(BigDecimal.valueOf(10))));
        score = score.add(totalScore.multiply(ratio).multiply(new BigDecimal(getCount(readBookWeekStatisDTO.getReadNewBookCount())).divide(BigDecimal.valueOf(10))));
        score = score.add(totalScore.multiply(ratio).multiply(new BigDecimal(getCount(appProductClickCount)).divide(BigDecimal.valueOf(10))));
        score = score.add(totalScore.multiply(ratio).multiply(new BigDecimal(getCount(newsClickCount)).divide(BigDecimal.valueOf(10))));
        return score.setScale(1, BigDecimal.ROUND_UP);
    }

    Integer getCount(Integer count){
        return count > 10 ? 10 : count;
    }

    // 计算超过用户的百分比
    BigDecimal getCompareUserRatio(BigDecimal score){
        // 因为是用户点击了才生成报告，所以用户每次进去报告页面会导致看到不同的占比，所以根据分数来随机一个占比，这个数据其实也没有实际用处
        BigDecimal userRatio = new BigDecimal(100);
        if(new BigDecimal(10).compareTo(score) == 1){
            // 先舍去小数点，然后乘10，再加上10以内的小数；
            // 例如 8.6 = 8.0*10=80+(10以内的小数)=88.8；所以就是 88.8 就是 8.6 对应的超过用户占比
            userRatio = score
                    .setScale(0,1)
                    .multiply(new BigDecimal(10))
                    .add(new BigDecimal(new Random().nextDouble()).multiply(new BigDecimal(10)).setScale(1,1));
        }
        return userRatio;
    }

    @Override
    public PageBeanNew getReadReportList(Long wechatUserId, Integer currentPage, Integer numPerPage ) {
        HashMap<String, Object> params = new HashMap<>();
        params.put("wechatUserId", wechatUserId);
        // 补充历史记录报告
        replenishHistoryReport(wechatUserId);
        // 查询列表
        PageBeanNew pageBeanNew = appletRecordStatisReportDao.listPageNew(new PageParam(currentPage, numPerPage), params, "getList");
        List recordList = pageBeanNew.getRecordList();
        if (ListUtils.isEmpty(recordList)){
            return pageBeanNew;
        }
        return pageBeanNew;
    }

    /**
     * 补充历史记录报告
     */
    private void replenishHistoryReport(Long wechatUserId) {
        // 检测上次生成历史记录的时间
        String redisKey = AppletConstants.APPLET_RECORD_HISTORY_STATIS_REPORT_LAST_DATE + wechatUserId;
        String lastDate = JedisClusterUtils.get(redisKey);
        String monday = DateUtils.getReqDate(CommonUtils.getWeekStart());
        // 如果本周已经生成过，则return
        if(monday.equals(lastDate)){
            return;
        }
        // 本周已经生成记录标识
        JedisClusterUtils.set(redisKey, monday, 3600 * 24 * 7);
        // 获取开始时间到上周所有的周一
        List<Date> allMonday = getAllMonday(AppletConstants.APPLET_RECORD_STATIS_REPORT_START_DATE, DateUtils.addDay(CommonUtils.getWeekStart(), -7));
        if(CollectionUtils.isEmpty(allMonday)){
            return;
        }
        // 获取所有的历史记录
        List<AppletRecordStatisReport> historyReportList = appletRecordStatisReportDao.getUserHistoryReport(wechatUserId, allMonday);
        // 检测缺省的历史记录
        if(historyReportList == null){
            historyReportList = Lists.newArrayList();
        }
        List<Date> existsReportList = historyReportList.stream().map(x -> x.getBeginDate()).collect(Collectors.toList());
        allMonday.removeAll(existsReportList);
        if(CollectionUtils.isEmpty(allMonday)){
            return;
        }
        // 循环生成缺省的历史记录，添加到所有历史记录表
        AppletRecordStatisReport statisReport;
        Date sunday;
        for (Date _monday : allMonday) {
            sunday = DateUtils.addDay(_monday, 6);
            statisReport = new AppletRecordStatisReport();
            // 计算本周分数结果
            BigDecimal score = getReportScore(wechatUserId, _monday, sunday);
            if(BigDecimal.ZERO.compareTo(score) == 0){
                continue;
            }
            statisReport.setWechatUserId(wechatUserId);
            statisReport.setBeginDate(_monday);
            statisReport.setEndDate(sunday);
            statisReport.setScore(score);
            statisReport.setCompareUserRatio(getCompareUserRatio(score));
            historyReportList.add(statisReport);
        }
        // 重新计算比上周的分数值，并更新缺省下一周记录的比上周的值
        Map<String, AppletRecordStatisReport> statisReportMap = historyReportList.stream().collect(Collectors.toMap(x -> DateUtils.getReqDate(x.getBeginDate()), x -> x));
        for (AppletRecordStatisReport report : statisReportMap.values()) {
            AppletRecordStatisReport prevReport = statisReportMap.get(DateUtils.getReqDate(DateUtils.addDay(report.getBeginDate(), -7)));
            if(prevReport == null || prevReport.getScore() == null){
                report.setCompareScore(report.getScore().setScale(1));
                continue;
            }
            report.setCompareScore(report.getScore().subtract(prevReport.getScore()).setScale(1));
        }
        // 批量插入、更新
        appletRecordStatisReportDao.insertOrUpdate(historyReportList);
    }

    private List<Date> getAllMonday(Date beginDate, Date endDate){
        List<Date> mondayList = Lists.newArrayList();
        if(beginDate == null){
            return mondayList;
        }
        // 如果结束时间为null，则将其赋值为当前时间
        if(endDate == null){
            endDate = new Date();
        }
        Date beginMonday = CommonUtils.getWeekStart(beginDate);
        Date endMonday = CommonUtils.getWeekStart(endDate);
        // 如果开始时间比结束时间大，直接返回
        if(beginMonday.compareTo(endMonday) == 1){
            return mondayList;
        }
        mondayList.add(beginMonday);
        while (beginMonday.compareTo(endMonday) == -1){
            beginMonday = DateUtils.addDay(beginMonday, 7);
            mondayList.add(beginMonday);
        }
        return mondayList;
    }

    @Override
    public String shareReadReport(Long wechatUserId, String mondayDate) {
        if(mondayDate == null){
            throw new BizException(BizException.PARAM_IS_NULL.getCode(),"mondayDate不能为空");
        }
        // 生成分享图
        HtmlDto htmlDto=new HtmlDto();
        htmlDto.setHeight(1206);
        htmlDto.setWidth(750);
        htmlDto.setHtmlCode(builderShareHtml(wechatUserId, mondayDate));
        htmlDto.setSnapshot(new Long(System.currentTimeMillis()).toString());
        return ResponseHandleUtil.parseResponse(htm2ImgService.toJPGByChrome(htmlDto), String.class);
    }

    private String builderShareHtml(Long wechatUserId, String mondayDate) {
        Date monday = DateUtils.getDateFromString(mondayDate, "yyyy-MM-dd");
        // 校准周一
        monday = CommonUtils.getWeekStart(monday);
        // 直接获取本周分数结果
        AppletRecordStatisReport thisWeekReport = appletRecordStatisReportDao.getByWechatUserId(wechatUserId, monday);
        if(thisWeekReport == null){
            throw new BizException(BizException.DB_SELECT_IS_FAIL.getCode(), "没有找到阅读报告，它可能去火星啦");
        }
        // 获取用户信息
        Wechat wechat = readerConsr.getWechatUserInfo(wechatUserId);
        // HTML生成
        return "\n" +
                "<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "\n" +
                "<head>\n" +
                "  <meta charset=\"GBK\">\n" +
                "  <!-- <meta charset=\"utf-8\"> -->\n" +
                "  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
                "  <title>report-share</title>\n" +
                "</head>\n" +
                "<style>\n" +
                "  * {\n" +
                "    margin: 0;\n" +
                "    padding: 0;\n" +
                "  }\n" +
                "\n" +
                "  body {\n" +
                "    font-family: sans-serif;\n" +
                "    color:#333;\n" +
                "    box-sizing: border-box;\n" +
                "  }\n" +
                "  .report-shareInfo{\n" +
                "    width:750px;\n" +
                "    height:100vh;\n" +
                "    background:url('https://file.5rs.me/oss/uploadfe/png/6841a46a78818b3014d604a13f10c39f.png') no-repeat;\n" +
                "    background-size: cover;\n" +
                "    margin:0 auto;\n" +
                "    position: relative;\n" +
                "    padding-top: 80px;\n" +
                "    box-sizing: border-box;\n" +
                "  }\n" +
                "  .title-bg{\n" +
                "    width:462px;\n" +
                "    height:110px;\n" +
                "    position: absolute;\n" +
                "    left: 145px;\n" +
                "    top:44px;\n" +
                "    z-index: 1;\n" +
                "  }\n" +
                "  .report-content{\n" +
                "    position: relative;\n" +
                "    width:640px;\n" +
                "    height:922px;\n" +
                "    background: url('https://file.5rs.me/oss/uploadfe/png/83dcdfb55be87c6aabaf808e343fd07a.png') no-repeat;\n" +
                "    background-size: 640px 922px;\n" +
                "    margin:0 auto;\n" +
                "    padding: 80px 36px 0;\n" +
                "    box-sizing: border-box;\n" +
                "    display: flex;\n" +
                "    flex-direction: column;\n" +
                "    align-items: center;\n" +
                "  }\n" +
                "  .user-info{\n" +
                "    display: flex;\n" +
                "    align-items: center;\n" +
                "    width:100%;\n" +
                "  }\n" +
                "  .head-url{\n" +
                "    width: 80px;\n" +
                "    height:80px;\n" +
                "    display: flex;\n" +
                "    border: 4px solid #2470FB;\n" +
                "    border-radius: 100%;\n" +
                "    overflow: hidden;\n" +
                "    background: url('"+wechat.getPicUrl()+"') no-repeat;\n" +
                "    background-size: contain;\n" +
                "    background-position: center;\n" +
                "    margin-right: 14px;\n" +
                "    margin-left: 14px;\n" +
                "  }\n" +
                "  .user-right{\n" +
                "    display: flex;\n" +
                "    flex-direction: column;\n" +
                "    justify-content: space-around;\n" +
                "  }\n" +
                "  .username{\n" +
                "    font-size: 32px;\n" +
                "    line-height: 1.4;\n" +
                "  }\n" +
                "  .loginDays{\n" +
                "    font-size: 24px;\n" +
                "  }\n" +
                "  .loginDays span{\n" +
                "    font-size: 24px;\n" +
                "    color: #FE5E47;\n" +
                "  }\n" +
                "  .score-content{\n" +
                "    width:402px;\n" +
                "    height:316px;\n" +
                "    background: url('https://file.5rs.me/oss/uploadfe/png/0fafcb400d753d9fd6b62041b5df664b.png') no-repeat;\n" +
                "    display: flex;\n" +
                "    flex-direction: column;\n" +
                "    align-items: center;\n" +
                "    justify-content: center;\n" +
                "    margin-top: 26px;\n" +
                "    box-sizing: border-box;\n" +
                "    padding-top: 46px;\n" +
                "  }\n" +
                "  .score-tips{\n" +
                "    color: #80413B;\n" +
                "    font-size: 24px;\n" +
                "  }\n" +
                "  .score{\n" +
                "    font-size: 48px;\n" +
                "    color: #80413B;\n" +
                "    font-weight: bold;\n" +
                "    display: flex;\n" +
                "    align-items: center;\n" +
                "  }\n" +
                "  .danwei{\n" +
                "    color: #80413B;\n" +
                "    font-size: 24px;\n" +
                "    font-weight: normal;\n" +
                "  }\n" +
                "  .score-compare{\n" +
                "    display: flex;\n" +
                "    flex-direction: column;\n" +
                "    justify-content: center;\n" +
                "    align-items: center;\n" +
                "    font-size: 32px;\n" +
                "    color: #333;\n" +
                "    font-weight: bold;\n" +
                "  }\n" +
                "  .score-compare span{\n" +
                "    color:#FE5E47;\n" +
                "    margin-top: 8px;\n" +
                "  }\n" +
                "  .compareScore{\n" +
                "    display: flex;\n" +
                "    align-items: center;\n" +
                "  }\n" +
                "  .qrcode-content{\n" +
                "    position: absolute;\n" +
                "    left: 50px;\n" +
                "    bottom: 40px;\n" +
                "    display: flex;\n" +
                "    flex-direction: column;\n" +
                "    align-items: center;\n" +
                "    justify-content: center;\n" +
                "  }\n" +
                "  .qrcoe-img{\n" +
                "    width:160px;\n" +
                "    height:160px;\n" +
                "    overflow: hidden;\n" +
                "  }\n" +
                "  .qrcode-content span{\n" +
                "    color: #999;\n" +
                "    font-size: 20px;\n" +
                "    margin-top:10px;\n" +
                "  }\n" +
                "  .time-line{\n" +
                "    color: #333;\n" +
                "    font-size: 24px;\n" +
                "    position: absolute;\n" +
                "    right: 50px;\n" +
                "    bottom:36px;\n" +
                "  }\n" +
                "  .share-btn{\n" +
                "    position: absolute;\n" +
                "    z-index: 2;\n" +
                "    width:284px;\n" +
                "    height:76px;\n" +
                "    left:180px;\n" +
                "    right:180px;\n" +
                "    bottom: 240px;\n" +
                "  }\n" +
                "</style>\n" +
                "\n" +
                "<body>\n" +
                "  <div class=\"report-shareInfo\">\n" +
                "    <img class='title-bg' src='https://file.5rs.me/oss/uploadfe/png/0278d5cff4ee667fc973000de2460b4b.png' />\n" +
                "    <div class=\"report-content\">\n" +
                "      <div class=\"user-info\">\n" +
                "        <div class=\"head-url\"></div>\n" +
                "        <div class=\"user-right\">\n" +
                "          <div class=\"username\">\n" +
                "            "+wechat.getNickName()+"\n" +
                "          </div>\n" +
                "          <div class=\"loginDays\">\n" +
                "            书僮小睿已陪伴我<span>"+ wechat.getLoginDays() +"天</span>\n" +
                "          </div>\n" +
                "        </div>\n" +
                "      </div>\n" +
                "      <div class=\"score-content\">\n" +
                "        <span class=\"score-tips\">综合评分</span>\n" +
                "        <div class=\"score\">"+thisWeekReport.getScore()+"<span class=\"danwei\">分</span></div>\n" +
                "      </div>\n" +
                "      <div class=\"score-compare\">\n" +
                "        <div>当前阅读评估分值超过了</div>\n" +
                "        <div class=\"compareScore\"><span>"+thisWeekReport.getCompareUserRatio()+"%</span>的用户</div>\n" +
                "      </div>\n" +
                "      <div class=\"qrcode-content\">\n" +
                "        <img class=\"qrcoe-img\" src='https://file.5rs.me/oss/uploadfe/png/52b9033dd2e80d059c12a29204ca9b45.png' />\n" +
                "        <span>识别二维码进入小程序</span>\n" +
                "      </div>\n" +
                "      <div class=\"time-line\">"+DateUtils.formatDate(thisWeekReport.getBeginDate(), "yyyy/MM/dd")+"至"+DateUtils.formatDate(thisWeekReport.getEndDate(), "MM/dd")+"</div>\n" +
                "      <!-- <img class=\"share-btn\" src='https://file.5rs.me/oss/uploadfe/png/a11217df439f101c34737c360da02f17.png' /> -->\n" +
                "    </div>\n" +
                "  </div>\n" +
                "</body>\n" +
                "\n" +
                "</html>";
    }

}
