package cn.reghao.tnb.content.app.vod.service.impl;

import cn.reghao.jutil.jdk.web.db.Page;
import cn.reghao.jutil.jdk.web.db.PageList;
import cn.reghao.tnb.common.auth.UserContext;
import cn.reghao.tnb.content.api.dto.VideoCard;
import cn.reghao.tnb.content.app.vod.db.mapper.SearchRecordMapper;
import cn.reghao.tnb.content.app.vod.db.mapper.VideoPostMapper;
import cn.reghao.tnb.content.app.vod.model.dto.SearchCriteria;
import cn.reghao.tnb.content.app.vod.model.po.SearchRecord;
import cn.reghao.tnb.content.app.vod.model.po.VideoPost;
import cn.reghao.tnb.content.app.vod.model.vo.HotSearch;
import cn.reghao.tnb.content.app.vod.model.vo.SuggestKeyword;
import cn.reghao.tnb.content.app.vod.service.ContentPermission;
import cn.reghao.tnb.content.app.vod.service.SearchService;
import cn.reghao.tnb.content.app.vod.service.VideoPostQuery;
import cn.reghao.tnb.content.app.util.redis.ds.RedisString;
import cn.reghao.tnb.search.api.dto.VideoSummary;
import cn.reghao.tnb.search.api.iface.DataSearchService;
import cn.reghao.tnb.user.api.iface.UserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2024-08-07 07:30:10
 */
@Service
public class SearchServiceImpl implements SearchService {
    @DubboReference(check = false, retries = 1, timeout = 60_000)
    private DataSearchService dataSearchService;
    @DubboReference(check = false, retries = 1, timeout = 60_000)
    private UserService userService;

    private final int pageSize = 12;
    private final VideoPostMapper videoPostMapper;
    private final SearchRecordMapper searchRecordMapper;
    private final ContentPermission contentPermission;
    private final RedisString redisString;
    private final VideoPostQuery videoPostQuery;
    private boolean mysqlSearch = false;

    public SearchServiceImpl(VideoPostMapper videoPostMapper, SearchRecordMapper searchRecordMapper,
                             ContentPermission contentPermission, RedisString redisString,
                             VideoPostQuery videoPostQuery) {
        this.videoPostMapper = videoPostMapper;
        this.searchRecordMapper = searchRecordMapper;
        this.contentPermission = contentPermission;
        this.redisString = redisString;
        this.videoPostQuery = videoPostQuery;
    }

    /**
     * 根据输入返回最适合的搜索关键词
     *
     * @param
     * @return
     * @date 2021-12-08 下午7:06
     */
    public List<SuggestKeyword> suggestKeyword(String keyword) {
        List<SuggestKeyword> list = searchRecordMapper.findSuggestKeyword(keyword);
        return list;
    }

    public PageList<VideoCard> searchByKeyword(String keyword, String nextIdStr, int pageNumber) {
        processKeywordAsync(keyword);
        PageList<VideoCard> pageList;
        if (mysqlSearch) {
            pageList = searchKeywordInMySql(keyword, pageNumber);
        } else {
            pageList = searchKeywordInLucene(keyword, pageNumber);
        }

        return pageList;
    }

    public PageList<VideoCard> searchKeywordInMySql(String keyword, int pageNumber) {
        List<Integer> scopes = contentPermission.getUserScopes();
        SearchCriteria searchCriteria = new SearchCriteria.Builder().scope(scopes).title(keyword).build();
        int total = videoPostMapper.countBySearchCriteria(searchCriteria);
        Page page = new Page(pageNumber, pageSize);
        List<VideoPost> list = videoPostMapper.findSearchCriteriaByPage(page, searchCriteria);
        if (list.isEmpty()) {
            return PageList.empty();
        }
        List<String> videoIds = list.stream().map(VideoPost::getVideoId).collect(Collectors.toList());

        List<VideoCard> list1 = videoPostMapper.findVideoCardByVideoIds(videoIds).stream()
                .map(videoPostCard -> videoPostQuery.getVideoCard(videoPostCard, true))
                .collect(Collectors.toList());

        return PageList.pageList(pageNumber, pageSize, total, list1);
    }

    public PageList<VideoCard> searchKeywordInLucene(String keyword, int pageNumber) {
        long loginUser = UserContext.getUserId();
        List<Integer> userScopes = contentPermission.getUserScopes(loginUser);
        PageList<VideoSummary> pageList = dataSearchService.searchVideo(keyword, userScopes, pageNumber);
        List<VideoSummary> videoSummaryList = pageList.getList();
        Map<String, List<VideoSummary>> map = videoSummaryList.stream().collect(Collectors.groupingBy(VideoSummary::getVideoId));
        List<String> videoIds = new ArrayList<>(map.keySet());
        if (videoIds.isEmpty()) {
            return PageList.empty();
        }

        List<VideoCard> list1 = videoPostMapper.findVideoCardByVideoIds(videoIds).stream()
                .map(videoPostCard -> {
                    VideoCard videoCard = videoPostQuery.getVideoCard(videoPostCard, true);
                    List<VideoSummary> list2 = map.get(videoCard.getVideoId());
                    if (!list2.isEmpty()) {
                        videoCard.setTitle(list2.get(0).getTitle());
                    }
                    return videoCard;
                })
                .collect(Collectors.toList());
        return PageList.pageList(pageNumber, pageSize, (int) pageList.getTotalSize(), list1);
    }

    private void processKeywordAsync(String keyword) {
        saveKeyword(keyword);
        /*int total = getTotal(keyword);
        if (total == 0) {
            saveKeyword(keyword);
            setTotal(keyword, total);
        }*/
    }

    private int getTotal(String keyword) {
        String key = String.format("tnb:search:total:%s", keyword);
        String value = redisString.get(key);
        return value != null ? Integer.parseInt(value) : 0;
    }

    private void setTotal(String keyword, int total) {
        String key = String.format("tnb:search:total:%s", keyword);
        redisString.setWithTimeout(key, total+"", 600);
    }

    private void saveKeyword(String keyword) {
        searchRecordMapper.save(new SearchRecord(keyword));
    }

    public List<HotSearch> getHotSearch() {
        List<HotSearch> list = searchRecordMapper.findHotSearch();
        return list;
    }
}
