import { ref } from "vue";

/** abstract */
export default class WebSocketClient{
    
    constructor() {
        
        //-----------------------------------------------------------------
        // public
        
        /**
         * @description 连接中
         * @type Ref<bool>
         */
        this.IsConnected = ref(false);
        
        /**
         * @description 重连剩余秒数
         * @type Ref<number>
         */
        this.RetrySurplusSec = ref(0);

        /**
         * @description 服务名称 ws://{Addr}/{ServiceName}
         * @type Ref<string>
         */
        this.ServiceName = ref("");

        /**
         * @description 服务地址 ws://{Addr}/{ServiceName}
         * @type Ref<string>
         */
        this.Addr = ref("localhost:5540");

        /**
         * @description URL ws://{Addr}/{ServiceName}
         * @type Ref<string>
         */
        this.URL = () => `ws://${this.Addr.value}/${this.ServiceName.value}`
        //-----------------------------------------------------------------
        // protected

        /**
         * @description WebSocket实例
         * @type WebSocket
         */
        this.ws = null;

        //-----------------------------------------------------------------
        // private

        /** 连接重试计时 */
        this._retryStopwatch = new Date();

        /** 重连定时器 */
        this._retryTimer = 0;
    }


    //-----------------------------------------------------------------
    // public

    /**
     * @description 初始化 然后直接连接
     * @param {string} serviceName 服务名称
     * @param {string} addr 服务地址
     */
    Init(serviceName,addr){
        
        this.ServiceName.value = serviceName;
        this.Addr.value = addr;
        this._connect();
    }

    /**
     * @description 重连
     * @param {string} addr 
     */
    ReConnect(addr=null)
    {
        if(addr!=null && addr!='')
            this.Addr.value = addr;

        if(this._retryTimer){
            this._stopRetry();
        }

        if (this.ws) 
            this._close();
        
        this._connect();
    }

    /**
     * @description 释放资源
     */
    Dispose()
    {
        if(this._retryTimer){
            this._stopRetry();
        }
        if (this.ws) 
            this._close();
    }

    //-----------------------------------------------------------------
    // protected
    
    /**
     * @description 发送数据
     * @param {string} data 
     */
    send(data)
    {
        if(this.ws.readyState != WebSocket.OPEN)
        {
            console.error(`this.ws.readyState (${this.ws.readyState}) != WebSocket.OPEN`);
            return;
        }
        
        this.ws.send(data);
    }

    //-----------------------------------------------------------------
    // protected abstract

    /**
     * @description 消息事件，需要重载
     * @protected abstract
     * @param {string} msg 
     */
    onMessage(msg){
        //throw new Error('you should override "onMessage"'); 
        console.error('you should override "onMessage"');
    }
    
    /**
     * @description 连接成功事件，需要重载
     * @protected abstract
     */
    onOpen(){
        //throw new Error('you should override "onOpen"'); 
        console.error('you should override "onOpen"');
    }

    /**
     * @description 连接断开事件，需要重载
     * @protected abstract
     */
    onClose(){
        //throw new Error('you should override "onClose"'); 
        console.error('you should override "onClose"');
    }

    //-----------------------------------------------------------------
    // private
    _connect()
    {
        //WebSocket 在 new 时已经异步connect， 失败会调用onclose事件,需要重新new
        console.log(`this.ws = new WebSocket(${this.URL()})`);
        this.ws = new WebSocket(this.URL());
        this.ws.onmessage = (ev)=>{
            console.log(`onmessage(${ev})`); 
            console.log(`ev.data=${ev.data}`);
            this.onMessage(ev.data);
        };

        this.ws.onclose = (ev)=>{
            console.log(`onclose(${ev})`);
            //连接断开,重连
            this._retry();
            
            if(this.IsConnected.value){
                this.IsConnected.value = false;
                this.onClose();
            }
        }
        this.ws.onerror = (ev)=>{
            console.log(`onerror(${ev})`);
            //连接断开,重连
            // this._retry();
            
            // if(this.IsConnected.value){
            //     this.IsConnected.value = false;
            //     this.onClose();
            // }
        }
        this.ws.onopen = (ev)=> {
            console.log(`onopen(${ev})`);
            this.IsConnected.value = true;
            this.onOpen();
        }
    }
    _close()
    {
        this.ws.close();
        this.ws.onmessage = null;
        this.ws.onclose = null;
        this.ws.onerror = null;
        this.ws.onopen = null;
        this.ws = null;
    }


    _retry(){
        this._retry_stopwatch = new Date();
        this._updateRetryStatus();
        if(this._retryTimer)
            this._stopRetry();
        this._startRetry();
    }
    _stopRetry(){
        clearInterval(this._retryTimer);
        this._retryTimer = 0;
    }
    _startRetry(){
        if(this._retryTimer)
            return;
        this._retryTimer = setInterval(()=>{
            if (this._updateRetryStatus())
                {
                    console.log(`重连`);
                    this._stopRetry();
                    this._connect();
                }
        },2000);
    }
    /**
     * 更新 RetrySurplusSec 值
     * @returns 需要触发connect = true
     */
    _updateRetryStatus(){
        var now = new Date();
        var elapsed_ms = now.getTime() - this._retry_stopwatch.getTime();
        elapsed_ms = 5000 - elapsed_ms;
        this.RetrySurplusSec.value = Math.floor(((elapsed_ms > 0) ? elapsed_ms : 0)/1000);

        return (this.RetrySurplusSec.value <= 0);
    }
}