package com.gic.haoban.manage.service.service.chat.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.Constant;
import com.gic.api.base.commons.Page;
import com.gic.commons.util.EntityUtil;
import com.gic.commons.util.GICMQClientUtil;
import com.gic.commons.util.PageHelperUtils;
import com.gic.commons.util.UniqueIdUtils;
import com.gic.haoban.manage.api.dto.chat.GroupChatActivityDTO;
import com.gic.haoban.manage.api.dto.chat.GroupChatActivityInviteLogDTO;
import com.gic.haoban.manage.api.dto.chat.GroupChatActivityRewardDTO;
import com.gic.haoban.manage.api.enums.chat.*;
import com.gic.haoban.manage.api.qdto.chat.GroupChatActivityInviteLogQDTO;
import com.gic.haoban.manage.service.dao.mapper.chat.GroupChatActivityInviteLogMapper;
import com.gic.haoban.manage.service.dao.mapper.chat.GroupChatUserMapper;
import com.gic.haoban.manage.service.entity.chat.TabGroupChatActivityInviteLog;
import com.gic.haoban.manage.service.entity.chat.TabGroupChatActivityShareBind;
import com.gic.haoban.manage.service.entity.chat.TabGroupChatUser;
import com.gic.haoban.manage.service.pojo.bo.chat.GroupChatActivityBaseContext;
import com.gic.haoban.manage.service.pojo.bo.chat.GroupChatActivityContext;
import com.gic.haoban.manage.service.service.chat.GroupChatActivityInviteLogService;
import com.gic.haoban.manage.service.service.chat.GroupChatActivityRewardLogService;
import com.gic.haoban.manage.service.service.chat.GroupChatActivityService;
import com.gic.haoban.manage.service.service.chat.GroupChatActivityShareBindService;
import com.gic.member.api.dto.MemberDTO;
import com.gic.member.api.service.MemberService;
import com.gic.member.tag.api.dto.outapi.MemberTagSingleDTO;
import com.gic.member.tag.api.service.MemberTagOpenApiService;
import com.gic.redis.data.util.RedisUtil;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 社群邀请有礼邀请日志表(TabHaobanGroupChatActivityInviteLog)表服务实现类
 *
 * @author makejava
 * @since 2024-09-27 16:09:56
 */
@Service("groupChatActivityInviteLogService")
public class GroupChatActivityInviteLogServiceImpl implements GroupChatActivityInviteLogService {

    private static final Logger logger = LogManager.getLogger(GroupChatActivityInviteLogService.class);

    public static final String ACTIVITY_GROUP_CHAT_KEY = "haoban-manage3-service:activity_group_chat:";

    @Autowired
    private GroupChatActivityInviteLogMapper groupChatActivityInviteLogMapper;
    @Autowired
    private GroupChatActivityService groupChatActivityService;
    @Autowired
    private GroupChatActivityRewardLogService groupChatActivityRewardLogService;
    @Autowired
    private GroupChatUserMapper groupChatUserMapper;
    @Autowired
    private GroupChatActivityShareBindService groupChatActivityShareBindService;
    @Autowired
    private MemberTagOpenApiService memberTagOpenApiService;
    @Autowired
    private MemberService memberService;

    private GroupChatActivityInviteLogDTO convertToDTO(TabGroupChatActivityInviteLog tabGroupChatActivityInviteLog){
        GroupChatActivityInviteLogDTO groupChatActivityInviteLogDTO = new GroupChatActivityInviteLogDTO();
        BeanUtils.copyProperties(tabGroupChatActivityInviteLog,groupChatActivityInviteLogDTO);
        return groupChatActivityInviteLogDTO;
    }

