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

import com.google.common.collect.Lists;

import com.pcloud.book.applet.biz.AppletRecordAggrStatisBiz;
import com.pcloud.book.applet.biz.AppletRecordBiz;
import com.pcloud.book.applet.biz.ServeCollectBiz;
import com.pcloud.book.applet.contants.AppletConstants;
import com.pcloud.book.applet.dao.AppletRecordDao;
import com.pcloud.book.applet.dao.AppletRecordSevenDayDao;
import com.pcloud.book.applet.dto.AppletRecordDTO;
import com.pcloud.book.applet.entity.AppletRecord;
import com.pcloud.book.applet.entity.AppletRecordSevenDay;
import com.pcloud.book.applet.entity.ServeCollect;
import com.pcloud.book.applet.enums.AppletRankTypeEnum;
import com.pcloud.book.applet.enums.AppletRecordTypeEnum;
import com.pcloud.book.applet.enums.AppletSourceTypeEnum;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.consumer.label.LabelConsr;
import com.pcloud.book.consumer.reader.ReaderConsr;
import com.pcloud.book.group.biz.ResourcePageBiz;
import com.pcloud.book.group.constant.ResourcePageConstants;
import com.pcloud.book.group.dao.WeworkTeacherFriendRecordDao;
import com.pcloud.book.mapper.clickhouse.AppletRecordCHMapper;
import com.pcloud.book.util.common.YesOrNoEnums;
import com.pcloud.book.util.properties.BookProps;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.utils.BeanUtils;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.cache.redis.JedisClusterUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.readercenter.common.enums.YesOrNoNumEnum;
import com.pcloud.readercenter.userlabel.dto.UserGradeLabelIdDTO;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;

@Service("appletRecordAggrStatisBiz")
public class AppletRecordAggrStatisBizImpl implements AppletRecordAggrStatisBiz {

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

    @Autowired
    private AppletRecordCHMapper appletRecordCHMapper;
    @Autowired
    private AppletRecordBiz appletRecordBiz;
    @Autowired
    private AppletRecordDao appletRecordDao;
    @Autowired
    private WeworkTeacherFriendRecordDao weworkTeacherFriendRecordDao;
    @Autowired
    private ServeCollectBiz serveCollectBiz;
    @Autowired
    private ResourcePageBiz resourcePageBiz;
    @Autowired
    private AppletRecordSevenDayDao appletRecordSevenDayDao;
    @Autowired
    private ReaderConsr readerConsr;
    @Autowired
    private LabelConsr labelConsr;

    @Override
    public PageBeanNew getAggrStatis(Long wechatUserId, String keyword, Integer sourceType, Integer rankType, Integer currentPage, Integer numPerPage) {
        String cacheKey = MessageFormat.format("{0}_{1}_{2}", AppletConstants.APPLET_RESOURCE_AGGR_STATIS, sourceType, rankType);
        List<AppletRecordDTO> aggrStatis = JedisClusterUtils.getJsonList(cacheKey, AppletRecordDTO.class);
        if(ListUtils.isEmpty(aggrStatis)){
            return new PageBeanNew(currentPage, numPerPage, 0, Lists.newArrayList());
        }

        if(StringUtils.isNotEmpty(keyword)){
            List<AppletRecordDTO> collect = aggrStatis.stream().filter(x -> x.getFromName().contains(keyword)).collect(Collectors.toList());
            if(CollectionUtil.isEmpty(collect)){
                return new PageBeanNew(currentPage, numPerPage, 0, Lists.newArrayList());
            }
            List<AppletRecordDTO> list = aggrStatis.stream().filter(x -> x.getFromName().contains(keyword)).skip(currentPage * numPerPage).limit(numPerPage).collect(Collectors.toList());
            fillCollect(wechatUserId, list);
            return new PageBeanNew(currentPage, numPerPage, collect.size(), list);
        } else {
            List<AppletRecordDTO> list = aggrStatis.stream().skip(currentPage * numPerPage).limit(numPerPage).collect(Collectors.toList());
            fillCollect(wechatUserId, list);
            return new PageBeanNew(currentPage, numPerPage, aggrStatis.size(), list);
        }
    }

    @Override
    public void syncDataAndUpdateCache(String date){
        fixAppletRecordDataSync4CH(date);
        updateAggrStatisCache();
    }

