package com.ruoyi.im.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.service.YjAppUserService;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.im.constant.RedisKey;
import com.ruoyi.common.im.enums.MessageStatus;
import com.ruoyi.common.im.enums.MessageType;
import com.ruoyi.common.im.model.IMGroupMessage;
import com.ruoyi.common.im.model.IMUserInfo;
import com.ruoyi.common.im.util.BeanUtils;
import com.ruoyi.common.im.util.CommaTextUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.im.domain.Friend;
import com.ruoyi.im.domain.Group;
import com.ruoyi.im.domain.GroupMember;
import com.ruoyi.im.domain.GroupMessage;
import com.ruoyi.im.domain.dto.GroupInviteDTO;
import com.ruoyi.im.domain.vo.GroupMemberVO;
import com.ruoyi.im.domain.vo.GroupMessageVO;
import com.ruoyi.im.domain.vo.GroupVO;
import com.ruoyi.im.mapper.GroupMapper;
import com.ruoyi.im.mapper.GroupMessageMapper;
import com.ruoyi.im.service.FriendService;
import com.ruoyi.im.service.GroupMemberService;
import com.ruoyi.im.service.GroupService;
import com.ruoyi.imclient.IMClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Slf4j
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP)
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements GroupService {
    private final YjAppUserService userService;
    private final GroupMemberService  groupMemberService;
    private final GroupMessageMapper groupMessageMapper;
    private final IMClient imClient;

    @Override
    @Transactional
    public GroupVO createGroup(GroupVO vo) {
        AppUser user = SecurityUtils.getAppLoginUser().getAppUser();
        //沟通群是否存在
       Long groupId= this.baseMapper.groupExist(user.getId(),vo.getCustomerService(),vo.getInstructor());
       if (ObjectUtil.isNotEmpty(groupId)){
           return findById(groupId);
       }

       //建群
        AppUser customer=userService.getById(vo.getCustomerService()) ;
        if (ObjectUtil.isEmpty(customer)){
            throw new GlobalException("客服信息失效,跳转失败");
        }
        AppUser instructor=userService.getById(vo.getInstructor()) ;
        if (ObjectUtil.isEmpty(instructor)){
            throw new GlobalException("教练信息失效,跳转失败");
        }

        // 保存群组数据
        Group group = BeanUtils.copyProperties(vo, Group.class);
        group.setName(vo.getProductName()+" - "+user.getNickName()+"群");
        group.setOwnerId(user.getId());
        this.save(group);

        // 把群主加入群
        addMember(group.getId(),user);

        //课程顾问
        addMember(group.getId(),customer);

        //教练
        addMember(group.getId(),instructor);


        GroupVO groupVo = findById(group.getId());
        // 推送同步消息给自己的其他终端
        // sendAddGroupMessage(groupVo, Lists.newArrayList(), true);
        // 推送进入群聊消息
        List<Long> userIds = groupMemberService.findUserIdsByGroupId(group.getId());
        String content = String.format("'%s'邀请'%s'加入了群聊"
                , user.getNickName()
                , customer.getNickName()+","+instructor.getNickName());
        this.sendTipMessage(group.getId(), userIds, content, true);
        // 返回
        log.info("创建群聊，群聊id:{},群聊名称:{}", group.getId(), group.getName());
        return groupVo;
    }

    void addMember(Long groupId,AppUser user){
        GroupMember member = new GroupMember();
        member.setGroupId(groupId);
        member.setUserId(user.getId());
        member.setHeadImage(user.getAvatar());
        member.setUserNickName(user.getNickName());
        member.setRemarkNickName(user.getNickName());
        member.setRemarkGroupName(user.getNickName());
        member.setCreatedTime(new Date());
        member.setQuit(false);
        groupMemberService.save(member);
    }


    @Override
    public GroupVO findById(Long groupId) {
        Group group = super.getById(groupId);
        if (Objects.isNull(group)) {
            throw new GlobalException("群组不存在");
        }
        GroupMember member = groupMemberService.findByGroupAndUserId(groupId, SecurityUtils.getAppLoginUser().getAppUserId());
        if (Objects.isNull(member)) {
            throw new GlobalException("您未加入群聊");
        }
        return convert(group, member);
    }


    @Override
    public List<GroupVO> findGroups() {
        // 查询当前用户的群id列表
        List<GroupMember> groupMembers = groupMemberService.findByUserId(SecurityUtils.getAppLoginUser().getAppUserId());
        // 一个月内退的群可能存在退群前的离线消息,一并返回作为前端缓存
        groupMembers.addAll(groupMemberService.findQuitInMonth(SecurityUtils.getAppLoginUser().getAppUserId()));
        if (groupMembers.isEmpty()) {
            return new LinkedList<>();
        }
        // 拉取群列表
        List<Long> ids = groupMembers.stream().map((GroupMember::getGroupId)).collect(Collectors.toList());
        LambdaQueryWrapper<Group> groupWrapper = Wrappers.lambdaQuery();
        groupWrapper.in(Group::getId, ids);
        List<Group> groups = this.list(groupWrapper);
        // 转vo
        return groups.stream().map(group -> {
            GroupMember member =
                groupMembers.stream().filter(m -> group.getId().equals(m.getGroupId())).findFirst().get();
            return convert(group, member);
        }).collect(Collectors.toList());
    }
    @Cacheable(key = "#groupId")
    @Override
    public Group getAndCheckById(Long groupId) {
        Group group = super.getById(groupId);
        if (Objects.isNull(group)) {
            throw new GlobalException("群组不存在");
        }
        if (group.getDissolve()) {
            throw new GlobalException("群组'" + group.getName() + "'已解散");
        }
        if (group.getIsBanned()) {
            throw new GlobalException("群组'" + group.getName() + "'已被封禁,原因:" + group.getReason());
        }
        return group;
    }

    private void sendTipMessage(Long groupId, List<Long> recvIds, String content, Boolean sendToAll) {
        AppUser session = SecurityUtils.getAppLoginUser().getAppUser();
        // 消息入库
        GroupMessage message = new GroupMessage();
        message.setContent(content);
        message.setType(MessageType.TIP_TEXT.code());
        message.setStatus(MessageStatus.UNSEND.code());
        message.setSendTime(new Date());
        message.setSendNickName(session.getNickName());
        message.setGroupId(groupId);
        message.setSendId(session.getId());
        message.setRecvIds(sendToAll ? "" : CommaTextUtils.asText(recvIds));
        groupMessageMapper.insert(message);
        // 推送
        GroupMessageVO msgInfo = BeanUtils.copyProperties(message, GroupMessageVO.class);
        IMGroupMessage<GroupMessageVO> sendMessage = new IMGroupMessage<>();
        sendMessage.setSender(new IMUserInfo(session.getId(), 1));
        if (CollUtil.isEmpty(recvIds)) {
            // 为空表示向全体发送
            List<Long> userIds = groupMemberService.findUserIdsByGroupId(groupId);
            sendMessage.setRecvIds(userIds);
        } else {
            sendMessage.setRecvIds(recvIds);
        }
        sendMessage.setData(msgInfo);
        sendMessage.setSendResult(false);
        sendMessage.setSendToSelf(false);
        imClient.sendGroupMessage(sendMessage);
    }

    private GroupVO convert(Group group, GroupMember member) {
        List<Long> members = groupMemberService.findUserIdsByGroupId(group.getId());
        List<Long> OtherMembers=members.stream().filter(it->!it.equals(member.getUserId())).collect(Collectors.toList());
        GroupVO vo = BeanUtils.copyProperties(group, GroupVO.class);
        vo.setRemarkGroupName(member.getRemarkGroupName());
        vo.setRemarkNickName(member.getRemarkNickName());
        vo.setShowNickName(member.getShowNickName());
        vo.setShowGroupName(StrUtil.blankToDefault(member.getRemarkGroupName(), group.getName()));
        vo.setQuit(member.getQuit());
        vo.setCustomerService(OtherMembers.get(0));//客服id
        vo.setInstructor(OtherMembers.get(1));//教练id
        return vo;
    }

    private void sendAddGroupMessage(GroupVO group, List<Long> recvIds, Boolean sendToSelf) {
        GroupMessageVO msgInfo = new GroupMessageVO();
        msgInfo.setContent(JSON.toJSONString(group));
        msgInfo.setType(MessageType.GROUP_NEW.code());
        msgInfo.setSendTime(new Date());
        msgInfo.setGroupId(group.getId());
        msgInfo.setSendId(SecurityUtils.getAppLoginUser().getAppUserId());
        IMGroupMessage<GroupMessageVO> sendMessage = new IMGroupMessage<>();
        sendMessage.setSender(new IMUserInfo(SecurityUtils.getAppLoginUser().getAppUserId(), 1));
        sendMessage.setRecvIds(recvIds);
        sendMessage.setData(msgInfo);
        sendMessage.setSendResult(false);
        sendMessage.setSendToSelf(sendToSelf);
        imClient.sendGroupMessage(sendMessage);
    }
    @Override
    public List<GroupMemberVO> findGroupMembers(Long groupId) {
        Group group = getAndCheckById(groupId);
        List<GroupMember> members = groupMemberService.findByGroupId(groupId);
        List<Long> userIds = members.stream().map(GroupMember::getUserId).collect(Collectors.toList());
        List<Long> onlineUserIds = imClient.getOnlineUser(userIds);
        return members.stream().map(m -> {
            GroupMemberVO vo = BeanUtils.copyProperties(m, GroupMemberVO.class);
            vo.setShowNickName(m.getShowNickName());
            vo.setShowGroupName(StrUtil.blankToDefault(m.getRemarkGroupName(), group.getName()));
            vo.setOnline(onlineUserIds.contains(m.getUserId()));
            return vo;
        }).sorted((m1, m2) -> m2.getOnline().compareTo(m1.getOnline())).collect(Collectors.toList());
    }

}
