import { getLanguage } from "taehui-ts/language";
import { getMillis } from "taehui-ts/date";

import { CloseEventHandler, Event, EventHandler } from "src/site/Site";

const EventPB = require("src/Event_pb");

const siteComponent = new (class {
  ws?: WebSocket;
  avatarID: string;
  eventDefaultHandler: EventHandler;
  eventCloseHandler: CloseEventHandler;
  onLoaded: () => void;
  onData: ({ data }: { data: MessageEvent }) => void;
  onClosed: () => void;

  constructor() {
    this.ws = undefined;
    this.avatarID = "";
    this.eventDefaultHandler = () => {};
    this.eventCloseHandler = () => {};

    this.onLoaded = () => {
      this.send({
        eventID: EventPB.Event.EventID.ESTABLISH,
        text: JSON.stringify({
          language: getLanguage(),
        }),
      });
    };

    this.onData = ({ data }) => {
      try {
        const { array } = EventPB.Event.deserializeBinary(data);
        this.eventDefaultHandler({
          eventID: array[2],
          text: array[3],
          data: array[4],
        });
      } catch (e) {}
    };

    this.onClosed = () => {
      this.eventCloseHandler();
      this.connect();
    };
  }

  connect() {
    this.ws = new WebSocket(
      `${window.location.protocol.replace("http", "ws")}//${
        window.location.host
      }/qwilight/ws`,
    );
    this.ws.binaryType = "arraybuffer";
    this.ws.addEventListener("open", this.onLoaded);
    this.ws.addEventListener("message", this.onData);
    this.ws.addEventListener("close", this.onClosed);
  }

  disconnect() {
    this.eventCloseHandler();
    this.ws?.removeEventListener("open", this.onLoaded);
    this.ws?.removeEventListener("message", this.onData);
    this.ws?.removeEventListener("close", this.onClosed);
    this.ws?.close();
  }

  send({ eventID, text, data }: Event) {
    try {
      const event = new EventPB.Event();
      event.setMillis(getMillis());
      event.setAvatarid(this.avatarID);
      event.setEventid(eventID);
      event.setText(text);
      data?.forEach((dataItem) => {
        event.addData(dataItem);
      });
      this.ws?.send(event.serializeBinary());
    } catch (e) {}
  }

  setEventDefaultHandler(eventDefaultHandler: EventHandler) {
    this.eventDefaultHandler = eventDefaultHandler;
  }

  setEventCloseHandler(eventCloseHandler: CloseEventHandler) {
    this.eventCloseHandler = eventCloseHandler;
  }

  setAvatarID(avatarID: string) {
    this.avatarID = avatarID;
  }
})();

export default siteComponent;
