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

import cn.hutool.core.map.MapUtil;
import com.google.common.collect.Lists;
import com.pcloud.book.applet.biz.AppletBookIgnorBiz;
import com.pcloud.book.book.dao.BookDao;
import com.pcloud.book.book.vo.request.BookSearchParamVO;
import com.pcloud.book.elasticsearch7.domain.dto.param.BookSearchDto;
import com.pcloud.book.elasticsearch7.domain.entity.Es7Book;
import com.pcloud.book.elasticsearch7.service.Es7BookSearchService;
import com.pcloud.book.elasticsearch7.service.Es7BookSyncService;
import com.pcloud.book.es.biz.ESBookAndAdviserBiz;
import com.pcloud.book.es.entity.ESBookAndAdviser;
import com.pcloud.book.rightsSetting.constants.RightsSettingConstant;
import com.pcloud.book.util.common.Converter;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.cache.redis.JedisClusterUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.universe.commons.paging.Pagination;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.pcloud.book.book.constant.BookConstant.IGNOR_BOOK_KEY;

/**
 * @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);

    private static final String NOT_FOUND_BOOK_ID_SELECT_KEY = "BOOK:ESBookAndAdviserBizImpl:getNotFoundBookId";
    private static final String NOT_FOUND_BOOK_ID_STATUS_SELECT_KEY = "BOOK:ESBookAndAdviserBizImpl:runStatus";

    @Autowired
    private BookDao bookDao;
    @Autowired
    private Es7BookSyncService es7BookSyncService;
    @Autowired
    private Es7BookSearchService es7BookSearchService;
    @Autowired
    private AppletBookIgnorBiz appletBookIgnorBiz;

    @ParamLog("导入全部book和bookAdviser")
    @Override
    public void addAllBookAndAdviserToES() {
        es7BookSyncService.asyncAllBooks();
    }

    @ParamLog("更新书和编辑书")
    @Override
    public void updateBookAndAdviserToES(List<Long> bookIds) {
        if (ListUtils.isEmpty(bookIds)) {
            return;
        }
        try {
            es7BookSyncService.updateBooksByIds(bookIds);
        }catch (Exception e){
            LOGGER.error("更新书和编辑书出错：{}", StringUtils.join(bookIds));
        }
    }

    @Override
    public Pagination<ESBookAndAdviser> getAdviserBooks4ES(String grayStatus, String keyword, Long templetId, Long secondTempletId, Long thirdTempletId, Integer currentPage, Integer numPerPage) {

        BookSearchDto dto = BookSearchDto.builder()
                .grayStatus(grayStatus).keyword(keyword).templetIds(Lists.newArrayList(templetId))
                .scecondTempletIds(Lists.newArrayList(secondTempletId)).thirdTempletIds(Lists.newArrayList(thirdTempletId))
                .build();
        dto.setCurrentPage(Optional.ofNullable(currentPage).orElse(0) + 1);
        dto.setPageSize(numPerPage);
        Pagination<Es7Book> data = es7BookSearchService.getAdviserBooks4ES(dto);

        return Converter.convert(data);
    }

    @Override
    public Pagination<ESBookAndAdviser> getESAdviserBooks4Applet(String grayStatus, String keyword, List<Long> templetIds, List<Long> graLabelIds,
                                                           List<Long> subLabelIds, Integer currentPage, Integer numPerPage, List<Long> scecondTempletIds, Integer isAdviserBook, List<Long> adviserIds, Long agentId) {

        BookSearchDto dto = BookSearchDto.builder()
                .grayStatus(grayStatus).keyword(keyword).templetIds(templetIds).graLabelIds(graLabelIds)
                .subLabelIds(subLabelIds).scecondTempletIds(scecondTempletIds).adviserIds(adviserIds)
                .ignoreBookIdList(getIgnoreBookIdList()).filterResourceCount(false)
                .build();
        dto.setCurrentPage(Optional.ofNullable(currentPage).orElse(0) + 1);
        dto.setPageSize(numPerPage);
        Pagination<Es7Book> data = es7BookSearchService.getESAdviserBooks4AppletV2(dto);

        return Converter.convert(data);
    }

    @Override
    public Pagination<ESBookAndAdviser> getESAdviserBooks4AppletV2(String grayStatus, String keyword, List<Long> templetIds, List<Long> graLabelIds,
                                                           List<Long> subLabelIds, Integer currentPage, Integer numPerPage, List<Long> scecondTempletIds, List<Long> adviserIds, Long agentId) {
        BookSearchDto dto = BookSearchDto.builder()
                .grayStatus(grayStatus).keyword(keyword).templetIds(templetIds).graLabelIds(graLabelIds)
                .subLabelIds(subLabelIds).scecondTempletIds(scecondTempletIds).adviserIds(adviserIds)
                .ignoreBookIdList(getIgnoreBookIdList()).isAdviserBook(true).filterResourceCount(true)
                .build();
        dto.setCurrentPage(Optional.ofNullable(currentPage).orElse(0) + 1);
        dto.setPageSize(numPerPage);
        Pagination<Es7Book> data = es7BookSearchService.getESAdviserBooks4AppletV2(dto);

        return Converter.convert(data);
    }

    private List<Long> getIgnoreBookIdList() {
        List<Long> bookIds = JedisClusterUtils.getJsonList(IGNOR_BOOK_KEY, Long.class);
        if (ListUtils.isEmpty(bookIds)) {
            bookIds = appletBookIgnorBiz.getAllIgnorBookIds();
            JedisClusterUtils.setJsonList(IGNOR_BOOK_KEY ,bookIds,3600 * 24);
        }
        return bookIds;
    }

    @Override
    public Pagination<ESBookAndAdviser> getESAdviserBooks4Answer(BookSearchParamVO vo) {
        BookSearchDto dto = BookSearchDto.builder()
                .grayStatus(vo.getGrayStatus()).keyword(vo.getKeyword()).isAdviserBook(true)
                .label1(vo.getLabel1()).label2(vo.getLabel2()).label3(vo.getLabel3())
                .build();
        dto.setCurrentPage(Optional.ofNullable(vo.getCurrentPage()).orElse(0) + 1);
        dto.setPageSize(Optional.ofNullable(vo.getNumPerPage()).orElse(10));
        Pagination<Es7Book> data = es7BookSearchService.getESAdviserBooks4Answer(dto);
        return Converter.convert(data);
    }

    @Override
    public Pagination<ESBookAndAdviser> getAdviserBooks4SeriesBook(String keyword, Integer currentPage, Integer numPerPage, List<Long> adviserIds,
                                                             Long agentId, Long subLabelId, Long graLabelId, String serialNumber, Long verLabelId, Long volLabelId) {
        //k12教育分类校验
        List<Long> templetIds = Arrays.asList(RightsSettingConstant.K12_TEMPLET_ID_NEW);

        BookSearchDto dto = BookSearchDto.builder().keyword(keyword).isAdviserBook(true)
                .adviserIds(adviserIds).templetIds(templetIds).serialNumber(serialNumber)
                .subLabelIds(Lists.newArrayList(subLabelId)).graLabelIds(Lists.newArrayList(graLabelId))
                .verLabelIds(Lists.newArrayList(verLabelId)).volLabelIds(Lists.newArrayList(volLabelId))
                .build();
        dto.setCurrentPage(Optional.ofNullable(currentPage).orElse(0) + 1);
        dto.setPageSize(Optional.ofNullable(numPerPage).orElse(10));
        Pagination<Es7Book> data = es7BookSearchService.getAdviserBooks4SeriesBook(dto);

        return Converter.convert(data);
    }

    @Override
    public Map<String, Object> getNotFoundBookId(String lastBookId) throws Exception {
        String lock = JedisClusterUtils.get(NOT_FOUND_BOOK_ID_SELECT_KEY);
        if(!StringUtil.isEmpty(lock)){
            throw new BizException(BizException.DB_DML_FAIL.getCode(), "请不要重复执行");
        }
        JedisClusterUtils.set(NOT_FOUND_BOOK_ID_SELECT_KEY, "lock", 3600);
        // 解除停止状态
        JedisClusterUtils.set(NOT_FOUND_BOOK_ID_STATUS_SELECT_KEY, "running", 3600);
        List<Long> notFoundBookIds = Lists.newArrayList();
        Integer pageNumber = 100;
        List<Long> esBookIds = null;
        List<Long> existsBookIds = null;

        String runStatus = "running";
        try {
            if(StringUtil.isEmpty(lastBookId)){
                lastBookId = "0";
            }
            while ("running".equalsIgnoreCase(runStatus)) {
                Pagination<Es7Book> data = es7BookSearchService.findGreaterThanBookIdBooks(Long.parseLong(lastBookId));
                List<Long> esContent = data.getList().stream().map(Es7Book::getBookId).collect(Collectors.toList());;
                if (esContent.size() > 0) {
                    // 循环每次查询100条
                    for (int i = 0; i < (esContent.size() % pageNumber == 0 ? esContent.size()/pageNumber : (esContent.size()/pageNumber+1)); i++) {
                        esBookIds = esContent.stream().skip(i * pageNumber).limit(pageNumber).map(Long::valueOf).collect(Collectors.toList());
                        if(ListUtils.isEmpty(esBookIds)){
                            continue;
                        }
                        // 查询，并筛选出不存在的数据
                        existsBookIds = bookDao.getByIds(esBookIds);
                        Thread.sleep(1);
                        if(ListUtils.isEmpty(existsBookIds)){
                            if(ListUtils.isEmpty(esBookIds)){
                                continue;
                            }
                            notFoundBookIds.addAll(esBookIds);
                        } else {
                            esBookIds.removeAll(existsBookIds);
                            if(ListUtils.isEmpty(esBookIds)){
                                continue;
                            }
                            notFoundBookIds.addAll(esBookIds);
                        }
                    }
                    lastBookId = String.valueOf(esContent.get(esContent.size()-1));
                } else {
                    runStatus = "complete";
                    break;
                }
                // 判断是否强制终止
                runStatus = JedisClusterUtils.get(NOT_FOUND_BOOK_ID_STATUS_SELECT_KEY);
            }
            return MapUtil.<String, Object>builder()
                    .put("runStatus", runStatus)
                    .put("lastBookId", lastBookId)
                    .put("notFoundBookIds", notFoundBookIds)
                    .put("msg", "stop".equalsIgnoreCase(runStatus) ? "执行被终止" : "执行完成")
                    .build();
        } catch (Exception e){
            LOGGER.info("getNotFoundBookId 执行出现异常，notFoundBookIds：" + notFoundBookIds.toString(), e);
            return MapUtil.<String, Object>builder()
                    .put("runStatus", runStatus)
                    .put("lastBookId", lastBookId)
                    .put("notFoundBookIds", notFoundBookIds)
                    .put("msg", "执行出现异常")
                    .build();
        } finally {
            // 移除执行锁
            JedisClusterUtils.del(NOT_FOUND_BOOK_ID_SELECT_KEY);
        }
    }

    @Override
    public void stopNotFoundBookId() {
        JedisClusterUtils.set(NOT_FOUND_BOOK_ID_STATUS_SELECT_KEY, "stop", 3600);
    }

    @Override
    public Pagination<ESBookAndAdviser> getESBooksOrderByChose(String keyword, List<Long> choseBookIdList, Integer currentPage, Integer numPerPage) {

        BookSearchDto dto = BookSearchDto.builder().keyword(keyword).build();
        dto.setCurrentPage(Optional.ofNullable(currentPage).orElse(0) + 1);
        dto.setPageSize(numPerPage);
        Pagination<Es7Book> data = es7BookSearchService.getESBooksOrderByChose(dto);

        return Converter.convert(data);
    }
}
