using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebSocketSharp;

namespace WSCF
{
    public abstract class WebSocketClient: INotifyPropertyChanged, IDisposable
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public bool IsConnected { get; set; }

        /// <summary>
        /// 重连剩余秒数
        /// </summary>
        public int RetrySurplusSec { get; private set; }


        Stopwatch retry_stopwatch = new Stopwatch();
        System.Timers.Timer retry_timer;

        public string ServiceName;
        protected WebSocket ws;

        System.Timers.Timer ping_timer;


        public WebSocketClient()
        {
            //断开重连 定时器
            retry_timer = new System.Timers.Timer();
            retry_timer.AutoReset = true;
            retry_timer.Interval = 1000;
            retry_timer.Elapsed += Retry_timer_Elapsed;

            //长时间没有通讯 测试连接状态 定时器
            ping_timer = new System.Timers.Timer();
            ping_timer.AutoReset = true;
            ping_timer.Interval = 10000;
            ping_timer.Elapsed += Ping_timer_Elapsed;

            //建立 websocket 连接
            //this.ServiceName = serviceName;
        }
        protected void Init(string serviceName, string addr) 
        {
            this.ServiceName = serviceName;
            ws = new WebSocket($"ws://{addr}/{ServiceName}");
            ws.OnMessage += Ws_OnMessage;
            ws.OnOpen += Ws_OnOpen;
            ws.OnClose += Ws_OnClose;

            Retry();
            Task.Factory.StartNew(() =>
            {
                ws.Connect();
            });
        }
        public void InitByConnName(string serviceName,string connName) 
        {
            var addr = FObjServiceClientManager.Instance.Connect_to_Another_OBJSys(connName, this);
            Init(serviceName, addr);
        }
        bool ping_timer_ing = false;
        private void Ping_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (ping_timer_ing)
                return;
            ping_timer_ing = true;


            ws.Ping();


            ping_timer_ing = false;
        }

        bool retry_timer_ing = false;
        private void Retry_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (retry_timer_ing)
                return;
            retry_timer_ing = true;

            if (UpdateRetryStatus())
            {
                Retry();//正常应该StopRetry() 怕它不会触发 Ws_OnClose， 只有当 OnOpen 才 StopRetry()
                ws.Connect();
            }

            retry_timer_ing = false;
        }

        public void TouchPing()
        {
            ping_timer.Stop();
            ping_timer.Start();
        }

        void StopPing()
        {
            ping_timer.Stop();
        }

        public void ReConnect(string addr)
        {
            if (ws == null) 
            {
                Init(ServiceName, addr);
                return;
            }
            ws.Close();
            ws.OnMessage -= Ws_OnMessage;

            ws = new WebSocket($"ws://{addr}/{ServiceName}");
            ws.OnMessage += Ws_OnMessage;
            ws.OnOpen += Ws_OnOpen;
            ws.OnClose += Ws_OnClose;

            Retry();//正常应该StopRetry() 怕它不会触发 Ws_OnClose， 只有当 OnOpen 才 StopRetry()
            Task.Factory.StartNew(() =>
            {
                ws.Connect();
            });
        }

        void Retry()
        {
            retry_stopwatch.Restart();
            UpdateRetryStatus();
            //5秒后再尝试连接
            retry_timer.Stop();
            retry_timer.Start();
        }
        void StopRetry()
        {
            retry_stopwatch.Stop();
            retry_timer.Stop();
        }
        bool UpdateRetryStatus()
        {
            TimeSpan elapsed = TimeSpan.FromSeconds(5) - retry_stopwatch.Elapsed;

            RetrySurplusSec = (int)(((elapsed > TimeSpan.Zero) ? elapsed : TimeSpan.Zero).TotalSeconds);

            return (RetrySurplusSec <= 0);
        }

        private void Ws_OnClose(object sender, CloseEventArgs e)
        {
            IsConnected = false;
            Retry();
            StopPing();
            OnClose();
        }

        private void Ws_OnOpen(object sender, EventArgs e)
        {
            IsConnected = true;
            StopRetry();
            OnOpen();
        }
        
        private void Ws_OnMessage(object sender, MessageEventArgs e)
        {
            if (!e.IsText)
                return;
            OnMessage(e.Data);
        }




        public virtual void Dispose()
        {
            ws.Close();
            FObjServiceClientManager.Instance.ObjClientDisponse(this);
        }




        protected void Send(string data)
        {
            ws.Send(data);
            TouchPing();
        }

        protected abstract void OnMessage(string msg);
        protected abstract void OnOpen();
        protected abstract void OnClose();


    }
}
