package com.snack.server.module.chat.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.snack.server.common.ResultCode;
import com.snack.server.exception.BusinessException;
import com.snack.server.module.chat.dto.req.ChatAckReq;
import com.snack.server.module.chat.dto.req.ChatSendMessageReq;
import com.snack.server.module.chat.entity.ChatMessage;
import com.snack.server.module.chat.entity.ChatSession;
import com.snack.server.module.chat.mapper.ChatMessageMapper;
import com.snack.server.module.chat.mapper.ChatSessionMapper;
import com.snack.server.module.chat.service.ChatMessageService;
import com.snack.server.module.chat.vo.ChatMessageVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 客服消息服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ChatMessageServiceImpl implements ChatMessageService {

    private final ChatMessageMapper chatMessageMapper;
    private final ChatSessionMapper chatSessionMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChatMessage sendMessage(ChatSendMessageReq req, Long senderId, Integer senderType) {
        // 1. 校验会话存在
        ChatSession session = chatSessionMapper.selectById(req.getSessionId());
        if (session == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "会话不存在");
        }

        // 2. 计算新 seq
        long newSeq = Math.max(session.getUserSeq() != null ? session.getUserSeq() : 0L,
                session.getAdminSeq() != null ? session.getAdminSeq() : 0L) + 1;

        // 3. 写消息
        ChatMessage msg = new ChatMessage();
        msg.setSessionId(req.getSessionId());
        msg.setSeq(newSeq);
        msg.setSenderId(senderId);
        msg.setSenderType(senderType);
        msg.setType(req.getType());
        msg.setContent(req.getContent());
        msg.setExtra(req.getExtra());
        msg.setIsRecalled(0);
        chatMessageMapper.insert(msg);

        // 4. 更新会话摘要
        ChatSession update = new ChatSession();
        update.setId(req.getSessionId());
        update.setLastMessage(req.getContent());
        update.setLastTime(msg.getCreateTime());
        chatSessionMapper.updateById(update);

        // 5. 累加未读
        if (senderType == 0) {
            chatSessionMapper.incrAdminUnread(req.getSessionId(), 1);
        } else {
            chatSessionMapper.incrUserUnread(req.getSessionId(), 1);
        }

        log.debug("[chat] msg saved sessionId={} seq={} type={}", req.getSessionId(), newSeq, req.getType());
        return msg;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleAck(ChatAckReq req, boolean isAdmin) {
        ChatSession session = chatSessionMapper.selectById(req.getSessionId());
        if (session == null) return;

        Long currentSeq = isAdmin ? session.getAdminSeq() : session.getUserSeq();
        if (req.getLastSeq() == null || (currentSeq != null && req.getLastSeq() <= currentSeq)) {
            return; // 不后退
        }

        ChatSession update = new ChatSession();
        update.setId(req.getSessionId());
        if (isAdmin) {
            update.setAdminSeq(req.getLastSeq());
            update.setAdminUnread(0);
        } else {
            update.setUserSeq(req.getLastSeq());
            update.setUserUnread(0);
        }
        chatSessionMapper.updateById(update);
    }

    @Override
    public List<ChatMessageVO> getMessages(Long sessionId, Long afterSeq, int limit) {
        LambdaQueryWrapper<ChatMessage> wrapper = new LambdaQueryWrapper<ChatMessage>()
                .eq(ChatMessage::getSessionId, sessionId)
                .gt(afterSeq != null && afterSeq > 0, ChatMessage::getSeq, afterSeq)
                .orderByAsc(ChatMessage::getSeq);
        if (limit > 0) {
            wrapper.last("LIMIT " + limit);
        }
        List<ChatMessage> list = chatMessageMapper.selectList(wrapper);
        return list.stream().map(this::toVO).toList();
    }

    @Override
    public List<ChatMessageVO> getMessagesSince(Long sessionId, Long lastAckSeq) {
        return getMessages(sessionId, lastAckSeq, 0);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChatMessageVO recallMessage(Long sessionId, Long messageId, Long operatorId, boolean isAdmin) {
        ChatMessage msg = chatMessageMapper.selectById(messageId);
        if (msg == null || !msg.getSessionId().equals(sessionId)) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "消息不存在");
        }
        if (msg.getIsRecalled() != null && msg.getIsRecalled() == 1) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "消息已被撤回");
        }
        // 只有本人或客服可撤回
        if (!isAdmin && !msg.getSenderId().equals(operatorId)) {
            throw new BusinessException(ResultCode.FORBIDDEN);
        }
        msg.setIsRecalled(1);
        chatMessageMapper.updateById(msg);
        return toVO(msg);
    }

    @Override
    public ChatMessageVO toVO(ChatMessage msg) {
        if (msg == null) return null;
        ChatMessageVO vo = new ChatMessageVO();
        BeanUtil.copyProperties(msg, vo);
        return vo;
    }
}