    @Override
    public List<GroupChatActivityInviteLogDTO> queryMaxBatchInviteLog(GroupChatActivityInviteLogQDTO inviteLogQDTO) {
//        Integer maxBatch = groupChatActivityInviteLogMapper.queryMaxBatchByChatActivityIdAndInviterMemberId(inviteLogQDTO.getChatActivityId(), inviteLogQDTO.getInviterMemberId());
//        //没有最大批次数据表示没有任何邀请数据 直接返回
//        if (Objects.isNull(maxBatch)) {
//            return Lists.newArrayList();
//        }
//        inviteLogQDTO.setBatchNumber(maxBatch);
        List<TabGroupChatActivityInviteLog> logList = groupChatActivityInviteLogMapper.queryList(inviteLogQDTO);
        if(CollectionUtils.isEmpty(logList)){
            return Lists.newArrayList();
        }
        return logList.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    public Page<GroupChatActivityInviteLogDTO> queryInviteLogDetails(GroupChatActivityInviteLogQDTO inviteLogQDTO) {
        PageHelper.startPage(inviteLogQDTO);
        List<TabGroupChatActivityInviteLog> logList = groupChatActivityInviteLogMapper.queryList(inviteLogQDTO);
        return PageHelperUtils.changePageHelperToCurrentPage(logList, GroupChatActivityInviteLogDTO.class);
    }

    @Override
    public void groupChatInviteMQ(List<TabGroupChatUser> chatUserList) {
        chatUserList = chatUserList.stream().filter(x ->
                        !Objects.equals(x.getUserType(), 1)
                        && StringUtils.isNotBlank(x.getUnionid()))
                .collect(Collectors.toList());
        logger.info("入群逻辑处理数:{}", chatUserList.size());
        if (CollectionUtils.isEmpty(chatUserList)) {
            return;
        }
        List<String> unionIdList = chatUserList.stream().map(TabGroupChatUser::getUnionid).collect(Collectors.toList());
        List<List<String>> partition = Lists.partition(unionIdList, 1000);
        for (List<String> unionIds : partition) {
            List<TabGroupChatActivityShareBind> shareBindList = groupChatActivityShareBindService.query24Record(unionIds);
            if (CollectionUtils.isEmpty(shareBindList)) {
                return;
            }
            logger.info("入群有邀请绑定数:{}", shareBindList.size());
            Map<String, List<TabGroupChatActivityShareBind>> map = shareBindList.stream().collect(Collectors.groupingBy(TabGroupChatActivityShareBind::getInviteeUnionId));
            for (TabGroupChatUser groupChatUser : chatUserList) {
                Long chatUserId = groupChatUser.getChatUserId();
                String unionid = groupChatUser.getUnionid();
                List<TabGroupChatActivityShareBind> list = map.get(unionid);
                if (CollectionUtils.isEmpty(list)) {
                    continue;
                }
                Set<Long> chatActivityIdSet = new HashSet<>();
                //同个活动取最近一条绑定信息
                for (TabGroupChatActivityShareBind shareBind : list) {
                    Long chatActivityId = shareBind.getChatActivityId();
                    if (chatActivityIdSet.add(chatActivityId)) {
                        GroupChatActivityBaseContext chatActivityContext = new GroupChatActivityBaseContext();
                        chatActivityContext.setChatUserId(chatUserId);
                        chatActivityContext.setChatActivityId(chatActivityId);
                        chatActivityContext.setInviterMemberId(shareBind.getInviterMemberId());
                        chatActivityContext.setEnterpriseId(shareBind.getEnterpriseId());
                        chatActivityContext.setUniqueId(shareBind.getInviteeUnionId());
//                         todo 社群邀请-mq异步
//                        groupChatInvite(chatActivityContext);
                        try {
                            GICMQClientUtil.getClientInstance().sendMessage("shareGroupChatInviteMQ",JSON.toJSONString(chatActivityContext));
                        } catch (Exception e) {
                            logger.info("社群邀请MQ发送异常",e);
                        }
                    }
                }
            }
        }
    }

    @Override
    public void groupChatInvite(GroupChatActivityBaseContext baseContext) {
        logger.info("社群活动邀请:{}", JSON.toJSONString(baseContext));
        Long chatUserId = baseContext.getChatUserId();
        GroupChatActivityContext context = EntityUtil.changeEntityNew(GroupChatActivityContext.class, baseContext);
        TabGroupChatUser groupChatUser = groupChatUserMapper.selectById(chatUserId);
        if (groupChatUser == null) {
            logger.info("社群群明细为空");
            return;
        }
        context.setChatUser(groupChatUser);
        String inviterMemberId = context.getInviterMemberId();
        String enterpriseId = context.getEnterpriseId();
        Long chatActivityId = context.getChatActivityId();
        String key = ACTIVITY_GROUP_CHAT_KEY + inviterMemberId;
        RedisUtil.lock(key, 30L);
        try {
            GroupChatActivityDTO chatActivityDTO = groupChatActivityService.getActivityDetailCache(enterpriseId, chatActivityId);
            if (chatActivityDTO == null) {
                logger.info("社群活动为空");
                return;
            }
            context.setChatActivityDTO(chatActivityDTO);
            boolean checked = checkActivity(context);
            if (!checked) {
                return;
            }
            Integer inviteType = Constant.FLAG_FALSE;
            int batchNumber = -1;
            Integer invalidInviteType = getActivityEffective(context);
            logger.info("获取本次入群有效状态:{}", invalidInviteType);
            if (invalidInviteType == null) {
                inviteType = Constant.FLAG_TRUE;
                //获取奖励批次
                batchNumber = getActivityBatchNumber(context);
            }
            //保存邀请记录
            saveChatActivityInvite(context, batchNumber, inviteType, invalidInviteType);
            //有效发放奖励
            if (Objects.equals(inviteType, Constant.FLAG_TRUE)) {
                groupChatActivityRewardLogService.dealRewardAndSaveLog(context);
            }
            //受邀人打标
            Integer labelFlag = chatActivityDTO.getLabelFlag();
            String labelJson = chatActivityDTO.getLabelJson();
            if (Objects.equals(labelFlag, Constant.FLAG_TRUE) && StringUtils.isNotBlank(labelJson)) {
                MemberTagSingleDTO dto = new MemberTagSingleDTO();
                dto.setEnterpriseId(enterpriseId);
                dto.setOptType(0);
                dto.setMemberId(context.getChatUser().getMemberId());
                String id = JSONObject.parseObject(labelJson).getString("id");
                dto.setTagItemIdList(Lists.newArrayList(id));
                this.memberTagOpenApiService.saveMemberTagSingle(dto);
            }
        } catch (Exception e) {
            logger.info("社群活动处理异常",e);
        } finally {
            RedisUtil.unlock(key);
        }
    }

    /**
     * 校验活动是否写邀请记录
     * @param context
     * @return
     */
    private boolean checkActivity(GroupChatActivityContext context) {
        GroupChatActivityDTO activity = context.getChatActivityDTO();
        TabGroupChatUser chatUser = context.getChatUser();
        Date joinTime = chatUser.getJoinTime();
        Date startDate = activity.getStartDate();
        Date endDate = activity.getEndDate();
        Date limitDate = activity.getLimitDate();
        if (DateUtil.compare(startDate, joinTime) > 0) {
            logger.info("活动开始时间大于入群时间");
            return false;
        }
        if (limitDate != null) {
            endDate = limitDate;
        }
        logger.info("校验活动判断时间:{}", endDate);
        //入群时间大于结束时间
        if (DateUtil.compare(joinTime, endDate) > 0) {
            logger.info("入群时间大于结束时间");
            return false;
        }
        Integer inviteMemberType = activity.getInviteMemberType();
        if (Objects.equals(inviteMemberType, ChatActivityInviteMemberTypeEnum.OPEN_CARD.value)) {
            logger.info("邀请会员类型限制为开卡会员");
            String memberId = chatUser.getMemberId();
            if (StringUtils.isBlank(memberId)) {
                logger.info("memberId为空");
                return false;
            }
            MemberDTO member = memberService.getMember(memberId);
            if (member == null || StringUtils.isBlank(member.getCardNum())) {
                logger.info("会员为开卡");
                return false;
            }
        }
        TabGroupChatActivityInviteLog inviteLog = new TabGroupChatActivityInviteLog();
        inviteLog.setChatActivityId(context.getChatActivityId());
        inviteLog.setInviteeUserId(chatUser.getUserId());
        inviteLog.setEnterpriseId(context.getEnterpriseId());
        inviteLog.setInviterMemberId(context.getInviterMemberId());
        List<TabGroupChatActivityInviteLog> list = groupChatActivityInviteLogMapper.queryAll(inviteLog);
        if (CollectionUtils.isNotEmpty(list)) {
            logger.info("已有邀请记录:{}",JSON.toJSONString(inviteLog));
            return false;
        }
        return true;
    }

    /**
     * 获取本次入群有效状态
     *
     * @param context
     * @return
     */
    private Integer getActivityEffective(GroupChatActivityContext context) {
        GroupChatActivityDTO activity = context.getChatActivityDTO();
        String enterpriseId = activity.getEnterpriseId();
        String userId = context.getChatUser().getUserId();
        Long chatActivityId = context.getChatActivityId();
        Integer inviteType = activity.getInviteType();
        TabGroupChatActivityInviteLog inviteLog = new TabGroupChatActivityInviteLog();
        inviteLog.setChatActivityId(chatActivityId);
        inviteLog.setInviteeUserId(userId);
        inviteLog.setEnterpriseId(enterpriseId);
        List<TabGroupChatActivityInviteLog> list = groupChatActivityInviteLogMapper.queryAll(inviteLog);
        if (CollectionUtils.isNotEmpty(list)) {
            return ChatActivityInvalidInviteTypeEnum.ONE.value;
        }
        if (Objects.equals(ChatActivityInviteTypeEnum.NONE_GROUP_CHAT.value, inviteType)) {
            List<TabGroupChatUser> chatUserList = groupChatUserMapper.listByUserId(enterpriseId, userId, 1);
            if (CollectionUtils.isNotEmpty(chatUserList)) {
                return ChatActivityInvalidInviteTypeEnum.TWO.value;
            }
        }
        if (Objects.equals(ChatActivityInviteTypeEnum.FIRST_GROUP_CHAT.value, inviteType)) {
            List<TabGroupChatUser> chatUserList2 = groupChatUserMapper.listByUserId(enterpriseId, userId, null);
            if (CollectionUtils.isNotEmpty(chatUserList2)) {
                return ChatActivityInvalidInviteTypeEnum.THREE.value;
            }
        }
        return null;
    }

    /**
     * 获取完成批次
     * @param context
     * @return
     */
    private int getActivityBatchNumber(GroupChatActivityContext context) {
        GroupChatActivityDTO activity = context.getChatActivityDTO();
        String enterpriseId = activity.getEnterpriseId();
        String inviterMemberId = context.getInviterMemberId();
        Long chatActivityId = context.getChatActivityId();
        TabGroupChatActivityInviteLog inviteLog = new TabGroupChatActivityInviteLog();
        inviteLog.setChatActivityId(chatActivityId);
        inviteLog.setInviterMemberId(inviterMemberId);
        inviteLog.setEnterpriseId(enterpriseId);
        inviteLog.setInviteType(Constant.FLAG_TRUE);
        Long count = groupChatActivityInviteLogMapper.count(inviteLog) + 1;
        logger.info("有效邀请数:{}", count);
        Integer inviteRewardType = activity.getInviteRewardType();
        int batchNumber = -1;
        Map<Integer, List<GroupChatActivityRewardDTO>> rewardMap = activity.getRewardMap();
        List<GroupChatActivityRewardDTO> rewardDTOList = rewardMap.get(ChatActivityRewardInviteEnum.INVITER.value);
        if (Objects.equals(inviteRewardType, ChatActivityInviteRewardEnum.FIXED_REWARD.value)) {
            GroupChatActivityRewardDTO rewardDTO = rewardDTOList.get(0);
            Integer limitReward = rewardDTO.getLimitReward();
            Integer inviteNumber = rewardDTO.getInviteNumber();
            batchNumber = (count.intValue() + inviteNumber - 1) / inviteNumber;
            batchNumber = batchNumber > limitReward ? -1 : batchNumber;
        } else {
            List<GroupChatActivityRewardDTO> list = rewardDTOList.stream().sorted(Comparator.comparing(GroupChatActivityRewardDTO::getInviteNumber).reversed())
                    .collect(Collectors.toList());
            Integer maxInviteNumber = list.get(0).getInviteNumber();
            Integer minInviteNumber = list.get(list.size() - 1).getInviteNumber();
            batchNumber = list.get(0).getInviteLevel();
            if (count.intValue() > maxInviteNumber) {
                batchNumber = -1;
            }else if (count.intValue() <= minInviteNumber) {
                batchNumber = 1;
            } else {
                for (GroupChatActivityRewardDTO rewardDTO : list) {
                    Integer inviteNumber = rewardDTO.getInviteNumber();
                    if (count.intValue() == inviteNumber) {
                        batchNumber = rewardDTO.getInviteLevel();
                        break;
                    } else if (count.intValue() > inviteNumber) {
                        batchNumber = rewardDTO.getInviteLevel() + 1;
                        break;
                    }
                }
            }
        }
        logger.info("有效邀请批次:{}", batchNumber);
        return batchNumber;
    }

    private void saveChatActivityInvite(GroupChatActivityContext context,Integer batchNumber,Integer inviteType,Integer invalidInviteType) {
        TabGroupChatActivityInviteLog inviteLog = new TabGroupChatActivityInviteLog();
        inviteLog.setChatActivityInviteId(UniqueIdUtils.uniqueLong());
        inviteLog.setChatActivityId(context.getChatActivityId());
        inviteLog.setInviterMemberId(context.getInviterMemberId());
        TabGroupChatUser chatUser = context.getChatUser();
        if (StringUtils.isBlank(chatUser.getMemberId())) {
            inviteLog.setInviteeMemberId("-1");
        }else {
            inviteLog.setInviteeMemberId(chatUser.getMemberId());
        }
        inviteLog.setInviteeUserId(chatUser.getUserId());
        inviteLog.setInviteeUnionId(chatUser.getUnionid());
        inviteLog.setUserName(chatUser.getUserName());
        inviteLog.setNickName(chatUser.getNickName());
        inviteLog.setGroupChatId(chatUser.getGroupChatId());
        inviteLog.setInviteType(inviteType);
        inviteLog.setInvalidInviteType(invalidInviteType);
        inviteLog.setBatchNumber(batchNumber);
        inviteLog.setEnterpriseId(chatUser.getEnterpriseId());
        inviteLog.setWxEnterpriseId(chatUser.getWxEnterpriseId());
        groupChatActivityInviteLogMapper.insert(inviteLog);
    }

}
