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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.pcloud.appcenter.app.dto.AppDto;
import com.pcloud.book.applet.biz.AppletBannerBiz;
import com.pcloud.book.applet.biz.AppletNewsBiz;
import com.pcloud.book.applet.dao.AppletBannerDao;
import com.pcloud.book.applet.dao.AppletUserBookcaseDao;
import com.pcloud.book.applet.dto.AppletBannerDTO;
import com.pcloud.book.applet.dto.AppletBannerStats;
import com.pcloud.book.applet.dto.AppletNewsDTO;
import com.pcloud.book.applet.dto.ServeItemInfoDTO;
import com.pcloud.book.applet.entity.AppletBanner;
import com.pcloud.book.applet.entity.AppletBannerRecord;
import com.pcloud.book.applet.entity.AppletUserBookcase;
import com.pcloud.book.applet.enums.AppletRecordTypeEnum;
import com.pcloud.book.applet.mapper.AppletBannerRecordMapper;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.consumer.app.AppConsr;
import com.pcloud.book.consumer.channel.QrcodeSceneConsr;
import com.pcloud.book.consumer.resource.ProductConsr;
import com.pcloud.book.group.tools.SendWeixinRequestTools;
import com.pcloud.book.rightsSetting.biz.RightsSettingBiz;
import com.pcloud.channelcenter.wechat.dto.AccountSettingDto;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.ParamChecker;
import com.pcloud.common.utils.ServeLinkUtils;
import com.pcloud.resourcecenter.product.dto.ProductDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * 小程序banner
 */
@Component
@Slf4j
public class AppletBannerBizImpl implements AppletBannerBiz {

    @Autowired
    private AppletBannerDao appletBannerDao;
    @Autowired
    private AppletNewsBiz appletNewsBiz;
    @Autowired
    private AppletBannerRecordMapper appletBannerRecordMapper;
    @Autowired
    private ProductConsr productConsr;
    @Autowired
    private AppConsr appConsr;
    @Autowired
    private AppletUserBookcaseDao appletUserBookcaseDao;
    @Autowired
    private RightsSettingBiz rightsSettingBiz;
    @Autowired
    private QrcodeSceneConsr qrcodeSceneConsr;


    @Override
    public Long addBanner(AppletBanner appletBanner) {
        if (!ListUtil.toList(3,4).contains(appletBanner.getJumpType())) {
            ParamChecker.checkStringIsEmpty(appletBanner.getBannerPic(), "Banner图缺失！");
        }
        if (null == appletBanner.getAgentId()){
            appletBanner.setAgentId(0L);
        }
        Integer seq = appletBannerDao.getMaxSeq(appletBanner.getAgentId());
        appletBanner.setSeq(seq+1);
        appletBanner.setShowState(false);
        appletBannerDao.insert(appletBanner);
        return appletBanner.getId();
    }

    @Override
    public void updateBanner(AppletBanner appletBanner) {
        if (null==appletBanner.getId()){
            throw new BookBizException(BookBizException.PARAM_IS_NULL,"缺少id");
        }
        if (Objects.nonNull(appletBanner.getJumpType()) && !ListUtil.toList(3, 4).contains(appletBanner.getJumpType())) {
            ParamChecker.checkStringIsEmpty(appletBanner.getBannerPic(), "Banner图缺失！");
        }
        appletBannerDao.update(appletBanner);
    }

    @Override
    public void deleteBanner(Long id) {
        appletBannerDao.deleteById(id);
    }

    @Override
    public AppletBannerDTO getBannerById(Long id) {
        AppletBanner appletBanner = appletBannerDao.getById(id);
        AppletBannerDTO appletBannerDTO = new AppletBannerDTO();
        if (null != appletBanner){
            BeanUtils.copyProperties(appletBanner,appletBannerDTO);
            fillServeInfo(ListUtil.toList(appletBannerDTO));
            List<AppletBannerStats> bannerPVUV = appletBannerRecordMapper.getBannerPVUV(ListUtil.toList(appletBanner.getId()));
            if (CollUtil.isNotEmpty(bannerPVUV) && Objects.nonNull(bannerPVUV.get(0))){
                AppletBannerStats appletBannerStats = bannerPVUV.get(0);
                String pv = Objects.nonNull(appletBannerStats.getPv()) ? String.valueOf(appletBannerStats.getPv()) : "0";
                String uv = Objects.nonNull(appletBannerStats.getUv()) ? String.valueOf(appletBannerStats.getUv()) : "0";
                appletBannerDTO.setClickPVUV(pv + "/" + uv);
            }
        }
        return appletBannerDTO;
    }

