package com.sikey.wa04.business.infrastructure.adapter.dao;

import com.sikey.wa04.business.domain.adapter.MessageAdapter;
import com.sikey.wa04.business.domain.entity.ChatSessionId;
import com.sikey.wa04.business.domain.entity.UserId;
import com.sikey.wa04.business.domain.entity.message.Message;
import com.sikey.wa04.business.domain.entity.message.MessageId;
import com.sikey.wa04.business.domain.entity.message.MessageReceivedLog;
import com.sikey.wa04.business.infrastructure.dto.model.MessageRecvModel;
import com.sikey.wa04.business.infrastructure.dto.model.MessageSendModel;
import com.sikey.wa04.business.infrastructure.repository.MessageRecvRepository;
import com.sikey.wa04.business.infrastructure.repository.MessageSendRepository;
import com.sikey.wa04.common.enums.MessageStatus;
import com.sikey.wa04.common.enums.MessageType;
import com.sikey.wa04.common.utils.ObjectMapperUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * MessageAdapterImpl
 *
 * @author luoyangwei
 */
@Slf4j
@Component
public class MessageAdapterImpl implements MessageAdapter {

    @Resource
    private MessageSendRepository messageSendRepository;

    @Resource
    private MessageRecvRepository messageRecvRepository;

    @Override
    public void save(Message message) {
        MessageSendModel messageSendModel = new MessageSendModel();
        messageSendModel.setId(message.getId().getId());
        messageSendModel.setMsgType(message.getType().getValue());
        messageSendModel.setSendId(message.getSenderId());
        messageSendModel.setSendTime(message.getSendTime());
        messageSendModel.setContent(ObjectMapperUtil.convertValue(message.getContent(), ObjectMapperUtil.getValueTypeRef()));
        messageSendRepository.save(messageSendModel);
    }


    @Override
    public Message find(MessageId messageId) {
        Optional<MessageSendModel> messageSendModel = messageSendRepository.findById(messageId.getId());
        if (messageSendModel.isPresent()) {
            MessageSendModel sendModel = messageSendModel.get();
            return new Message()
                    .setId(messageId)
                    .setType(MessageType.valueOfMsg(sendModel.getMsgType()))
                    .setSenderId(sendModel.getSendId())
                    .setSendTime(sendModel.getSendTime())
                    .setContent(sendModel.getContent());
        }
        return new Message();
    }

    @Override
    public Integer unreadCount(UserId receiverId, ChatSessionId chatSessionId) {
        //获取聊天消息类型列表
        List<Integer> msgTypeList = MessageType.getChatMsgTypes();
        List<MessageRecvModel> messageRecvModels;
        if (chatSessionId.isGroup()) {
            messageRecvModels = messageRecvRepository.findByRecvIdAndGroupIdAndMsgTypeIn(receiverId.getId(), chatSessionId.getId(), msgTypeList);
        } else {
            messageRecvModels = messageRecvRepository.findByRecvIdAndSendIdAndMsgTypeIn(receiverId.getId(), chatSessionId.getId(), msgTypeList);
        }
        int unreadCount = (int) messageRecvModels.stream().filter(model ->
                model.getStatus().equals(MessageStatus.RECEIVED_ACK.getValue()) || model.getStatus().equals(MessageStatus.OFFLINE_QUEUE.getValue())
                        || model.getStatus().equals(MessageStatus.WAIT_ACK.getValue())).count();
        //log.info("[unreadCount未读消息]接收者：{}，会话id：{}，消息：{}；数量：{}", receiverId, JSONUtil.toJsonPrettyStr(chatSessionId),JSONUtil.toJsonPrettyStr(messageRecvModels), unreadCount);
        return unreadCount;
    }

