package com.m2pool.chat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.m2pool.chat.config.CustomWebSocketConfig;
import com.m2pool.chat.constant.Destination;
import com.m2pool.chat.constant.ExceptionEnum;
import com.m2pool.chat.dto.WebsocketMessageDto;
import com.m2pool.chat.entity.ChatMessage;
import com.m2pool.chat.entity.ChatRoom;
import com.m2pool.chat.entity.StompPrincipal;
import com.m2pool.chat.mapper.ChatMessageMapper;
import com.m2pool.chat.mapper.ChatRoomMapper;
import com.m2pool.chat.service.StompService;
import com.m2pool.chat.vo.UserMessageVo;
import com.m2pool.common.core.web.Result.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.user.SimpUserRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.alibaba.nacos.client.utils.EnvUtil.LOGGER;
import static com.m2pool.chat.constant.UserType.CUSTOMER;

@Service
public class StompServiceImpl implements StompService {

    @Autowired
    private SimpUserRegistry userRegistry;

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @Resource
    private ChatMessageMapper chatMessageMapper;

    @Resource
    private ChatRoomMapper chatRoomMapper;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private CustomWebSocketConfig webSocketConfig;


    /**
     * key 为发送者+接受者 ，value 为 图片内容
     */
    //private final ConcurrentHashMap<String, String> imageContent = new ConcurrentHashMap<>();

    @Override
    public AjaxResult sendMessageToUser(StompPrincipal principal, UserMessageVo userMessageVo) {
        WebsocketMessageDto build = buildDto(principal, userMessageVo);
        //获取当前聊天室对象
        ChatRoom chatRoom = chatRoomMapper.selectOne(new LambdaQueryWrapper<ChatRoom>()
                .eq(ChatRoom::getUserOneEmail,userMessageVo.getEmail())
                .eq(ChatRoom::getUserTwoEmail,principal.getName()));
        build(chatRoom,userMessageVo,principal,build);
        messagingTemplate.convertAndSendToUser(principal.getName(), Destination.QUEUE_CUSTOMER + "/" + principal.getName(),build);
        messagingTemplate.convertAndSendToUser(userMessageVo.getEmail(), Destination.QUEUE_USER + "/" + userMessageVo.getEmail(),build);
        return AjaxResult.success("成功");
    }

    @Override
    public AjaxResult sendMessageToCustomer(StompPrincipal principal, UserMessageVo userMessageVo) {
        WebsocketMessageDto build = buildDto(principal, userMessageVo);
        ChatRoom chatRoom = chatRoomMapper.selectOne(new LambdaQueryWrapper<ChatRoom>()
                .eq(ChatRoom::getUserOneEmail, principal.getName())
                .eq(ChatRoom::getUserTwoEmail, userMessageVo.getEmail()));
        build(chatRoom,userMessageVo,principal,build);
        messagingTemplate.convertAndSendToUser(principal.getName(), Destination.QUEUE_USER + "/" + principal.getName(),build);
        messagingTemplate.convertAndSendToUser(userMessageVo.getEmail(), Destination.QUEUE_CUSTOMER + "/" + userMessageVo.getEmail(),build);

        return AjaxResult.success("成功");
    }