    @Override
    public PageBeanNew<AppletBannerDTO> listBanner(Integer currentPage, Integer numPerPage, Boolean showState, Long agentId) {
        Map<String, Object> map = new HashMap<>();
        map.put("showState", showState);
        map.put("agentId", agentId);
        PageBeanNew<AppletBannerDTO> banner = appletBannerDao.listPageNew(new PageParam(currentPage, numPerPage), map, "listBanner");
        if (Objects.isNull(banner) || CollUtil.isEmpty(banner.getRecordList())) {
            return banner;
        }
        // 填充 资讯 | 作品 | 应用 信息
        fillServeInfo(banner.getRecordList());

        List<Long> bannerIds = banner.getRecordList().stream().filter(Objects::nonNull).map(AppletBannerDTO::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(bannerIds)) {
            return banner;
        }
        // 根据 bannerId 统计 PV/UV
        List<AppletBannerStats> bannerPVUV = appletBannerRecordMapper.getBannerPVUV(bannerIds);
        if (CollUtil.isEmpty(bannerPVUV)) {
            return banner;
        }
        Map<Long, AppletBannerStats> bannerStatsMap = bannerPVUV.stream()
                .collect(Collectors.toMap(AppletBannerStats::getBannerId, AppletBannerStats -> AppletBannerStats));
        banner.getRecordList().forEach(item -> {
            if (Objects.nonNull(item) && Objects.nonNull(item.getId()) && CollUtil.isNotEmpty(bannerStatsMap) && Objects.nonNull(bannerStatsMap.get(item.getId()))) {
                AppletBannerStats bannerStats = bannerStatsMap.get(item.getId());
                String pv = Objects.nonNull(bannerStats.getPv()) ? String.valueOf(bannerStats.getPv()) : "0";
                String uv = Objects.nonNull(bannerStats.getUv()) ? String.valueOf(bannerStats.getUv()) : "0";
                item.setClickPVUV(pv + "/" + uv);
            }
        });
        return banner;
    }

    private void fillServeInfo(List<AppletBannerDTO> recordList) {

        // 获取资讯信息
        Map<Long, AppletNewsDTO> newsDTOMap = new HashMap<>();
        CompletableFuture<List<Long>> newsBannerFuture = CompletableFuture.supplyAsync(() -> recordList.stream()
                .filter(x -> Objects.nonNull(x) && Objects.equals(x.getJumpType(), 3))
                .map(AppletBannerDTO::getServeId).filter(Objects::nonNull).distinct()
                .collect(Collectors.toList())).whenComplete((list, throwable) -> {
            if (Objects.nonNull(throwable)) {
                log.error("[fillServeInfo] banner 图填充资讯信息失败，err：{}", throwable.getMessage(), throwable);
            } else {
                if (CollUtil.isEmpty(list)){
                    return;
                }
                Map<Long, AppletNewsDTO> dtoMap = appletNewsBiz.getByIds(list);
                newsDTOMap.putAll(Objects.nonNull(dtoMap) ? dtoMap : new HashMap<>());
            }
        });

        // 获取应用信息
        Map<Long, AppDto> appDtoMap = new HashMap<>();
        CompletableFuture<List<Long>> appBannerFuture = CompletableFuture.supplyAsync(() -> recordList.stream()
                .filter(x -> Objects.nonNull(x) && Objects.equals(x.getServeType(), AppletRecordTypeEnum.APP.value))
                .map(AppletBannerDTO::getServeId).collect(Collectors.toList())).whenComplete((list, throwable) -> {
            if (Objects.nonNull(throwable)) {
                log.error("[fillServeInfo] banner 图填充应用信息失败，err：{}", throwable.getMessage(), throwable);
            } else {
                Map<Long, AppDto> dtoMap = !ListUtils.isEmpty(list) ? appConsr.mapByIds4AuditPass(list) : new HashMap<>();
                appDtoMap.putAll(dtoMap);
            }
        });

        // 获取作品信息
        Map<Long, ProductDto> productDtoMap = new HashMap<>();
        CompletableFuture<List<Long>> productBannerFuture = CompletableFuture.supplyAsync(() -> recordList.stream()
                .filter(x -> Objects.nonNull(x) && Objects.equals(x.getServeType(), AppletRecordTypeEnum.PRODUCT.value))
                .map(AppletBannerDTO::getServeId).collect(Collectors.toList())).whenComplete((list, throwable) -> {
            if (Objects.nonNull(throwable)) {
                log.error("[fillServeInfo] banner 图填充作品信息失败，err：{}", throwable.getMessage(), throwable);
            } else {
                Map<Long, ProductDto> dtoMap = !ListUtils.isEmpty(list) ? productConsr.getProBasesByIds(list) : new HashMap<>();
                productDtoMap.putAll(dtoMap);
            }
        });

        try {
            CompletableFuture.allOf(newsBannerFuture, appBannerFuture, productBannerFuture).get();
        } catch (InterruptedException | ExecutionException e) {
            log.error("[fillServeInfo] banner 填充信息失败，err：{}", e.getMessage(), e);
        }

        // 填充信息
        for (AppletBannerDTO banner : recordList) {
            if (Objects.nonNull(banner) && Objects.nonNull(banner.getServeId()) && Objects.nonNull(banner.getServeType())) {
                Integer serveType = banner.getServeType();
                if (Objects.equals(banner.getJumpType(), 3) && Objects.nonNull(newsDTOMap.get(banner.getServeId()))) {
                    banner.setNewsItem(newsDTOMap.get(banner.getServeId()));
                } else if (Objects.equals(serveType, AppletRecordTypeEnum.APP.value) && Objects.nonNull(appDtoMap.get(banner.getServeId()))) {
                    AppDto appDto = appDtoMap.get(banner.getServeId());
                    String resultLinkUrl = null;
                    if (Objects.nonNull(appDto.getChannelId())) {
                        AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(appDto.getChannelId());
                        // 根据 APP 拼接 linkUrl
                        String linkUrl = ServeLinkUtils.getServeLink("APP", appDto.getTypeCode(), appDto.getAppId().toString(),
                                appDto.getSceneCode(), appDto.getChannelId().toString(), appDto.getCreatedUser().toString(), null);
                        if (Objects.nonNull(accountSettingDto)) {
                            resultLinkUrl = SendWeixinRequestTools.splitUrl(accountSettingDto, linkUrl);
                        }
                    }
                    ServeItemInfoDTO build = ServeItemInfoDTO.builder().serveId(appDto.getAppId()).serveType(serveType)
                            .serveName(appDto.getTitle()).servePic(appDto.getSquareImg()).transverseImg(appDto.getTransverseImg())
                            .resultUrl(resultLinkUrl).hasThirdLink(StrUtil.isNotBlank(appDto.getTurnUrl()))
                            .serveTypeName(appDto.getTypeName()).build();
                    banner.setAppItem(build);
                } else if (Objects.equals(serveType, AppletRecordTypeEnum.PRODUCT.value) && Objects.nonNull(productDtoMap.get(banner.getServeId()))) {
                    ProductDto productDto = productDtoMap.get(banner.getServeId());
                    String resultLinkUrl = null;
                    if (Objects.nonNull(productDto.getChannelId())) {
                        AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(productDto.getChannelId());
                        if (null != accountSettingDto) {
                            resultLinkUrl = SendWeixinRequestTools.splitUrl(accountSettingDto, productDto.getTurnUrl());
                        }
                    }
                    ServeItemInfoDTO build = ServeItemInfoDTO.builder().serveId(productDto.getProductId()).serveType(serveType)
                            .serveName(productDto.getProductName()).servePic(productDto.getCoverImg()).transverseImg(productDto.getPicture1())
                            .resultUrl(resultLinkUrl).hasThirdLink(StrUtil.isNotBlank(productDto.getSkipUrl()))
                            .serveTypeName(productDto.getProductTypeName()).build();
                    banner.setAppItem(build);
                }
            }
        }
    }

