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

import com.pcloud.book.applet.biz.AppletUserBookcaseBiz;
import com.pcloud.book.book.constant.BookConstant;
import com.pcloud.book.book.dao.BookDao;
import com.pcloud.book.consumer.channel.QrcodeSceneConsr;
import com.pcloud.book.es.biz.ESBookAndAdviserBiz;
import com.pcloud.book.es.entity.ESBookAndAdviser;
import com.pcloud.book.es.repository.BookAndAdviserRepository;
import com.pcloud.book.group.biz.BookGroupBiz;
import com.pcloud.book.util.common.ThreadPoolUtils;
import com.pcloud.book.util.common.YesOrNoEnums;
import com.pcloud.book.util.properties.BookProps;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.string.StringUtil;

import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import lombok.extern.slf4j.Slf4j;

/**
 * @Description
 * @Author ruansiyuan
 * @Date 2020/4/13 12:21
 **/
@Component("esBookAndAdviserBiz")
@Slf4j
public class ESBookAndAdviserBizImpl implements ESBookAndAdviserBiz {

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

    @Autowired
    private BookDao bookDao;
    @Autowired
    private BookAndAdviserRepository bookAndAdviserRepository;
    @Autowired
    private AppletUserBookcaseBiz appletUserBookcaseBiz;
    @Autowired
    private QrcodeSceneConsr qrcodeSceneConsr;
    @Autowired
    private BookGroupBiz bookGroupBiz;

    @ParamLog("导入全部book和bookAdviser")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addAllBookAndAdviserToES() {
        ThreadPoolUtils.OTHER_THREAD_POOL.execute(() -> {
            Integer count = bookDao.count();
            LOGGER.info("总数:" + count);
            if (null == count || count <= 0) {
                return;
            }
            Long maxId = 0L;
            Integer index = 0;
            Integer offset = 10000;
            List<ESBookAndAdviser> list;
            while (index * offset < count) {
                list = bookDao.findAllBookAndAdviser(maxId, offset);
                if (ListUtils.isEmpty(list)) {
                    break;
                }
                fillInfo(list,null);
                bookAndAdviserRepository.save(list);
                maxId = Long.valueOf(list.get(list.size() - 1).getBookId());
                index += 1;
                list.clear();
            }
        });
    }

    private void fillInfo(List<ESBookAndAdviser> list, List<Long> bookIds){
        //书刊访问量
        Map<String, Integer> userCountMap = appletUserBookcaseBiz.mapBookUserCountList(bookIds);
        //书刊资源数量(二维码)
        Map<String, Integer> resourceCountMap = qrcodeSceneConsr.mapServeCount4Applet(bookIds);
        //书刊资源数量(社群书)
        Map<String, Integer> bookGroupResourceCountMap = bookGroupBiz.mapServeCount4Applet(bookIds);
        for (ESBookAndAdviser bookAndAdviser : list){
            String key = bookAndAdviser.getBookId() + "-" + bookAndAdviser.getAdviserId() + "-" + bookAndAdviser.getChannelId();
            Integer resourceCount=0;
            if (!MapUtils.isEmpty(userCountMap) && userCountMap.containsKey(key)){
                bookAndAdviser.setBookUserCount(userCountMap.get(key));
            }
            if (!MapUtils.isEmpty(resourceCountMap) && resourceCountMap.containsKey(key)){
                resourceCount = resourceCountMap.get(key);
            }
            if (!MapUtils.isEmpty(bookGroupResourceCountMap) && bookGroupResourceCountMap.containsKey(key)) {
                resourceCount = resourceCount + bookGroupResourceCountMap.get(key);
            }
            bookAndAdviser.setResourceCount(resourceCount);
        }
    }

    @ParamLog("更新书和编辑书")
    @Override
    public void updateBookAndAdviserToES(List<Long> bookIds) {
        if (ListUtils.isEmpty(bookIds)) {
            return;
        }
        try {
            List<ESBookAndAdviser> list = bookDao.findBookAndAdviserByBookIds(bookIds);
            filterBooks(list);
            fillInfo(list,bookIds);
            if (ListUtils.isEmpty(list)){
                return;
            }
            bookAndAdviserRepository.save(list);
        }catch (Exception e){
            LOGGER.error("更新书和编辑书出错："+bookIds.toString());
        }

    }