    /**
     * 将 clickHouse 的资源排行信息加入到 redis 缓存
     */
    @Override
    public void updateAggrStatisCache() {
        for (AppletSourceTypeEnum sourceType : AppletSourceTypeEnum.values()) {
            for (AppletRankTypeEnum rankType : AppletRankTypeEnum.values()) {
                String cacheKey = MessageFormat.format("{0}_{1}_{2}", AppletConstants.APPLET_RESOURCE_AGGR_STATIS, sourceType.value, rankType.value);
                HashMap<String, Object> paramMap = new HashMap<>();
                paramMap.put("offset", 0);
                paramMap.put("limit", 100);
                addDateCondition(rankType.value, paramMap);
                addTypeCodeCondition(sourceType.value, paramMap);
                List<AppletRecordDTO> aggrStatis = null;
                // 导师需要在另外表里查询
                if(sourceType.value == AppletSourceTypeEnum.ANSWER_1V1.value){
                    paramMap.put("recordType", AppletRecordTypeEnum.WX_WORK_TEACHER.value);
                    aggrStatis = weworkTeacherFriendRecordDao.getAggrStatis(paramMap);
                } else {
                    aggrStatis = appletRecordCHMapper.getAggrStatis(paramMap);
                }
                // 加载其它数据
                appletRecordBiz.fillAppletRecord(aggrStatis, YesOrNoNumEnum.NO.getValue());
                // 删除部分不存在的数据
                aggrStatis = aggrStatis.stream().filter(x->x.getSourceDelete() == 0).collect(Collectors.toList());
                // 设置缓存
                JedisClusterUtils.setJsonList(cacheKey, aggrStatis, 3600 * 24);
            }
        }
    }

    @Override
    public void fixAppletRecordDataSync4CH(String createDate) {
        if(StringUtil.isEmpty(createDate)){
            createDate = DateUtils.getShortDateStr(DateUtils.getDate(-1));
        }
        // 分批插入的大小
        Integer finalBatchSize = 1000;
        final List<AppletRecord> result = new LinkedList<>();

        appletRecordDao.fixAppletRecordDataSync4CH(createDate, new ResultHandler<AppletRecord>(){
            @Override
            public void handleResult(ResultContext<? extends AppletRecord> resultContext) {
                result.add(resultContext.getResultObject());
                if(result.size() == finalBatchSize){
                    appletRecordCHMapper.batchInsert(result);
                    LOGGER.info("[AppletRecordAggrStatisBizImpl.fixDataSync4CH] CH数据同步，NUM：{},数据满1000条，插入一次", resultContext.getResultCount());
                    result.clear();
                }
            }
        });

        if(CollUtil.isNotEmpty(result)){
            appletRecordCHMapper.batchInsert(result);
        }
        appletRecordCHMapper.optimize();
        LOGGER.info("[AppletRecordAggrStatisBizImpl.fixDataSync4CH] CH数据同步结束");
    }



    private void addDateCondition(Integer rankType, HashMap<String, Object> paramMap) {
        if(rankType == 2){
            // 月榜
            paramMap.put("beginDate", DateUtils.formatDate(DateUtils.addDay(DateUtils.getDayBegin(), -30)));
            paramMap.put("endDate", DateUtils.formatDate(DateUtils.addDay(DateUtils.getDayEnd(), -1)));
        }
        if(rankType == 3){
            // 周榜
            paramMap.put("beginDate", DateUtils.formatDate(DateUtils.addDay(DateUtils.getDayBegin(), -7)));
            paramMap.put("endDate", DateUtils.formatDate(DateUtils.addDay(DateUtils.getDayEnd(), -1)));
        }
    }

    private void addTypeCodeCondition(Integer sourceType, HashMap<String, Object> paramMap) {
        List<Map> recordTypes = Lists.newArrayList();
        HashMap<String, Object> recordTypeMap;
        switch (sourceType){
            case 1:
                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.PRODUCT.value);
                recordTypeMap.put("typeCodes", Lists.newArrayList("VIDEO_SCHEDULE", "AUDIO", "AUDIO_SCHEDULE", "VIDEO", "SCHEDULE", "TUTORIAL"));
                recordTypes.add(recordTypeMap);

                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.APP.value);
                recordTypeMap.put("typeCodes", Lists.newArrayList("MATCH_LISTEN", "AUDIO", "LISTEN", "VIDEO", "LIVE_TIMETABLE"));
                recordTypes.add(recordTypeMap);