    @Override
    public PageBeanNew<AppletBannerDTO> listBanner4Wechat(Integer currentPage, Integer numPerPage, Boolean showState, Long officialAccountsId, Long wechatUserId) {
        Long agentId = appletNewsBiz.getAgentIdByAccountId(officialAccountsId);
        PageBeanNew<AppletBannerDTO> pageBeanNew = listBanner(currentPage, numPerPage, showState, agentId);
        // 依据当前用户正在读的书，所属分类获取最新上架的资讯
        processFillType(pageBeanNew.getRecordList(), wechatUserId);
        return pageBeanNew;
    }

    private void processFillType(List<AppletBannerDTO> recordList, Long wechatUserId) {
        if (CollUtil.isEmpty(recordList)) {
            return;
        }
        List<AppletBannerDTO> fillBanner = recordList.stream().filter(x -> Objects.nonNull(x) && Objects.equals(x.getJumpType(), 3)
                && Objects.equals(x.getFillType(), 2)).collect(Collectors.toList());
        if (CollUtil.isEmpty(fillBanner)) {
            return;
        }

        AppletUserBookcase userReadBook = appletUserBookcaseDao.getUserReadBook(wechatUserId);
        if (Objects.isNull(userReadBook)) {
            recordList.removeAll(fillBanner);
            return;
        }
        AppletNewsDTO newsDTO = rightsSettingBiz.getAppletNewsDTO4UserReadBook(userReadBook);
        if (Objects.isNull(newsDTO) || Objects.isNull(newsDTO.getId())) {
            recordList.removeAll(fillBanner);
            return;
        }
        recordList.stream().filter(x -> Objects.nonNull(x) && Objects.equals(x.getJumpType(), 3)
                && Objects.equals(x.getFillType(), 2)).forEach(item -> item.setNewsItem(newsDTO));
    }

    @Override
    public void bannerClickRecord(Long wechatUserId, Long bannerId) {
        AppletBanner banner = appletBannerDao.getById(bannerId);

        if (Objects.isNull(banner)) {
            appletBannerRecordMapper.insert(AppletBannerRecord.builder()
                    .bannerId(bannerId).createTime(new Date()).wechatUserId(wechatUserId).build());
        } else {
            AppletBannerRecord record = AppletBannerRecord.builder()
                    .createTime(new Date()).wechatUserId(wechatUserId)
                    .bannerId(bannerId).jumpType(banner.getJumpType())
                    .serveId(banner.getServeId()).serveType(banner.getServeType()).build();
            appletBannerRecordMapper.insert(record);
        }
    }
}
