package com.snack.server.module.chat.websocket;

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.service.ChatMessageService;
import com.snack.server.module.chat.service.ChatSessionService;
import com.snack.server.module.chat.vo.ChatMessageVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;

import java.security.Principal;
/**
 * WebSocket STOMP 控制器
 *
 * 客户端通过 /app/chat/* 发送消息，服务端通过 /user/queue/chat/* 点对点推送
 */
@Slf4j
@Controller
@RequiredArgsConstructor
public class ChatStompController {

    private final SimpMessagingTemplate messagingTemplate;
    private final ChatMessageService chatMessageService;
    private final ChatSessionService chatSessionService;

    /**
     * 发送消息
     *
     * 请求体: { sessionId, type, content, extra, clientMsgId }
     * 客户端订阅: /user/queue/chat/{sessionId}
     */
    @MessageMapping("/chat/send")
    public void handleSend(@Payload ChatSendMessageReq req, Principal principal) {
        if (principal == null) return;
        String[] parts = principal.getName().split(":");
        if (parts.length < 2) return;
        String loginType = parts[0]; // "user" or "admin"
        Long senderId = Long.parseLong(parts[1]);
        int senderType = "admin".equalsIgnoreCase(loginType) ? 1 : 0;

        try {
            ChatMessage message = chatMessageService.sendMessage(req, senderId, senderType);
            ChatMessageVO vo = chatMessageService.toVO(message);

            // 推送给会话参与方（点对点）
            messagingTemplate.convertAndSendToUser(
                    principal.getName(), "/queue/chat/" + req.getSessionId(), vo);

            log.debug("[ws] msg sent sessionId={} type={} from={}", req.getSessionId(), req.getType(), senderId);
        } catch (Exception e) {
            log.error("[ws] 发送消息失败: {}", e.getMessage());
            messagingTemplate.convertAndSendToUser(
                    principal.getName(), "/queue/chat/event",
                    new ErrorPayload("send_error", e.getMessage()));
        }
    }

    /**
     * 已读确认
     *
     * 请求体: { sessionId, lastSeq }
     */
    @MessageMapping("/chat/ack")
    public void handleAck(@Payload ChatAckReq req, Principal principal) {
        if (principal == null) return;
        String[] parts = principal.getName().split(":");
        boolean isAdmin = parts.length >= 2 && "admin".equalsIgnoreCase(parts[0]);

        try {
            chatMessageService.handleAck(req, isAdmin);
        } catch (Exception e) {
            log.error("[ws] ACK 失败: {}", e.getMessage());
        }
    }

    /**
     * 关闭会话
     */
    @MessageMapping("/chat/close")
    public void handleClose(@Payload CloseSessionReq req, Principal principal) {
        if (principal == null) return;
        String[] parts = principal.getName().split(":");
        if (parts.length < 2) return;
        boolean isAdmin = "admin".equalsIgnoreCase(parts[0]);
        Long operatorId = Long.parseLong(parts[1]);

        try {
            chatSessionService.closeSession(req.sessionId, operatorId, isAdmin);
            log.info("[ws] 会话 {} 关闭（{}:{}）", req.sessionId, parts[0], operatorId);
        } catch (Exception e) {
            log.error("[ws] 关闭会话失败: {}", e.getMessage());
        }
    }

    /**
     * 客服接管会话
     */
    @MessageMapping("/chat/accept")
    public void handleAccept(@Payload AcceptSessionReq req, Principal principal) {
        if (principal == null) return;
        String[] parts = principal.getName().split(":");
        if (!"admin".equalsIgnoreCase(parts[0])) return;
        Long adminId = Long.parseLong(parts[1]);

        try {
            chatSessionService.acceptByAdmin(req.sessionId, adminId, "");
            log.info("[ws] 客服 {} 接管会话 {}", adminId, req.sessionId);
        } catch (Exception e) {
            log.error("[ws] 接管失败: {}", e.getMessage());
        }
    }

    // --- 内部结构 ---

    public record ErrorPayload(String type, String message) {
    }

    public record CloseSessionReq(Long sessionId) {
    }

    public record AcceptSessionReq(Long sessionId) {
    }
}
