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

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;

import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.consumer.channel.QrcodeSceneConsr;
import com.pcloud.book.consumer.live.LiveCons;
import com.pcloud.book.consumer.reader.ReaderConsr;
import com.pcloud.book.consumer.resource.ProductConsr;
import com.pcloud.book.copyright.biz.BookAuthServeBiz;
import com.pcloud.book.copyright.biz.BookAuthUserBiz;
import com.pcloud.book.copyright.dao.BookAuthServeDao;
import com.pcloud.book.copyright.dao.BookAuthUserDao;
import com.pcloud.book.copyright.dao.BookClickBuyRecordDao;
import com.pcloud.book.copyright.dto.BookAuthUserDTO;
import com.pcloud.book.copyright.dto.CheckUserAuthDTO;
import com.pcloud.book.copyright.dto.DateDTO;
import com.pcloud.book.copyright.dto.ServeDTO;
import com.pcloud.book.copyright.entity.BookAuthUser;
import com.pcloud.book.copyright.entity.BookClickBuyRecord;
import com.pcloud.book.copyright.enums.AuthBookTypeEnum;
import com.pcloud.book.copyright.tools.CopyrightTools;
import com.pcloud.book.copyright.vo.BookAuthCodeUserVO;
import com.pcloud.book.copyright.vo.BookClickBuyRecordParam;
import com.pcloud.book.copyright.vo.ProvinceTop10VO;
import com.pcloud.book.copyright.vo.SixMonthCountVO;
import com.pcloud.book.copyright.vo.ThirtyDayCountVO;
import com.pcloud.book.util.common.ThreadPoolUtils;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.cookie.Cookie;

import com.pcloud.readercenter.wechat.entity.WechatUser;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author lily
 * @date 2018/12/4 15:54
 */
@Component("bookAuthUserBiz")
public class BookAuthUserBizImpl implements BookAuthUserBiz {
    private static final Logger LOGGER = LoggerFactory.getLogger(BookAuthUserBizImpl.class);
    @Autowired
    private BookAuthUserDao bookAuthUserDao;
    @Autowired
    private BookClickBuyRecordDao bookClickBuyRecordDao;
    @Autowired
    private QrcodeSceneConsr qrcodeSceneConsr;
    @Autowired
    private BookAuthServeDao bookAuthServeDao;
    @Autowired
    private LiveCons liveCons;
    @Autowired
    private ProductConsr productConsr;
    @Autowired
    private ReaderConsr readerConsr;
    @Autowired
    private BookAuthServeBiz bookAuthServeBiz;


