/* (C) 2022 YiRing, Inc. */
package com.yiring.websocket.web;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.util.Auths;
import com.yiring.common.constant.DateFormatter;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.websocket.domain.Reply;
import com.yiring.websocket.domain.StompPrincipal;
import com.yiring.websocket.registry.StompUserRegistry;
import java.time.LocalDateTime;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.simp.user.SimpUser;
import org.springframework.messaging.simp.user.SimpUserRegistry;
import org.springframework.stereotype.Controller;

/**
 * STOMP Receiver Controller
 *
 * @author ifzm
 * @version 0.1
 * 2019/9/28 23:13
 */

@Slf4j
@Controller
@RequiredArgsConstructor
public class StompReceiver {

    final Auths auths;
    final SimpMessagingTemplate simpMessagingTemplate;
    final SimpUserRegistry simpUserRegistry;
    final StompUserRegistry stompUserRegistry;

    /**
     * 登录
     *
     * @param accessor StompHeaderAccessor
     */
    @MessageMapping("/login")
    @SendToUser("/topic/notice")
    public Result<Reply> login(StompHeaderAccessor accessor, String token) {
        try {
            User user = auths.getUserByToken(token);
            StompPrincipal principal = (StompPrincipal) accessor.getUser();
            assert principal != null;
            principal.setType(StompPrincipal.Type.LOGIN_USER);
            principal.setUser(user.getUsername());
            accessor.setUser(principal);
            stompUserRegistry.updateUser(accessor.getSessionId(), principal);
            log.info("STOMP user `{}` login success.", principal.getUser());

            // 构建回复结果
            Reply reply = Reply.builder().from(accessor.getDestination()).data(user.getUsername()).build();
            return Result.ok(reply);
        } catch (Exception e) {
            return Result.no(Status.UNAUTHORIZED);
        }
    }

    /**
     * 更新用户状态
     *
     * @param accessor 访问器
     */
    @MessageMapping("/state")
    public void state(StompHeaderAccessor accessor, String message) {
        log.info("收到来自 STOMP Client `/app/state` 消息：{}", message);

        StompPrincipal principal = (StompPrincipal) accessor.getUser();
        assert principal != null;
        principal.setOptions(JSON.parseObject(message));
        accessor.setUser(principal);
        log.info("principal info: {}", principal);

        stompUserRegistry.updateUser(accessor.getSessionId(), principal);
    }

    /**
     * 测试 ping
     *
     * @param accessor StompHeaderAccessor
     * @param message  消息
     * @return Result<Reply>
     */
    @MessageMapping("/ping")
    @SendToUser("/topic/notice")
    public Result<Reply> ping(StompHeaderAccessor accessor, String message) {
        log.info("收到来自 STOMP Client `/app/ping` 消息：{}", message);

        Set<SimpUser> simpUsers = simpUserRegistry.getUsers();
        log.info("SimpUsers: {}", simpUsers);

        Set<StompPrincipal> stompPrincipals = stompUserRegistry.getUsers();
        log.info("StompPrincipals: {}", stompPrincipals);

        JSONObject body = new JSONObject();
        body.put("message", "pong");
        body.put("time", DateFormatter.DATE_TIME.format(LocalDateTime.now()));

        // 构建回复结果
        Reply reply = Reply.builder().from(accessor.getDestination()).data(body).build();
        return Result.ok(reply);
    }
}