                paramMap.put("recordTypes", recordTypes);
                break;
            case 2:
                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.NEWS.value);
                recordTypes.add(recordTypeMap);

                paramMap.put("recordTypes", recordTypes);
                break;
            case 3:
                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.PRODUCT.value);
                recordTypeMap.put("typeCodes", Lists.newArrayList("PRETEST", "FORMAT", "LINK", "ARTICLE", "PDF"));
                recordTypes.add(recordTypeMap);

                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.APP.value);
                recordTypeMap.put("typeCodes", Lists.newArrayList("GROUP", "ZSCORE", "BOOKCARD", "ITEM_BANK", "SPECIAL", "RECITE_WORD", "BOOK", "WORD_DICTATION", "ORAL_EVALUATION", "BOOK_CLICK", "STROKE_ORDER"));
                recordTypes.add(recordTypeMap);

                paramMap.put("recordTypes", recordTypes);
                break;
            case 4:
                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.BOOK_RECOMMEND.value);
                recordTypes.add(recordTypeMap);

                paramMap.put("recordTypes", recordTypes);
                break;
            case 5:
                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.PRODUCT.value);
                recordTypeMap.put("typeCodes", Lists.newArrayList("VIDEO_SCHEDULE", "AUDIO_SCHEDULE", "PDF"));
                recordTypes.add(recordTypeMap);

                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.APP.value);
                recordTypeMap.put("typeCodes", Lists.newArrayList("ANSWER", "TEST_PAPER", "TEACH_RESOURCE", "COURSE_WARE", "PDF"));
                recordTypes.add(recordTypeMap);

                paramMap.put("recordTypes", recordTypes);
                break;
            case 6:
                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.ADVISER_GROUP.value);
                recordTypes.add(recordTypeMap);

                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.MODEL_GROUP.value);
                recordTypes.add(recordTypeMap);

                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.THIRD_GROUP.value);
                recordTypes.add(recordTypeMap);

                paramMap.put("recordTypes", recordTypes);
                break;
            case 7:
                /* recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.WX_WORK_TEACHER.value);
                recordTypes.add(recordTypeMap);

                paramMap.put("recordTypes", recordTypes); */
                break;
            case 8:
                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.PRODUCT.value);
                recordTypeMap.put("typeCodes", Lists.newArrayList("ATTENDANCE_TASK"));
                recordTypes.add(recordTypeMap);

                recordTypeMap = new HashMap<>();
                recordTypeMap.put("recordType", AppletRecordTypeEnum.APP.value);
                recordTypeMap.put("typeCodes", Lists.newArrayList("CLOCK", "WISH", "FLAG", "TEST"));
                recordTypes.add(recordTypeMap);

                paramMap.put("recordTypes", recordTypes);
                break;
        }
    }

    private void fillCollect(Long wechatUserId, List<AppletRecordDTO> list) {
        List<ServeCollect> serveCollectList = serveCollectBiz.getList4RightsSettingByWechatUserId(wechatUserId);
        if (ListUtils.isEmpty(serveCollectList)) {
            return;
        }
        List<ServeCollect> collect4Product = serveCollectList.stream().filter(e -> Objects.equals(e.getServeType(), AppletRecordTypeEnum.PRODUCT.value)).collect(Collectors.toList());
        List<ServeCollect> collect4App = serveCollectList.stream().filter(e -> Objects.equals(e.getServeType(), AppletRecordTypeEnum.APP.value)).collect(Collectors.toList());
        Map<Long, ServeCollect> serveCollectMap4Product = new HashMap<>();
        Map<Long, ServeCollect> serveCollectMap4App = new HashMap<>();
        if (!ListUtils.isEmpty(collect4Product)) {
            serveCollectMap4Product = collect4Product.stream().collect(Collectors.toMap(e -> e.getServeId(), a -> a, (k1, k2) -> k1));
        }
        if (!ListUtils.isEmpty(collect4App)) {
            serveCollectMap4App = collect4App.stream().collect(Collectors.toMap(e -> e.getServeId(), a -> a, (k1, k2) -> k1));
        }
        List<AppletRecordDTO> productOrApps = list.stream().filter(e -> Objects.equals(e.getRecordType(), AppletRecordTypeEnum.PRODUCT.value) ||
                Objects.equals(e.getRecordType(), AppletRecordTypeEnum.APP.value)).collect(Collectors.toList());
        if (!ListUtils.isEmpty(productOrApps)) {
            for (AppletRecordDTO item : productOrApps) {
                if (Objects.equals(item.getRecordType(), AppletRecordTypeEnum.PRODUCT.value) && MapUtils.isNotEmpty(serveCollectMap4Product) &&
                        null != serveCollectMap4Product.get(item.getFromId())) {
                    item.setIsCollect(YesOrNoEnums.YES.getValue());
                } else if (Objects.equals(item.getRecordType(), AppletRecordTypeEnum.APP.value) && MapUtils.isNotEmpty(serveCollectMap4App) &&
                        null != serveCollectMap4App.get(item.getFromId())) {
                    item.setIsCollect(YesOrNoEnums.YES.getValue());
                }
            }
        }
    }


    /**
     * 将 clickHouse 的资源排行加入到 数据库
     */
    @Override
    public void updateH5Resource() {
        //资源广场模块
        for (ResourcePageConstants.ResourceSourceTypeEnum sourceTypeEnum : ResourcePageConstants.ResourceSourceTypeEnum.values()) {
            Map<String,Object> paramMap = new HashMap<>();
            paramMap.put("offset", 0);
            paramMap.put("limit", 1000);
            if ("pro".equals(BookProps.getSystemEnv())) {
                paramMap.put("beginDate", DateUtils.formatDate(DateUtils.addDay(DateUtils.getDayBegin(), -7)));
            }
            paramMap.put("endDate", DateUtils.formatDate(DateUtils.addDay(DateUtils.getDayEnd(), -1)));
            paramMap.put("sourceKeywords", Arrays.asList(sourceTypeEnum.getKeywords()));

            //资源广场模块搜索-7天内扫码量高的资源
            List<AppletRecordDTO> sevenDaysourceAggrStatis = appletRecordCHMapper.getAggrStatis4H5(paramMap);
            if (ListUtils.isEmpty(sevenDaysourceAggrStatis)) {
                continue;
            }
            List<Long> fromIdList = sevenDaysourceAggrStatis.stream().filter(s->s!=null && s.getFromId()>0).map(AppletRecordDTO::getFromId).collect(Collectors.toList());
            Map<String,Object> map = new HashMap<>();
            map.put("endDate", DateUtils.formatDate(DateUtils.addDay(DateUtils.getDayEnd(), -1)));
            map.put("fromIdList", fromIdList);
            
            //7天内扫码量高的资源的总扫码量
            List<AppletRecordDTO> sourceAggrStatis = appletRecordCHMapper.getAggrStatis4H5(map);
            appletRecordBiz.fillAppletRecord(sourceAggrStatis, YesOrNoNumEnum.NO.getValue());
            sourceAggrStatis = sourceAggrStatis.stream().filter(x -> x.getSourceDelete() == 0).collect(Collectors.toList());
            if (ListUtils.isEmpty(sourceAggrStatis)) {
                continue;
            }
            appletRecordSevenDayDao.deleteBySourceType(sourceTypeEnum.getCode());
            List<AppletRecordSevenDay> serveList = new ArrayList<>();
            BeanUtils.copyListProperties(sourceAggrStatis, serveList,AppletRecordSevenDay.class);
            serveList.forEach(s->s.setSourceType(sourceTypeEnum.getCode()));
            appletRecordSevenDayDao.insert(serveList);
        }
    }

    @Override
    public PageBeanNew getResource4H5(Long wechatUserId, Long officialAccountsId, String keyword, Integer sourceType, Integer currentPage, Integer numPerPage) {
        if (null == sourceType && StringUtil.isEmpty(keyword)) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "缺少参数");
        }
        //最多查询50个
        Integer maxCount = 50;
        List<AppletRecordDTO> countList;
        if (StringUtils.isNotEmpty(keyword)) {
            //关键词搜索
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("sourceKeywords", Arrays.asList(keyword));
            paramMap.put("offset", 0);
            paramMap.put("limit", maxCount);
            paramMap.put("endDate", DateUtils.formatDate(DateUtils.addDay(DateUtils.getDayEnd(), -1)));
            countList = appletRecordCHMapper.getAggrStatis4H5(paramMap);

        } else {
            //无关键词-根据学龄段搜索,序优先匹配同年级的资源
            UserGradeLabelIdDTO userGradeLabelIdDTO = readerConsr.getUserGrade(wechatUserId, officialAccountsId);
            //学龄段标签, 年级标签
            Long parentLabel = 1L;
            Long gradeLabelId = null;
            if (null != userGradeLabelIdDTO && null != userGradeLabelIdDTO.getLabelId()) {
                parentLabel = (null == userGradeLabelIdDTO.getParentId() || userGradeLabelIdDTO.getParentId() == 0) ?
                        userGradeLabelIdDTO.getLabelId() : userGradeLabelIdDTO.getParentId();
                gradeLabelId = userGradeLabelIdDTO.getLabelId();
            }
            //年龄段下所有年级
            List<Long> gradeLabelIds = readerConsr.getUserGradeIdByParentId(parentLabel);
            //年级排序,当前年级在前
            List<Long> orderFieldIds = new ArrayList<>(Arrays.asList(gradeLabelId));
            if (!ListUtils.isEmpty(gradeLabelIds) && gradeLabelIds.contains(gradeLabelId)) {
                gradeLabelIds.remove(gradeLabelId);
            }
            orderFieldIds.addAll(gradeLabelIds);
            countList = appletRecordSevenDayDao.getResourceByGrade4H5(sourceType, orderFieldIds, maxCount);
        }
        if (ListUtils.isEmpty(countList)) {
            return new PageBeanNew(currentPage, numPerPage, 0, Lists.newArrayList());
        }
        appletRecordBiz.fillAppletRecord(countList, YesOrNoNumEnum.NO.getValue());
        countList = countList.stream().filter(x -> x.getSourceDelete() == 0).collect(Collectors.toList());
        if (ListUtils.isEmpty(countList)) {
            return new PageBeanNew(currentPage, numPerPage, 0, Lists.newArrayList());
        }
        List<AppletRecordDTO> recordDTOS = countList.stream().skip(currentPage * numPerPage).limit(numPerPage).collect(Collectors.toList());
        fillLabel(recordDTOS);
        PageBeanNew pageBeanNew = new PageBeanNew<>(currentPage, numPerPage, countList.size(), recordDTOS);
        return pageBeanNew;
    }


    private void fillLabel(List<AppletRecordDTO> recordList) {
        if (ListUtils.isEmpty(recordList)) {
            return;
        }
        List<Long> labelIds = new ArrayList<>();
        for (AppletRecordDTO appletRecordDTO : recordList) {
            if (null != appletRecordDTO.getProLabelId()) {
                labelIds.add(appletRecordDTO.getProLabelId());
            }
            if (null != appletRecordDTO.getDepLabelId()) {
                labelIds.add(appletRecordDTO.getDepLabelId());
            }
            if (null != appletRecordDTO.getPurLabelId()) {
                labelIds.add(appletRecordDTO.getPurLabelId());
            }
        }
        if (!ListUtils.isEmpty(labelIds)) {
            Map<Long, String> labelMap = labelConsr.getLabelName(labelIds);
            if (!MapUtils.isEmpty(labelMap)) {
                for(AppletRecordDTO appletRecordDTO : recordList){
                    if (null != appletRecordDTO.getProLabelId() && labelMap.containsKey(appletRecordDTO.getProLabelId())) {
                        appletRecordDTO.setProLabelName(labelMap.get(appletRecordDTO.getProLabelId()));
                    }
                    if (null != appletRecordDTO.getDepLabelId() && labelMap.containsKey(appletRecordDTO.getDepLabelId())) {
                        appletRecordDTO.setDepLabelName(labelMap.get(appletRecordDTO.getDepLabelId()));
                    }
                    if (null != appletRecordDTO.getPurLabelId() && labelMap.containsKey(appletRecordDTO.getPurLabelId())) {
                        appletRecordDTO.setPurLabelName(labelMap.get(appletRecordDTO.getPurLabelId()));
                    }
                }
            }
        }
    }
}
