package net.northking.cctp.mobile.socket;

import com.alibaba.fastjson.JSON;
import com.hzbank.testteam.autotest.dependencies.authDependency.constants.AuthDependencyConstants;
import com.hzbank.testteam.autotest.dependencies.authDependency.dto.TokenValueDTO;
import com.hzbank.testteam.autotest.dependencies.baseDefineDependency.utils.SpringUtil;
import net.northking.cctp.common.exception.PlatformRuntimeException;
import net.northking.cctp.mobile.constants.DeviceConstants;
import net.northking.cctp.mobile.constants.MobileConnectionConstants;
import net.northking.cctp.mobile.db.service.MobileConnectService;
import net.northking.cctp.mobile.entity.UpperWSResponse;
import net.northking.cctp.mobile.util.SpringUtils;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint("/pub/connectMobile")
public class MobileSessionManager {

    private final Logger logger = LoggerFactory.getLogger(MobileSessionManager.class);

    /**
     * 下面的key都是session对应的id
     */
    private Map<String, String> deviceIdMap = new ConcurrentHashMap<>();

    private Map<String, String> sessionIdMap = new ConcurrentHashMap<>();

    private Map<String, String> reportIdMap = new ConcurrentHashMap<>();

    @PostConstruct
    public void init() {
        logger.info("Init web session manager ...");
    }

    /**
     * 与界面建立Websocket会话
     *
     * @param session 会话对象
     */
    @OnOpen
    public void onOpen(Session session) {
        String queryString = session.getQueryString();
        Map<String, String> queryParams = decodeQueryString(queryString);
        logger.info("收到页面建立连接请求:[queryString:{},localSessionId:{}]", queryString, session.getId());
        String userToken = queryParams.get(DeviceConstants.AUTHORIZATION);
        String sessionId = queryParams.get(DeviceConstants.KEY_SESSION_ID);
        String deviceToken = queryParams.get(DeviceConstants.KEY_DEVICE_TOKEN);
        String reportId = queryParams.get(DeviceConstants.KEY_REPORT_ID);
        String mode = queryParams.get(DeviceConstants.KEY_MODE);
        if (StringUtils.isNotBlank(mode)) {
            logger.debug("deviceToken:[{}]直播连接视频",deviceToken);
        }else {
            logger.debug("deviceToken:[{}]录制连接视频",deviceToken);
        }
        if (StringUtils.isBlank(sessionId)) {
            UpperWSResponse response = buildErrorMessage(null, "sessionId为空");
            sendErrorMessageToWeb(session,JSON.toJSONString(response));
//            closeSession(session, CloseReason.CloseCodes.CANNOT_ACCEPT,"sessionId不能为空");
            return;
        }
        sessionIdMap.put(session.getId(), sessionId);
        if (StringUtils.isBlank(userToken) || (!authorize(sessionId, userToken))) {
            UpperWSResponse response = buildErrorMessage(null, "用户认证失败");
            sendErrorMessageToWeb(session,JSON.toJSONString(response));
//            closeSession(session, CloseReason.CloseCodes.CANNOT_ACCEPT,"用户认证失败");
            return;
        }
        if (StringUtils.isBlank(deviceToken)) {
            UpperWSResponse response = buildErrorMessage(null, "设备token不能为空");
            sendErrorMessageToWeb(session,JSON.toJSONString(response));
//            closeSession(session, CloseReason.CloseCodes.CANNOT_ACCEPT,"设备token不能为空");
            return;
        }
        if (StringUtils.isNotBlank(reportId)) {
            logger.info("该sessionId:{},链接是真机连接,reportId:{}",sessionId,reportId);
            reportIdMap.put(session.getId(), reportId);
        }
        session.setMaxTextMessageBufferSize(50 * 1024 * 1024);
        session.setMaxBinaryMessageBufferSize(50 * 1024 * 1024);
        String deviceId = SpringUtils.getBean(MobileConnectService.class).getDeviceIdByToken(deviceToken);
        if (StringUtils.isBlank(deviceId)) {
            logger.debug("未获取到设备id对应的设备token:{}", deviceToken);
            UpperWSResponse response = buildErrorMessage(null, "根据设备token获取设备id为空");
            sendErrorMessageToWeb(session,JSON.toJSONString(response));
//            closeSession(session, CloseReason.CloseCodes.CANNOT_ACCEPT,"根据设备token获取设备id为空！");
            return;
        }
        deviceIdMap.put(session.getId(), deviceId);
        try {
            SpringUtils.getBean(MobileConnectService.class).prepareConnectionEnvironment(sessionId, session, deviceToken,deviceId,userToken,mode);
        } catch (PlatformRuntimeException e) {
            UpperWSResponse response = buildErrorMessage(null, e.getMessage());
            sendErrorMessageToWeb(session,JSON.toJSONString(response));
//            closeSession(session,CloseReason.CloseCodes.NORMAL_CLOSURE ,e.getMessage());
        }
        logger.info("手机连接环境准备完成[sessionId:{},deviceId:{}]", sessionId,deviceId);
    }


