import { ConnectStatus, CustomeSocket, SocketSettings } from "../types/socket";
import { ref } from "vue";
import { useInjector, useState } from "vue-vulcan";
import { CUSTOME_SOCKET, SOCKET_SETTINGS } from "../communication/token";

export function useSocket<S = any>() {
  const [status, setStatus]  = useState<ConnectStatus>('ready');
  const [currentMsg, setMsg] = useState<S>(null);
  const customeSocket        = useInjector<CustomeSocket<S>>(CUSTOME_SOCKET, 'optional');
  const socketSettings       = useInjector<SocketSettings>(SOCKET_SETTINGS, 'optional');

  let ws: CustomeSocket<S>;
  const brokenTime = ref(0);
  if(customeSocket) ws = customeSocket;  

  let initUrl: string;
  const connect = (url?: string) => {
    initUrl = url;
    if(customeSocket) {
      ws.connect(url)
    } else {
      ws = new WebSocket(url) as unknown as CustomeSocket<S>
    }
    ws.addEventListener('message', event => setMsg(event.data));    
    ws.addEventListener('open', () => {
      console.log('ws链接成功')
      setStatus('opening');
      brokenTime.value = 0;
      socketSettings.heartData && startHeartConnect();
    } );    
    ws.addEventListener('close', () => {setStatus('closed');});
    ws.addEventListener('error', () => {
      setStatus('onerror');       
    });
  }

  // 心跳链接  
  const startHeartConnect = (data?: any) => {
    const time = socketSettings.heartInterval;
    setInterval( () => ws.send(data || socketSettings.heartData), time && time >= 3000 ? time : 5000 )    
  }
 
  // 重连功能  
  const limit = socketSettings.retryLimit || 100;
  const reconnect = () => {
    if(!initUrl) return;
    console.log('开始重连')
    brokenTime.value ++;    
    if(brokenTime.value > limit) {
      ws.close();
    } else {
      setStatus('reconnect');
      setTimeout( () => connect(initUrl), brokenTime.value*1000 );
    }    
  }

  return {
    currentMsg,
    status,
    connect,
    reconnect,
    startHeartConnect,
    send: ws.send,
    close: () => {
      setStatus('closed');
      ws.close();      
    },
    onOpen: (cb: any) => ws.addEventListener('open', cb)
  }
}
