package com.ym.mec.biz.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ym.mec.biz.dal.dto.WebSocketClientDetail;
import com.ym.mec.biz.dal.dto.WebSocketInfo;
import com.ym.mec.biz.dal.enums.WebsocketTypeEnum;
import com.ym.mec.biz.service.WebSocketEventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author Joburgess
 * @Date 2021/6/9 0009
 */
@Service
public class WebSocketHandler extends AbstractWebSocketHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketHandler.class);

    /**
     * @describe 存储客户端链接
     */
    public static final Map<String, WebSocketClientDetail> WS_CLIENTS = new ConcurrentHashMap<>();

    private static Map<WebsocketTypeEnum, WebSocketEventHandler> appMap = new ConcurrentHashMap<>();

    /**
     * @describe 注册应用
     * @author Joburgess
     * @date 2021/8/5 0005
     * @param websocketType:
     * @param webSocketEventHandler:
     * @return boolean
     */
    public static boolean regist(WebsocketTypeEnum websocketType, WebSocketEventHandler webSocketEventHandler){
        if (appMap.containsKey(websocketType)){
            return false;
        }
        appMap.put(websocketType, webSocketEventHandler);
        return true;
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String phone = session.getPrincipal().getName().split(":")[1];
        if(WS_CLIENTS.containsKey(phone)){
            WS_CLIENTS.get(phone).getSession().close();
        }
        LOGGER.info("{}上线", phone);
        WS_CLIENTS.put(phone, new WebSocketClientDetail(session, System.currentTimeMillis()));
        appMap.values().forEach(e->e.afterConnectionEstablished(session, phone));
        super.afterConnectionEstablished(session);
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        super.handleMessage(session, message);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message){
        String phone = session.getPrincipal().getName().split(":")[1];
        LOGGER.info("{}: {}", phone, message.getPayload());
        WebSocketInfo<JSONObject> webSocketInfo = JSON.parseObject(message.getPayload(), WebSocketInfo.class);

        if(Objects.isNull(webSocketInfo.getHeader().getType())){
            webSocketInfo.getHeader().setType(WebsocketTypeEnum.SOUND_COMPARE);
        }

        appMap.get(webSocketInfo.getHeader().getType()).receiveTextMessage(session, phone, webSocketInfo);
    }

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
        String phone = session.getPrincipal().getName().split(":")[1];
        appMap.values().forEach(e->e.receiveBinaryMessage(session, phone, message));
    }

    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
        super.handlePongMessage(session, message);
        LOGGER.info("心跳信息：{}", new String(message.getPayload().array(), "utf-8"));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        String phone = session.getPrincipal().getName().split(":")[1];
        session.close();
        LOGGER.info("{}异常: {}", phone, exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        String phone = session.getPrincipal().getName().split(":")[1];
        LOGGER.info("{}离线: {}s", phone, (System.currentTimeMillis() - WS_CLIENTS.get(phone).getLoginTime())/1000);
        appMap.values().forEach(e->e.afterConnectionClosed(session, phone));
        session.close();
        WS_CLIENTS.remove(phone);
    }

    @Override
    public boolean supportsPartialMessages() {
        return super.supportsPartialMessages();
    }

    /**
     * @describe 发送文本消息
     * @author Joburgess
     * @date 2021/8/23 0023
     * @param phone: 接收人手机号
     * @param message:
     * @return boolean
     */
    public static <T> boolean sendTextMessage(String phone, T message){
        if(!WS_CLIENTS.containsKey(phone)||!WS_CLIENTS.get(phone).getSession().isOpen()){
            return false;
        }
        try {
            WS_CLIENTS.get(phone).getSession().sendMessage(new TextMessage(JSON.toJSONString(message)));
        } catch (IOException e) {
            LOGGER.error("消息发送失败:{}", e);
            return false;
        }
        return true;
    }
}