    private void filterBooks(List<ESBookAndAdviser> books) {
        if ((ListUtils.isEmpty(books))){
            return;
        }
        Iterator<ESBookAndAdviser> iterator =  books.iterator();
        while (iterator.hasNext()) {
            ESBookAndAdviser esBookAndAdviser = iterator.next();
            String bookName = esBookAndAdviser.getBookName();
            if (StringUtil.isEmpty(bookName)){
                iterator.remove();
            }
            if (bookName.matches("^[`~!@#$%^&*()+=|{}:;\\[\\].<>/\\\\?~！@#￥%……（）——+|{}【】‘；：”“’。，,、？0123456789]+$") ||
                    bookName.matches("(.*)([哈]{4,})(.*)") ||
                    bookName.matches("(.*)([或]{4,})(.*)") ||
                bookName.matches("(.*)(红榜)(.*)")){
                iterator.remove();
            }
        }
    }

    @Override
    public Page<ESBookAndAdviser> getAdviserBooks4ES(String grayStatus, String keyword, Long templetId, Long secondTempletId, Integer currentPage, Integer numPerPage) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .filter(QueryBuilders.termQuery("isBookDelete", 0))
                .filter(Objects.isNull(templetId) ? QueryBuilders.boolQuery() : QueryBuilders.termQuery("templetId", templetId))
                .filter(Objects.isNull(secondTempletId) ? QueryBuilders.boolQuery() : QueryBuilders.termQuery("secondTempletId", secondTempletId));
        BoolQueryBuilder should = QueryBuilders.boolQuery()
                .should(StringUtil.isEmpty(keyword) ? QueryBuilders.boolQuery() : QueryBuilders.wildcardQuery("bookName", "*" + keyword + "*"))
                .should(StringUtil.isEmpty(keyword) ? QueryBuilders.boolQuery() : QueryBuilders.wildcardQuery("isbn", "*" + keyword + "*"));
        BoolQueryBuilder should1 = QueryBuilders.boolQuery()
                .should(QueryBuilders.termQuery("isBookAdviserDelete", 0))
                .should(QueryBuilders.termQuery("isAdviserBook", 0));
        // 审核通过之后屏蔽掉测试编辑的书刊
        BoolQueryBuilder adviserIdBuilder = QueryBuilders.boolQuery();
        if (YesOrNoEnums.YES.getCode().equals(grayStatus)) {
            if ("test".equalsIgnoreCase(BookProps.getSystemEnv())) {
                adviserIdBuilder = QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("adviserId", 1404));
            }
            if ("uat".equalsIgnoreCase(BookProps.getSystemEnv())) {
                adviserIdBuilder = QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("adviserId", 12829));
            }
            if ("pro".equalsIgnoreCase(BookProps.getSystemEnv())) {
                adviserIdBuilder = QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("adviserId", 1362));
            }
        }
        boolQueryBuilder.must(should);
        boolQueryBuilder.must(should1);
        boolQueryBuilder.must(adviserIdBuilder);
        Sort sort=new Sort(Sort.Direction.DESC, "isAdviserBook","lastModifiedDate", "bookId");
        PageRequest pageRequest = new PageRequest(currentPage, numPerPage,sort);
        Page<ESBookAndAdviser> search = bookAndAdviserRepository.search(boolQueryBuilder, pageRequest);
        return search;
    }

    @Override
    public Page<ESBookAndAdviser> getESAdviserBooks4Applet(String grayStatus, String keyword, List<Long> templetIds, List<Long> graLabelIds, List<Long> subLabelIds, Integer currentPage, Integer numPerPage, List<Long> scecondTempletIds) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .filter(QueryBuilders.termQuery("isBookDelete", 0))
                .filter(ListUtils.isEmpty(templetIds) ? QueryBuilders.boolQuery() : QueryBuilders.termsQuery("templetId", templetIds));
        BoolQueryBuilder should = QueryBuilders.boolQuery()
                .should(StringUtil.isEmpty(keyword) ? QueryBuilders.boolQuery() : QueryBuilders.wildcardQuery("bookName",  keyword))
                .should(StringUtil.isEmpty(keyword) ? QueryBuilders.boolQuery() : QueryBuilders.wildcardQuery("isbn", "*" + keyword + "*"));
        BoolQueryBuilder should1 = QueryBuilders.boolQuery()
                .should(QueryBuilders.termQuery("isBookAdviserDelete", 0))
                .should(QueryBuilders.termQuery("isAdviserBook", 0));
        //（年级&&科目）||二级分类
        BoolQueryBuilder must1 = QueryBuilders.boolQuery()
                .filter(ListUtils.isEmpty(graLabelIds) ? QueryBuilders.boolQuery() : QueryBuilders.termsQuery("graLabelId", graLabelIds))
                .filter(ListUtils.isEmpty(subLabelIds) ? QueryBuilders.boolQuery() : QueryBuilders.termsQuery("subLabelId", subLabelIds));
        BoolQueryBuilder must2 = QueryBuilders.boolQuery().filter(ListUtils.isEmpty(scecondTempletIds) ? QueryBuilders.boolQuery() : QueryBuilders.termsQuery("secondTempletId", scecondTempletIds));
        BoolQueryBuilder should2 = QueryBuilders.boolQuery().should(must1).should(must2);
        // 审核通过之后屏蔽掉测试编辑的书刊
        BoolQueryBuilder adviserIdBuilder = QueryBuilders.boolQuery();
        if (YesOrNoEnums.YES.getCode().equals(grayStatus)) {
            if ("test".equalsIgnoreCase(BookProps.getSystemEnv())) {
                for (Long adviserId :  BookConstant.TEST_ADVISERS){
                    adviserIdBuilder = QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("adviserId", adviserId));
                    boolQueryBuilder.must(adviserIdBuilder);
                }
            }
            if ("uat".equalsIgnoreCase(BookProps.getSystemEnv())) {
                for (Long adviserId :  BookConstant.UAT_ADVISERS){
                    adviserIdBuilder = QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("adviserId", adviserId));
                    boolQueryBuilder.must(adviserIdBuilder);
                }
            }
            if ("pro".equalsIgnoreCase(BookProps.getSystemEnv())) {
                for (Long adviserId :  BookConstant.PROD_ADVISERS){
                    adviserIdBuilder = QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("adviserId", adviserId));
                    boolQueryBuilder.must(adviserIdBuilder);
                }
            }
        }
        boolQueryBuilder.must(should);
        boolQueryBuilder.must(should1);
        if (!ListUtils.isEmpty(scecondTempletIds)) {
            if (ListUtils.isEmpty(graLabelIds) && ListUtils.isEmpty(subLabelIds)) {
                boolQueryBuilder.must(must2);
            } else {
                boolQueryBuilder.must(should2);
            }
        } else if (!ListUtils.isEmpty(graLabelIds) || !ListUtils.isEmpty(subLabelIds)) {
            boolQueryBuilder.must(must1);
        }
        Sort sort = new Sort(Sort.Direction.DESC, "bookUserCount", "resourceCount", "isAdviserBook", "lastModifiedDate", "bookId");
        PageRequest pageRequest = new PageRequest(currentPage, numPerPage, sort);
        Page<ESBookAndAdviser> search = bookAndAdviserRepository.search(boolQueryBuilder, pageRequest);
        return search;
    }

    @Override
    public void deleteAdviserBooks4ES() {
        Page<ESBookAndAdviser> search = getEsBookAndAdvisers();
        while (search.getContent().size() > 0){
            search.getContent().stream().forEach(e -> log.info("从es中删除的书是" + e.getVerLabelId() + ":" + e.getBookName()) );
            bookAndAdviserRepository.delete(search.getContent());
            search = getEsBookAndAdvisers();
        }
    }

    @Override
    @ParamLog("删除选中的书籍")
    public void deleteChoosedAdviserBooks4ES(String keyword) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("bookName", keyword));
        PageRequest pageRequest = new PageRequest(0, 100);
        Page<ESBookAndAdviser> search = bookAndAdviserRepository.search(boolQueryBuilder, pageRequest);
        if (search.getSize() > 0){
            search.getContent().stream().forEach(e -> log.info("从es中删除的书是" + e.getVerLabelId() + ":" + e.getBookName()) );
            bookAndAdviserRepository.delete(search.getContent());
        }
    }

    private Page<ESBookAndAdviser> getEsBookAndAdvisers() {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        BoolQueryBuilder should1 = QueryBuilders.boolQuery()
                .should(QueryBuilders.termQuery("isBookAdviserDelete", 0))
                .should(QueryBuilders.termQuery("isAdviserBook", 0));
        BoolQueryBuilder should2 = QueryBuilders.boolQuery()
                .should(QueryBuilders.regexpQuery("bookName","([`~!@#$%^&*()+=|{}:;\\[\\].<>/\\\\?~！@#￥%……（）——+|{}【】‘；：”“’。，,、？]+)"))
                .should(QueryBuilders.regexpQuery("bookName","([0123456789]+)"))
                .should(QueryBuilders.regexpQuery("bookName","((.*)(["+ BookConstant.HANZI+"]){4,}(.*))"))
                .should(QueryBuilders.regexpQuery("bookName","("+"(.*)(红榜)(.*)"+")"));
        boolQueryBuilder.must(should1);
        boolQueryBuilder.must(should2);
        PageRequest pageRequest = new PageRequest(0, 10);
        return bookAndAdviserRepository.search(boolQueryBuilder, pageRequest);
    }

}