    public void build(ChatRoom chatRoom,UserMessageVo userMessageVo,StompPrincipal principal,WebsocketMessageDto build){
        if (chatRoom == null && userMessageVo.getRoomId() == null){
            throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.ROOM_NOT_EXIST));
        }
        if(chatRoom != null && userMessageVo.getRoomId() == null){
            userMessageVo.setRoomId(chatRoom.getId());
        }
        build.setRoomId(userMessageVo.getRoomId());
        int serviceReadNum = chatRoom != null ? chatRoom.getServiceReadNum() : 0;
        build.setClientReadNum(serviceReadNum + 1);
        Long id = executeTran(principal, userMessageVo, chatRoom);
        System.out.println("发送消息，聊天室id"+userMessageVo.getRoomId()+"发送者邮箱"+principal.getName()+"接受者邮箱"+userMessageVo.getEmail()+"消息id"+id);
        // 多端情况下，需要把消息发送给
        build.setId(id);
    }

    /**
     * 构建聊天实时返回信息
     * @param principal
     * @param userMessageVo
     * @return
     */
    private WebsocketMessageDto buildDto(StompPrincipal principal, UserMessageVo userMessageVo) {
        Boolean isCreate = principal.getIsCreate();
        WebsocketMessageDto build = WebsocketMessageDto.builder()
                .type(userMessageVo.getType())
                .content(userMessageVo.getContent())
                .sendEmail(principal.getName())
                .sendUserType(principal.getType())
                .sendTime(new Date())
                .isCreate(isCreate)
                .clientReadNum(0)
                .build();
        if (isCreate){
            principal.setIsCreate(false);
        }
        return build;
    }

    /**
     * 执行消息表新增消息和聊天室已读未读消息数量更新事务
     * @param principal
     * @param userMessageVo
     * @param chatRoom
     */
    private Long executeTran(StompPrincipal principal, UserMessageVo userMessageVo, ChatRoom chatRoom){
        final Long[] id = {0L};
        // 消息存储
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    // 插入消息并获取 ID
                     id[0] = insertMessage(principal, userMessageVo);
                    //聊天室，已读未读数量，更新。
                    updateRoom(chatRoom,principal.getType());
                } catch (Exception e) {
                    // 回滚事务
                    status.setRollbackOnly();
                    throw e;
                }
            }
        });
        return id[0];
    }

    /**
     * 检查用户是否在线
     * @return
     */
    private boolean checkOnline(UserMessageVo userMessageVo){

        return userRegistry.getUsers().stream()
                .anyMatch(user -> user.getName().equals(userMessageVo.getEmail()));
    }

    /**
     * 新增消息
     * @param userMessageVo
     * @return
     */
    private Long insertMessage(StompPrincipal principal,UserMessageVo userMessageVo){
        ChatMessage message = ChatMessage.builder()
                .sendEmail(principal.getName())
                .content(userMessageVo.getContent())
                .type(userMessageVo.getType())
                .roomId(userMessageVo.getRoomId())
                .build();
        chatMessageMapper.insert(message);
        return message.getId();
    }

    /**
     * 修改聊天信息
     * @param chatRoom 本次聊天聊天室信息
     * @param sendUserType 发送者类型
     * @param  {bool 废弃 发送者是否在线，不在线，需要更新未读消息数量}
     */
    private void updateRoom(ChatRoom chatRoom,Integer sendUserType){
        System.out.println("聊天室信息"+chatRoom);
        if(chatRoom != null){
            ChatRoom room = ChatRoom.builder().id(chatRoom.getId()).build();
            if (CUSTOMER.equals(sendUserType)) {
                room.setClientReadNum(chatRoom.getClientReadNum() + 1);
                room.setLastCustomerSendTime(LocalDateTime.now());
            } else {
                room.setServiceReadNum(chatRoom.getServiceReadNum() + 1);
                room.setLastUserSendTime(LocalDateTime.now());
            }
            chatRoomMapper.updateById(room);
        }

    }

    /**
     * 用于客服关闭断线客服端聊天室接口
     * @param userName 游客邮箱
     * @return
     */
    public void customerCloseRoom(String userName){
        //目前配置只配置了一个客服，如果多个关闭消息，需同时发送多个客服
        System.out.println("当前配置的客服"+webSocketConfig.getDefaultCustomerEmail());
        String[] split = webSocketConfig.getDefaultCustomerEmail().split(",");
        for (String email : split) {
            messagingTemplate.convertAndSendToUser(
                    email,
                    Destination.QUEUE_CLOSE_ROOM + email, userName);
        }
    }

}