    @ParamLog(value = "获取授权用户数量")
    @Override
    public BookAuthCodeUserVO getAuthUserCount(Long bookId, Long channelId, Long adviserId, Integer authBookType) {
        if (bookId == null || channelId == null || adviserId == null) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "图书不存在");
        }
        BookAuthCodeUserVO bookAuthCodeUserVO = bookAuthUserDao.getAuthUserCount(bookId, channelId, adviserId, authBookType);
        if (bookAuthCodeUserVO != null) {
            bookAuthCodeUserVO.setCodeUserCount(bookAuthCodeUserVO.getTotalCount() - bookAuthCodeUserVO.getPayUserCount());
        } else {
            bookAuthCodeUserVO = new BookAuthCodeUserVO();
            bookAuthCodeUserVO.setCodeUserCount(0);
            bookAuthCodeUserVO.setPayUserCount(0);
        }
        return bookAuthCodeUserVO;
    }

    @Override
    public BookAuthCodeUserVO getAuthUserCountByMonth(Long bookId, Long channelId, Long adviserId, String monthDate) {
        if (bookId == null || channelId == null || adviserId == null) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "图书不存在");
        }
        BookAuthCodeUserVO bookAuthCodeUserVO = bookAuthUserDao.getAuthUserCountByMonth(bookId, channelId, adviserId, monthDate);
        if (bookAuthCodeUserVO != null && bookAuthCodeUserVO.getTotalCount() != null && bookAuthCodeUserVO.getPayUserCount() != null) {
            bookAuthCodeUserVO.setCodeUserCount(bookAuthCodeUserVO.getTotalCount() - bookAuthCodeUserVO.getPayUserCount());
        }
        return bookAuthCodeUserVO;
    }

    @Override
    public List<ThirtyDayCountVO> listThirtyDay(Long bookId, Long channelId, Long adviserId, String province, Integer authBookType) {
        DateDTO date = CopyrightTools.getDateByType(30L);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("startDate", date.getStartTime());
        paramMap.put("endDate", date.getEndTime());
        paramMap.put("bookId", bookId);
        paramMap.put("channelId", channelId);
        paramMap.put("adviserId", adviserId);
        paramMap.put("province", province);
        if(authBookType == null || authBookType.equals(AuthBookTypeEnum.PAPER_BOOK.value)) {
            paramMap.put("isPaperBook", 1);
        } else {
            paramMap.put("isGroupBook", 1);
        }
        List<ThirtyDayCountVO>  thirtyDayCountVOS = bookAuthUserDao.listThirtyDay(paramMap);
        setZoreRecord(thirtyDayCountVOS, date.getStartTime(), date.getEndTime());
        return thirtyDayCountVOS;
    }

    /**
     * 填充0
     */
    public void setZoreRecord(List<ThirtyDayCountVO> thirtyDayCountVOS, String startDate, String endDate) {
        // 计算开始时间和结束时间相差多少天，含当天所以要+1
        int dateDiff = (int) (DateUtils.getDateDiff(startDate, endDate) + 1);
        List<String> dates = DateUtils.getLastDays(endDate, dateDiff);
        for (String date : dates) {
            boolean bool = false;
            for (ThirtyDayCountVO thirtyDayCountVO : thirtyDayCountVOS) {
                if (date.equals(thirtyDayCountVO.getDate())) {
                    bool = true;
                    thirtyDayCountVO.setCodeUserCount(thirtyDayCountVO.getTotalCount()-thirtyDayCountVO.getPayUserCount());
                }
            }

            if (!bool) {
                ThirtyDayCountVO thirtyDayCountVO = new ThirtyDayCountVO();
                thirtyDayCountVO.setDate(date);
                thirtyDayCountVO.setCodeUserCount(0);
                thirtyDayCountVO.setPayUserCount(0);
                thirtyDayCountVOS.add(thirtyDayCountVO);
            }
        }
        thirtyDayCountVOS
                .sort((ThirtyDayCountVO dto1, ThirtyDayCountVO dto2) -> dto1.getDate().compareTo(dto2.getDate()));
    }

    @Override
    public List<SixMonthCountVO> listSixMonth(Long bookId, Long channelId, Long adviserId, String province, Integer authBookType) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("bookId", bookId);
        paramMap.put("channelId", channelId);
        paramMap.put("adviserId", adviserId);
        paramMap.put("province", province);
        paramMap.put("months", CopyrightTools.getLast6Months());
        if(authBookType == null || authBookType.equals(AuthBookTypeEnum.PAPER_BOOK.value)) {
            paramMap.put("isPaperBook", 1);
        } else {
            paramMap.put("isGroupBook", 1);
        }
        List<SixMonthCountVO> sixMonthCountVOS = bookAuthUserDao.listSixMonth(paramMap);
        setZoreRecord(sixMonthCountVOS);
        return sixMonthCountVOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insert(BookAuthUser bookAuthUser) {
        bookAuthUser.setMonths(new SimpleDateFormat("yyyy-MM").format(new Date()));
        bookAuthUserDao.insert(bookAuthUser);
    }

    @Override
    @ParamLog("校验用户是否已经授权")
    public Boolean checkIsHaveAuth(Long bookId, Long channelId, Long adviserId, Long wechatUserId, Integer authBookType) {
        List<Long> wechatUserIdList = readerConsr.getAllUnionUser(wechatUserId);
        return bookAuthUserDao.getIsHaveAuth(bookId, channelId, adviserId, wechatUserIdList, authBookType);
    }

    @Override
    public Boolean checkIsHaveAuthWithServer(String userInfo, Long serverId, String serverType) {
        // 如果包含超级作者资源, 则直接返回
        if(checkIsSuperProduct(serverId)){
            return false;
        }

        // 否则查询授权关系
        Long bookId = qrcodeSceneConsr.getBookId4SceneId(Cookie.getId(userInfo,Cookie._SCENE_ID));
        Long channelId = Cookie.getId(userInfo, Cookie._CHANNEL_ID);
        Long adviserId = Cookie.getId(userInfo,Cookie._ADVISER_ID);
        Long wecharUserId = Cookie.getId(userInfo,Cookie._WECHAT_USER_ID);

        if("live".equalsIgnoreCase(serverType)){
            List<Long> id = new ArrayList<>(1);
            id.add(serverId);
            Map<Long, Boolean> map = liveCons.checkIsSuperMerchant(id);
            if(map != null && Boolean.TRUE.equals(map.get(serverId))){
                return false;
            }
            else{
                return checkIsHaveAuthWithServer(bookId,channelId,adviserId,wecharUserId,serverId);
            }
        }
        else{
            return checkIsHaveAuthWithServer(bookId,channelId,adviserId,wecharUserId,serverId);
        }
    }

    private Boolean checkIsHaveAuthWithServer(Long bookId, Long channelId, Long adviserId, Long wecharUserId, Long serverId) {
        // 书类型指定为is_paper_book
        Boolean isUserAuth = checkIsHaveAuth(bookId,channelId,adviserId,wecharUserId,0);
        if(isUserAuth){
            List<Long> serverIds = new ArrayList<>();
            serverIds.add(serverId);
            List<ServeDTO> serveDTOS = bookAuthServeDao.isSetServeAuth(bookId, channelId, adviserId, serverIds);
            // 获取授权后是否仍需付费
            Boolean isAuthorizedPay = checkIsAuthorizedPay(bookId, channelId, adviserId, serverId);
            // 用户被授权, 指定的应用也被版权保护，且授权后不需要付费，则返回true
            return !ListUtils.isEmpty(serveDTOS) && !isAuthorizedPay;
        }
        // 其余情况都是false
        return false;
    }

    private Boolean checkIsAuthorizedPay(Long bookId, Long channelId, Long adviserId, Long serverId) {
        Map<String, Boolean> authorizedPayMap = bookAuthServeBiz.listIsOpen4AuthorizedPay(bookId, adviserId, channelId, CollUtil.toList(serverId));
        if(CollUtil.isEmpty(authorizedPayMap)){
            return false;
        }
        return authorizedPayMap.getOrDefault("PRODUCT" + serverId, false);
    }

    // 判断是否为超级作者的商品
    private Boolean checkIsSuperProduct(Long serverId) {
        Map<Long, Boolean> map = productConsr.getIsSuperByProductIdList(Lists.newArrayList(serverId));
        if (map != null && map.containsKey(serverId)) {
            return map.get(serverId);
        }

        return false;
    }

    @Override
    public BookAuthCodeUserVO getAuthUserTotalCount(List<Long> adviserIds, List<Long> removeAdviserIds) {
        BookAuthCodeUserVO bookAuthCodeUserVO = bookAuthUserDao.getAuthUserTotalCount(adviserIds, removeAdviserIds);
        if(bookAuthCodeUserVO != null){
            bookAuthCodeUserVO.setCodeUserCount(bookAuthCodeUserVO.getTotalCount() - bookAuthCodeUserVO.getPayUserCount());
        }
        return bookAuthCodeUserVO;
    }

    @Override
    @ParamLog("新增点击购买链接记录")
    public void insertClickBuyRecord(BookClickBuyRecordParam bookClickBuyRecordParam, Long channelId, Long wechatUserId) {
        ThreadPoolUtils.OTHER_THREAD_POOL.execute(() -> {
            try {
                BookClickBuyRecord bookClickBuyRecord = new BookClickBuyRecord();
                bookClickBuyRecord.setChannelId(channelId);
                bookClickBuyRecord.setWechatUserId(wechatUserId);
                BeanUtils.copyProperties(bookClickBuyRecordParam, bookClickBuyRecord);
                bookClickBuyRecordDao.insert(bookClickBuyRecord);
            } catch (Exception e) {
                LOGGER.error("新增点击购买链接记录" + bookClickBuyRecordParam);
            }
        });
    }

    @Override
    @ParamLog("省份排名前10")
    public List<ProvinceTop10VO> listTop10ByBook(Long bookId, Long channelId, Long adviserId, Integer type) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("bookId", bookId);
        paramMap.put("channelId", channelId);
        paramMap.put("adviserId", adviserId);
        if (type != null && type == 0) {
            DateDTO date = CopyrightTools.getDateByType(30L);
            paramMap.put("startDate", date.getStartTime());
            paramMap.put("endDate", date.getEndTime());
        }else if(type != null && type == 1){
            paramMap.put("months", CopyrightTools.getLast6Months());
        }
        List<ProvinceTop10VO> top10ByBook = bookAuthUserDao.listTop10ByBook(paramMap);
        if (!ListUtils.isEmpty(top10ByBook)) {
            for (ProvinceTop10VO provinceTop10VO : top10ByBook) {
                if (provinceTop10VO.getTotalCount() != null && provinceTop10VO.getPayUserCount() != null) {
                    provinceTop10VO.setCodeUserCount(provinceTop10VO.getTotalCount() - provinceTop10VO.getPayUserCount());
                }

            }
        }
        return top10ByBook;
    }

    @Override
    @ParamLog("校验用户是否授权(进群)")
    public Boolean checkUserIsHaveAuth(CheckUserAuthDTO checkUserAuthDTO) {
        Long bookId = checkUserAuthDTO.getBookId();
        Long channelId = checkUserAuthDTO.getChannelId();
        Long adviserId = checkUserAuthDTO.getAdviserId();
        List<Long> wechatUserIds = checkUserAuthDTO.getWechatUserIds();
        if(null == bookId || null == channelId || null == adviserId || ListUtils.isEmpty(wechatUserIds)) {
            LOGGER.error("参数缺失!");
            return false;
        }
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("bookId", bookId);
        paramMap.put("channelId", channelId);
        paramMap.put("adviserId", adviserId);
        paramMap.put("wechatUserIds", wechatUserIds);
        return bookAuthUserDao.checkUserIsHaveAuth(paramMap);
    }

    /**
     * 设置最近6月为空得书
     */
    private void setZoreRecord(List<SixMonthCountVO> sixMonthCountVOS) {
        List<String> last6Months = CopyrightTools.getLast6Months();
        for (String month : last6Months) {
            boolean bool = false;
            for (SixMonthCountVO sixMonthCountVO : sixMonthCountVOS) {
                if (month.equals(sixMonthCountVO.getDate())) {
                    bool = true;
                    sixMonthCountVO.setCodeUserCount(sixMonthCountVO.getTotalCount() - sixMonthCountVO.getPayUserCount());
                }
            }
            if (!bool) {
                SixMonthCountVO sixMonthCountVO = new SixMonthCountVO();
                sixMonthCountVO.setDate(month);
                sixMonthCountVO.setCodeUserCount(0);
                sixMonthCountVO.setPayUserCount(0);
                sixMonthCountVO.setTotalCount(0);
                sixMonthCountVOS.add(sixMonthCountVO);
            }
        }
        sixMonthCountVOS
                .sort((SixMonthCountVO dto1, SixMonthCountVO dto2) -> dto1.getDate().compareTo(dto2.getDate()));
    }

    @Override
    public Map<Long, List<BookAuthUserDTO>> getByAuthCodeIds(List<Long> authCodeIds) {
        if(CollectionUtils.isEmpty(authCodeIds)){
            return new HashMap<>();
        }
        List<BookAuthUserDTO> bookAuthUserList = bookAuthUserDao.getByAuthCodeIds(authCodeIds);
        if(CollectionUtils.isEmpty(bookAuthUserList)){
            return new HashMap<>();
        }
        List<Long> wechatUserIds = bookAuthUserList.stream().filter(x -> !Objects.isNull(x.getWechatUserId())).map(x -> x.getWechatUserId()).distinct().collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(wechatUserIds)){
            Map<Long, WechatUser> wechatUserMap = readerConsr.getUserList(wechatUserIds);
            for (BookAuthUserDTO bookAuthUserDTO : bookAuthUserList){
                Long wechatUserId = bookAuthUserDTO.getWechatUserId();
                if (!MapUtils.isEmpty(wechatUserMap) && null != wechatUserId && wechatUserMap.containsKey(wechatUserId)){
                    WechatUser wechatUser = wechatUserMap.get(wechatUserId);
                    bookAuthUserDTO.setNickName(null == wechatUser ? "" : wechatUser.getWechatUserNickname());
                }
            }
        }
        return bookAuthUserList.stream().collect(Collectors.groupingBy(x -> x.getBookAuthCodeId()));
    }
}
