package com.yeejoin.precontrol.common.ws;

import com.alibaba.fastjson.JSONObject;
import com.yeejoin.precontrol.common.component.SpringContextHolder;
import com.yeejoin.precontrol.common.constant.Constant;
import com.yeejoin.precontrol.common.service.IStatisticsService;
import com.yeejoin.precontrol.common.utils.StringUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint("/statistics/{orgCode}")
@Data
@NoArgsConstructor
@Component
@Slf4j
public class WebSocketStatistics {

    private static int onlineCount = 0;
    private static Map<String, WebSocketStatistics> clients = new ConcurrentHashMap<String, WebSocketStatistics>();
    private Session session;
    private String orgCode;
    private String token;
    private Long projetId;

    @OnOpen
    public void onOpen(@PathParam(value = "orgCode") String orgCode, Session session) throws IOException {
        String param = session.getQueryString();
        JSONObject jsonObject = processParam(param);
        if (jsonObject != null) {
            this.token = jsonObject.getString("token");
            String projectId = jsonObject.getString("projectId");
            if (StringUtil.isNotEmpty(projectId) && !"0".equals(projectId)) {
                this.projetId = jsonObject.getLong("projectId");
            }
        }
        this.session = session;
        this.orgCode = orgCode;
        addOnlineCount();
        clients.put(token, this);
        System.out.println("大屏数据监控：" + orgCode + "已连接");
        setConfig();
        // 有新的通道时 初始化所有数据
        if (StringUtil.isNotEmpty(this.projetId)) {
            sendMessageInitByProjectId(session, orgCode, this.projetId);
        } else {
            sendMessageInit(session, orgCode);
        }
    }

    /**
     * 处理参数
     *
     * @param param
     * @return
     */
    public JSONObject processParam(String param) {
        JSONObject jsonObject = new JSONObject();
        if (StringUtil.isNotEmpty(param)) {
            String[] split = param.split("&");
            for (String str : split) {
                String[] splitParam = str.split("=");
                jsonObject.put(splitParam[0], splitParam[1]);
            }
            return jsonObject;
        }
        return null;
    }

    private void getConfig() {
//        WebSocketStatistics.sendMessageAll();
    }

    private void setConfig() {
//        WebSocketStatistics.sendMessageAll();
    }

    @OnClose
    public void onClose(@PathParam(value = "orgCode") String orgCode, Session session) {
        log.info("websocket on close sessionId:" + session.getId());
        String token = session.getQueryString();
        token = token.substring(token.indexOf("=") + 1, token.length());
        log.info("websocket on close --->>> token : {} , orgCoed:{}", token, orgCode);
        clients.remove(token);
        subOnlineCount();
    }

    @OnMessage
    public void onMessage(String message) throws IOException {
        JSONObject jsonTo = JSONObject.parseObject(message);
        System.out.println(jsonTo);
    }

    @OnError
    public void onError(@PathParam(value = "orgCode") String orgCode, Session session, Throwable error) {
        log.info("websocket on error  sessionId:" + session.getId());
        String token = session.getQueryString();
        token = token.substring(token.indexOf("=") + 1, token.length());
        log.info("websocket on error --->>> token : {} , orgCoed:{}", token, orgCode);
        error.printStackTrace();
    }

    /**
     * 建立通道发送数据
     *
     * @param session
     * @param orgCode
     */
    public static synchronized void sendMessageInit(Session session, String orgCode) {
        IStatisticsService statisticsService = SpringContextHolder.getBean(IStatisticsService.class);
        try {
            session.getAsyncRemote().sendText(statisticsService.queryStatisticsData(orgCode, Constant.WS_ALL));
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" websocket send one to  {}  fail", orgCode);
        }
    }

    public static synchronized void sendMessageInitByProjectId(Session session, String orgCode, Long projectId) {
        IStatisticsService statisticsService = SpringContextHolder.getBean(IStatisticsService.class);
        try {
            session.getAsyncRemote().sendText(statisticsService.queryStatisticsDataByProjectId(orgCode, projectId));
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" websocket send one to  {}  fail", orgCode);
        }
    }

    /**
     * 给指定的 orgCode 推送消息
     *
     * @param message
     * @param orgCode
     */
    public static synchronized void sendMessageTo(String message, String orgCode) {
        try {
            // 遍历通道给对应的orgCode推送数据
            for (WebSocketStatistics item : clients.values()) {
                if (orgCode.equals(item.orgCode)) {
                    log.info("websocket send one to message : orgCode ：{}", item.orgCode);
                    item.session.getAsyncRemote().sendText(message);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" websocket send one to  {}  fail", orgCode);
        }
    }

    /**
     * 给 orgCode自身和他的上级推送
     *
     * @param orgCode
     * @param businessType
     */
    public static synchronized void sendMessageParentAndOrgCode(String orgCode, String businessType) {
        IStatisticsService statisticsService = SpringContextHolder.getBean(IStatisticsService.class);
        HashSet<String> mapOrgCode = new HashSet<String>();
        Map<String, String> mapTemp = new HashMap<String, String>();
        try {
            // 1.获取通道orgCode去重
            for (WebSocketStatistics item : clients.values()) {
                if (null == orgCode && "null".equals(item.orgCode)) {
                    mapOrgCode.add(item.orgCode);
                }
                if (orgCode != null && ("null".equals(item.orgCode) || item.orgCode.contains(orgCode) || orgCode.contains(item.orgCode) || item.orgCode.equals(orgCode))) {
                    mapOrgCode.add(item.orgCode);
                }
            }
            // 2. 按照个去重后的 orgCode查询对应的数据 自身和他的上级
            for (String orgCodeTemp : mapOrgCode) {
                mapTemp.put(orgCodeTemp, statisticsService.queryStatisticsData(orgCodeTemp, businessType));
            }
            // 3. 遍历通道给对应的orgCode推送数据
            for (WebSocketStatistics item : clients.values()) {
                if (mapOrgCode.contains(item.orgCode)) {
                    log.info("websocket sendMessageParentAndOrgCode to message : orgCode ：{}", item.orgCode);
                    item.session.getAsyncRemote().sendText(mapTemp.get(item.orgCode));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" websocket sendMessageParentAndOrgCode to fail : {}  ", e.getMessage());
        }
    }

    /**
     * 给所用通道推送消息
     *
     * @param businessType
     */
    public static synchronized void sendMessageAll(String businessType) {
        IStatisticsService statisticsService = SpringContextHolder.getBean(IStatisticsService.class);
        HashSet<String> mapOrgCode = new HashSet<String>();
        Map<String, String> mapTemp = new HashMap<String, String>();
        try {
            // 1.获取通道orgCode去重
            for (WebSocketStatistics item : clients.values()) {
                mapOrgCode.add(item.orgCode);
            }
            // 2. 按照个去重后的 orgCode查询对应的数据
            for (String orgCodeTemp : mapOrgCode) {
                mapTemp.put(orgCodeTemp, statisticsService.queryStatisticsData(orgCodeTemp, businessType));
            }
            // 3. 遍历通道给对应的orgCode推送数据
            for (WebSocketStatistics item : clients.values()) {
                if (mapOrgCode.contains(item.orgCode)) {
                    log.info("websocket sendMessageAll to message : orgCode ：{}", item.orgCode);
                    item.session.getAsyncRemote().sendText(mapTemp.get(item.orgCode));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" websocket sendMessageAll to fail : {}  ", e.getMessage());
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketStatistics.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketStatistics.onlineCount--;
    }

    public static synchronized Map<String, WebSocketStatistics> getClients() {
        return clients;
    }
}