    @Override
    public List<Message> findUnreadMessages(UserId receiverId, ChatSessionId chatSessionId) {
        //获取聊天消息类型列表
        List<Integer> msgTypeList = MessageType.getChatMsgTypes();
        List<MessageRecvModel> messageRecvModels;
        if (chatSessionId.isGroup()) {
            messageRecvModels = messageRecvRepository.findByRecvIdAndGroupIdAndMsgTypeIn(receiverId.getId(), chatSessionId.getId(), msgTypeList);
        } else {
            messageRecvModels = messageRecvRepository.findByRecvIdAndSendIdAndMsgTypeIn(receiverId.getId(), chatSessionId.getId(), msgTypeList);
        }

        List<Long> msgIds = messageRecvModels.stream()
                .filter(model -> model.getStatus().equals(MessageStatus.RECEIVED_ACK.getValue()) ||
                        model.getStatus().equals(MessageStatus.OFFLINE_QUEUE.getValue())
                        || model.getStatus().equals(MessageStatus.WAIT_ACK.getValue()))
                .map(MessageRecvModel::getMsgId)
                .distinct()
                .toList();

        //log.info("[findUnreadMessages未读消息]接收者：{}，会话id：{}，消息：{}；消息ID集合：{}", receiverId, JSONUtil.toJsonPrettyStr(chatSessionId),JSONUtil.toJsonPrettyStr(messageRecvModels), JSONUtil.toJsonPrettyStr(msgIds));
        if (msgIds.isEmpty()) {
            return List.of();
        }

        List<MessageSendModel> messageSendModels = messageSendRepository.findByIdIn(msgIds);

        List<Message> messages = new ArrayList<>();
        for (MessageSendModel messageSendModel : messageSendModels) {
            Message message = new Message()
                    .setId(new MessageId(messageSendModel.getId()))
                    .setType(MessageType.valueOfMsg(messageSendModel.getMsgType()))
                    .setContent(messageSendModel.getContent())
                    .setSenderId(messageSendModel.getSendId())
                    .setSendTime(messageSendModel.getSendTime())
                    .setGroup(chatSessionId.isGroup());
            messages.add(message);
        }

        // log.info("[未读消息]获取消息发送数据：{}，返回结果：{}", JSONUtil.toJsonPrettyStr(messageSendModels), JSONUtil.toJsonPrettyStr(messages));
        return messages;
    }

    @Override
    public List<Long> findUnreadMessagesAckId(UserId receiverId, ChatSessionId chatSessionId) {
        //获取聊天消息类型列表
        List<Integer> msgTypeList = MessageType.getChatMsgTypes();
        List<MessageRecvModel> messageRecvModels;
        if (chatSessionId.isGroup()) {
            messageRecvModels = messageRecvRepository.findByRecvIdAndGroupIdAndMsgTypeIn(receiverId.getId(), chatSessionId.getId(), msgTypeList);
        } else {
            messageRecvModels = messageRecvRepository.findByRecvIdAndSendIdAndMsgTypeIn(receiverId.getId(), chatSessionId.getId(), msgTypeList);
        }

        List<Long> ackIdList = messageRecvModels.stream()
                .filter(model -> model.getStatus().equals(MessageStatus.RECEIVED_ACK.getValue()) ||
                        model.getStatus().equals(MessageStatus.OFFLINE_QUEUE.getValue())
                        || model.getStatus().equals(MessageStatus.WAIT_ACK.getValue()))
                .map(MessageRecvModel::getId)
                .distinct()
                .toList();
        //log.info("[findUnreadMessagesAckId未读消息]接收者：{}，会话id：{}，消息：{}；ackIdList：{}", receiverId, JSONUtil.toJsonPrettyStr(chatSessionId),JSONUtil.toJsonPrettyStr(messageRecvModels), JSONUtil.toJsonPrettyStr(ackIdList));

        if (ackIdList.isEmpty()) {
            return List.of();
        }

        return ackIdList;
    }



    @Override
    public List<Message> findUnreadMessages(UserId receiverId, ChatSessionId chatSessionId, int pageNumber, int pageSize) {
        return List.of();
    }

    @Override
    public List<MessageReceivedLog> findReceivedLogs(MessageId messageId) {
        List<MessageReceivedLog> logs = new ArrayList<>();
        List<MessageRecvModel> messageRecvModels = messageRecvRepository.findByMsgId(messageId.getId());
        for (MessageRecvModel messageRecvModel : messageRecvModels) {
            logs.add(new MessageReceivedLog()
                    .setReceiverId(messageRecvModel.getRecvId())
                    .setReceivedTime(messageRecvModel.getCreatedAt())
                    .setAckId(messageRecvModel.getId())
                    .setStatus(MessageStatus.valueOf(messageRecvModel.getStatus())));
        }
        return logs;
    }

    @Override
    public void markAsRead(MessageReceivedLog receivedLog) {
        messageRecvRepository.updateStatusById(MessageStatus.READ.getValue(), receivedLog.getAckId());
    }

    /**
     * 标记为已读
     *
     * @param ackIdList 消息接收记录集合
     * @return
     */
    @Override
    public void markAsRead(List<Long> ackIdList) {
        messageRecvRepository.updateStatusByIdIn(MessageStatus.READ.getValue(), ackIdList);
    }
}