    /**
     * 根据token认证用户信息
     *
     * @param token
     * @param sessionId
     * @return
     */
    private boolean authorize(String sessionId, String token) {
        RedissonClient redisson = SpringUtil.getBean(RedissonClient.class);
        RBucket<TokenValueDTO> tokenValueDTORBucket = redisson.getBucket(AuthDependencyConstants.TOKEN_PREFIX + token);
        TokenValueDTO tokenValueDTO = tokenValueDTORBucket.get();
        if (tokenValueDTO != null ) {
            SpringUtils.getBean(MobileConnectService.class).addUserToken(sessionId, token);
            return true;
        }
        return false;
    }

//    /**
//     * todo:加锁校验设备token是否过期
//     *
//     * @param deviceToken
//     * @param sessionId
//     * @return
//     */
//    private boolean authorizeDeviceToken(String sessionId, String deviceToken) {
//            //存入deviceToken
//            List<String> oldTokens = SpringUtils.getBean(MobileConnectService.class).getDeviceToken(sessionId);
//            if (CollectionUtils.isEmpty(oldTokens)) {
//                oldTokens = new ArrayList<>();
//            }
//            oldTokens.add(deviceToken);
//            SpringUtils.getBean(MobileConnectService.class).addDeviceToken(sessionId, oldTokens);
//            return true;
//    }

    private Map<String, String> decodeQueryString(String queryString) {
        Map<String, String> queryParams = new HashMap<>();
        if (StringUtils.isNotBlank(queryString)) {
            String[] queryParamStrs = StringUtils.split(queryString, "[&]");
            if (queryParams != null && queryParamStrs.length > 0) {
                for (String paramStr : queryParamStrs) {
                    String[] param = StringUtils.split(paramStr, "=");
                    queryParams.put(param[0], param[1]);
                }
            }
        }
        return queryParams;
    }

    /**
     * 关闭调试会话
     *
     * @param session
     */
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        String localSessionId = session.getId();
        String sessionId = sessionIdMap.remove(localSessionId);
        if (StringUtils.isNotBlank(sessionId)) {
            logger.info("收到页面关闭连接请求:[sessionId:{},localSessionId:{}]", sessionId, localSessionId);
            if (null != closeReason) {
                logger.info("关闭代码：{}", closeReason.getCloseCode().getCode());
                logger.info("关闭原因：{}", closeReason.getReasonPhrase());
                logger.info("关闭原因：{}", JSON.toJSONString(closeReason));
            }
        } else {
            logger.info("未获取到页面的sessionId:[sessionId:{},localSessionId:{}]", sessionId, localSessionId);
        }
        String deviceId = deviceIdMap.remove(localSessionId);
        if (StringUtils.isNotBlank(deviceId)) {
            logger.debug("移除sessionId:[{}]，连接的deviceId:[{}]",sessionId,deviceId);
            SpringUtils.getBean(MobileConnectService.class).closeMobileConnection(deviceId);
        } else {
            logger.info("未获取到此次设备连接的设备id:[localSessionId:{}]", session.getId());
        }
        String reportId = reportIdMap.remove(localSessionId);
        logger.debug("移除sessionId:[{}]，连接的reportId:[{}]",sessionId,reportId);
        logger.info("成功关闭调试会话[sessionId:{},deviceId:{}]", sessionId,deviceId);
    }

    /**
     * 接收页面消息
     *
     * @param msg
     * @param session
     */
    @OnMessage
    public void onMessage(String msg, Session session) {
        String deviceId = deviceIdMap.get(session.getId());
        if (StringUtils.isNotBlank(deviceId)) {
            SpringUtils.getBean(MobileConnectService.class).processWebMsg(msg, deviceId);
        } else {
            logger.debug("前端的sessionId:[{}]，未获取到deviceId",session.getId());
        }
    }

    @OnError
    public void onError(Session session, Throwable t) {
        logger.error(String.format("Session Error->sessionId:%s", session.getId()), t);
        onClose(session, new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "错误出现关闭"));
    }

    private void sendErrorMessageToWeb(Session session,String msg){
        synchronized (session) {
            try {
                session.getBasicRemote().sendText(msg);
            } catch (IOException e) {
                logger.warn("webSocket已经断开......，sessionId:{}",session.getId());
                try {
                    session.close();
                } catch (IOException ioException) {

                }
            }
        }
    }

    private UpperWSResponse buildErrorMessage(String deviceId,String msg){
        UpperWSResponse msgResponse = new UpperWSResponse();
        msgResponse.setCmd(MobileConnectionConstants.CommandConstants.CMD_DEVICE_STATUS);
        msgResponse.setFinish(true);
        msgResponse.setMessage(msg);
        msgResponse.setSerial(deviceId);
        msgResponse.setSuccess(false);
        Map<String, Object> result = new HashMap<>();
        result.put("status", "disconnect");
        result.put("message", msg);
        msgResponse.setData(result);
        return msgResponse;
    }

}
