package com.ruoyi.im.service.impl;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException;
import com.ruoyi.basic.service.YjAppUserService;
import com.ruoyi.common.core.domain.entity.AppUser;
import com.ruoyi.common.im.constant.IMConstant;
import com.ruoyi.common.im.enums.IMTerminalType;
import com.ruoyi.common.im.model.IMPrivateMessage;
import com.ruoyi.common.im.model.IMUserInfo;
import com.ruoyi.common.im.enums.MessageStatus;
import com.ruoyi.common.im.enums.MessageType;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.JpushClientUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.im.util.BeanUtils;
import com.ruoyi.common.im.util.ThreadPoolExecutorFactory;
import com.ruoyi.im.domain.PrivateMessage;
import com.ruoyi.im.domain.dto.PrivateMessageDTO;
import com.ruoyi.im.domain.vo.PrivateMessageVO;
import com.ruoyi.im.mapper.PrivateMessageMapper;
import com.ruoyi.im.service.FriendService;
import com.ruoyi.im.service.PrivateMessageService;
import com.ruoyi.im.util.SensitiveFilterUtil;
import com.ruoyi.imclient.IMClient;
import com.ruoyi.mall.domain.MemberCart;
import com.ruoyi.mall.domain.Product;
import com.ruoyi.mall.domain.UserFavorite;
import com.ruoyi.mall.domain.order.OrderItem;
import com.ruoyi.mall.domain.vo.AppOrderVO;
import com.ruoyi.mall.domain.vo.MemberCartVO;
import com.ruoyi.mall.mapper.MemberCartMapper;
import com.ruoyi.mall.mapper.OrderItemMapper;
import com.ruoyi.mall.mapper.UserFavoriteMapper;
import com.ruoyi.mall.service.UserFavoriteService;
import com.ruoyi.mall.service.impl.MemberCartService;
import com.ruoyi.mall.service.impl.OrderItemService;
import com.ruoyi.mall.service.impl.OrderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DeadlockLoserDataAccessException;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper, PrivateMessage>
    implements PrivateMessageService {

    private final FriendService friendService;
    private final YjAppUserService appUserService;
    private final IMClient imClient;
    private final SensitiveFilterUtil sensitiveFilterUtil;
    private static final ScheduledThreadPoolExecutor EXECUTOR = ThreadPoolExecutorFactory.getThreadPoolExecutor();

    @Override
    public PrivateMessageVO sendMessage(PrivateMessageDTO dto) {
        AppUser appUser= SecurityUtils.getAppLoginUser().getAppUser();
        //无需验证好友
        Boolean isFriends = friendService.isFriend(appUser.getId(), dto.getRecvId());
        if (Boolean.FALSE.equals(isFriends)) {
            friendService.addFriend(dto.getRecvId());
//            throw new GlobalException("您已不是对方好友，无法发送消息");
        }
        // 保存消息
        PrivateMessage msg = BeanUtils.copyProperties(dto, PrivateMessage.class);
        msg.setSendId(appUser.getId());
        msg.setStatus(MessageStatus.UNSEND.code());
        msg.setSendTime(new Date());
        // 过滤内容中的敏感词
        if (MessageType.TEXT.code().equals(dto.getType())) {
            msg.setContent(sensitiveFilterUtil.filter(dto.getContent()));
        }
        this.save(msg);
        // 推送消息
        PrivateMessageVO msgInfo = BeanUtils.copyProperties(msg, PrivateMessageVO.class);
        IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
        sendMessage.setSender(new IMUserInfo(appUser.getId(),1));
        sendMessage.setRecvId(msgInfo.getRecvId());
        sendMessage.setSendToSelf(true);
        sendMessage.setData(msgInfo);
        sendMessage.setSendResult(true);
        imClient.sendPrivateMessage(sendMessage);
        jpush(appUser.getId(),appUser.getNickName(),msg.getContent(),dto.getRecvId());
        log.info("发送私聊消息，发送id:{},接收id:{}，内容:{}", appUser.getId(), dto.getRecvId(), dto.getContent());
        return msgInfo;
    }

    public void jpush(Long sendId,String senderName,String contentd,Long recvId){
        if (ObjectUtil.isNotEmpty(recvId)){
            String registerId= appUserService.getById(recvId).getRegisterId();
            if (StrUtil.isNotBlank(registerId)){
                String msg = String.format(
                        "%s：%s",
                        senderName, contentd
                );
                Map<String, String> extras=new HashMap<>();
                extras.put("type","privateMessage");
                extras.put("senderId",sendId.toString());
                extras.put("pagePath","/pages/chatbox/chat-box");
                JpushClientUtil.pushByRegistrationId(Arrays.asList(registerId),"瑜伽汇",msg,extras);
            }
        }

    }
    @Transactional
    @Override
    public PrivateMessageVO recallMessage(Long id) {
        AppUser session = SecurityUtils.getAppLoginUser().getAppUser();
        PrivateMessage msg = this.getById(id);
        if (Objects.isNull(msg)) {
            throw new GlobalException("消息不存在");
        }
        if (!msg.getSendId().equals(session.getId())) {
            throw new GlobalException("这条消息不是由您发送,无法撤回");
        }
        if (System.currentTimeMillis() - msg.getSendTime().getTime() > IMConstant.ALLOW_RECALL_SECOND * 1000) {
            throw new GlobalException("消息已发送超过5分钟，无法撤回");
        }
        // 修改消息状态
        msg.setStatus(MessageStatus.RECALL.code());
        this.updateById(msg);
        // 生成一条撤回消息
        PrivateMessage recallMsg = new PrivateMessage();
        recallMsg.setSendId(session.getId());
        recallMsg.setStatus(MessageStatus.UNSEND.code());
        recallMsg.setSendTime(new Date());
        recallMsg.setRecvId(msg.getRecvId());
        recallMsg.setType(MessageType.RECALL.code());
        recallMsg.setContent(id.toString());
        this.save(recallMsg);
        // 推送消息
        PrivateMessageVO msgInfo = BeanUtils.copyProperties(recallMsg, PrivateMessageVO.class);
        IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
        sendMessage.setSender(new IMUserInfo(session.getId(), 1));//终端类型 1:app
        sendMessage.setRecvId(msgInfo.getRecvId());
        sendMessage.setData(msgInfo);
        imClient.sendPrivateMessage(sendMessage);
        log.info("撤回私聊消息，发送id:{},接收id:{}，内容:{}", msg.getSendId(), msg.getRecvId(), msg.getContent());
        return msgInfo;
    }
    @Override
    public void pullOfflineMessage(Long minId) {
        AppUser session=SecurityUtils.getAppLoginUser().getAppUser();
        // 获取当前用户的消息
        LambdaQueryWrapper<PrivateMessage> wrapper = Wrappers.lambdaQuery();
        // 只能拉取最近3个月的消息,移动端只拉取一个月消息
//        int months = session.getTerminal().equals(IMTerminalType.APP.code()) ? 1 : 3;
        int months = new Integer(1).equals(IMTerminalType.APP.code()) ? 1 : 3;
        Date minDate = DateUtils.addMonths(new Date(), -months);
        wrapper.gt(PrivateMessage::getId, minId);
        wrapper.ge(PrivateMessage::getSendTime, minDate);
        wrapper.eq(PrivateMessage::getStatus,MessageStatus.UNSEND.code());
        wrapper.and(wp -> wp.eq(PrivateMessage::getSendId, session.getId()).or()
                .eq(PrivateMessage::getRecvId, session.getId()));
        wrapper.orderByAsc(PrivateMessage::getId);
        List<PrivateMessage> messages = this.list(wrapper);
        // 异步推送消息
        EXECUTOR.execute(() -> {
            // 开启加载中标志
            this.sendLoadingMessage(true, session);
            for (PrivateMessage m : messages) {
                PrivateMessageVO vo = BeanUtils.copyProperties(m, PrivateMessageVO.class);
                IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
                sendMessage.setSender(new IMUserInfo(m.getSendId(), IMTerminalType.WEB.code()));
                sendMessage.setRecvId(session.getId());
                List<Integer> list=new ArrayList<>();
                list.add(1);
                sendMessage.setRecvTerminals(list);
                sendMessage.setSendToSelf(false);
                sendMessage.setData(vo);
                sendMessage.setSendResult(true);
                imClient.sendPrivateMessage(sendMessage);
            }
            // 关闭加载中标志
            this.sendLoadingMessage(false, session);
            log.info("拉取私聊消息，用户id:{},数量:{}", session.getId(), messages.size());
        });
    }

    @Override
    public List<PrivateMessageVO> findHistoryMessage(Long friendId, Long page, Long size) {
        page = page > 0 ? page : 1;
        size = size > 0 ? size : 10;
        Long userId = SecurityUtils.getUserId();
        long stIdx = (page - 1) * size;
        QueryWrapper<PrivateMessage> wrapper = new QueryWrapper<>();
        wrapper.lambda().and(
                        wrap -> wrap.and(wp -> wp.eq(PrivateMessage::getSendId, userId).eq(PrivateMessage::getRecvId, friendId))
                                .or(wp -> wp.eq(PrivateMessage::getRecvId, userId).eq(PrivateMessage::getSendId, friendId)))
                .ne(PrivateMessage::getStatus, MessageStatus.RECALL.code()).orderByDesc(PrivateMessage::getId)
                .last("limit " + stIdx + "," + size);

        List<PrivateMessage> messages = this.list(wrapper);
        List<PrivateMessageVO> messageInfos =
                messages.stream().map(m -> BeanUtils.copyProperties(m, PrivateMessageVO.class))
                        .collect(Collectors.toList());
        log.info("拉取聊天记录，用户id:{},好友id:{}，数量:{}", userId, friendId, messageInfos.size());
        return messageInfos;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void readedMessage(Long friendId) {
        AppUser session = SecurityUtils.getAppLoginUser().getAppUser();
        // 推送消息给自己，清空会话列表上的已读数量
        PrivateMessageVO msgInfo = new PrivateMessageVO();
        msgInfo.setType(MessageType.READED.code());
        msgInfo.setSendId(friendId);
        msgInfo.setRecvId(session.getId());
        IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
        sendMessage.setData(msgInfo);
        sendMessage.setSender(new IMUserInfo(friendId, 1));
        sendMessage.setSendToSelf(true);
        sendMessage.setSendResult(false);
        imClient.sendPrivateMessage(sendMessage);
        // 推送回执消息给对方，更新已读状态
        msgInfo = new PrivateMessageVO();
        msgInfo.setType(MessageType.RECEIPT.code());
        msgInfo.setSendId(session.getId());
        msgInfo.setRecvId(friendId);
        sendMessage = new IMPrivateMessage<>();
        sendMessage.setSender(new IMUserInfo(session.getId(), 1));
        sendMessage.setRecvId(friendId);
        sendMessage.setSendToSelf(false);
        sendMessage.setSendResult(false);
        sendMessage.setData(msgInfo);
        imClient.sendPrivateMessage(sendMessage);
        // 修改消息状态为已读
        LambdaUpdateWrapper<PrivateMessage> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(PrivateMessage::getSendId,friendId)
                    .eq(PrivateMessage::getRecvId, session.getId())
                    .eq(PrivateMessage::getStatus, MessageStatus.SENDED.code())
                    .set(PrivateMessage::getStatus, MessageStatus.READED.code());
        this.update(updateWrapper);
        log.info("消息已读，接收方id:{},发送方id:{}", session.getId(), friendId);
    }

    @Override
    public Long getMaxReadedId(Long friendId) {
        AppUser session=SecurityUtils.getAppLoginUser().getAppUser();
        LambdaQueryWrapper<PrivateMessage> wrapper = Wrappers.lambdaQuery();
        wrapper
                .eq(PrivateMessage::getSendId, session.getId())
                .eq(PrivateMessage::getRecvId, friendId)
                .eq(PrivateMessage::getStatus, MessageStatus.READED.code())
                .orderByDesc(PrivateMessage::getId)
                .select(PrivateMessage::getId).last("limit 1");
        PrivateMessage message = this.getOne(wrapper);
        if (Objects.isNull(message)) {
            return -1L;
        }
        return message.getId();
    }

    @Autowired
    private MemberCartMapper cartMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private UserFavoriteMapper favoriteMapper;

    @Override
    public Map getConsultProduct(Long storeId){
        Long userId = SecurityUtils.getAppLoginUser().getAppUser().getId();
        Map map=new HashMap<>();
        //订单
        List<OrderItem> orderItems= orderItemMapper.getList(storeId,userId);
        // /购物车
        List<MemberCartVO> cartList=cartMapper.getList(userId,storeId);

        // /收藏
        List<Product> favorites=favoriteMapper.getFavoriteList(userId,storeId);
        map.put("order",orderItems);
        map.put("cartList",cartList);
        map.put("favorites",favorites);

        return map;
    }
    private void sendLoadingMessage(Boolean isLoadding,  AppUser session) {

        PrivateMessageVO msgInfo = new PrivateMessageVO();
        msgInfo.setType(MessageType.LOADING.code());
        msgInfo.setContent(isLoadding.toString());
        IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
        sendMessage.setSender(new IMUserInfo(session.getId(),1));
        sendMessage.setRecvId(session.getId());
        List<Integer> list=new ArrayList<>();
        list.add(1);
        sendMessage.setRecvTerminals(list);
        sendMessage.setData(msgInfo);
        sendMessage.setSendToSelf(false);
        sendMessage.setSendResult(false);
        imClient.sendPrivateMessage(sendMessage);
    }




}
