import {
  CloseEventHandler,
  Event,
  EventHandler,
} from "@/app/[language]/site/type";
import { getMillis } from "taehui-lib/date";
import { useLanguage } from "taehui-lib/language";

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

const wsAPI = new (class {
  ws?: WebSocket;
  avatarID: string;
  eventDefaultHandler: EventHandler;
  eventCloseHandler: CloseEventHandler;
  onLoaded: () => void;
  onData: ({ data }: { data: MessageEvent }) => void;
  onClosed: (e: CloseEvent) => void;
  language?: ReturnType<typeof useLanguage>;

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

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

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

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

  setLanguage(language: ReturnType<typeof useLanguage>) {
    this.language = language;
  }

  connect() {
    this.ws = new WebSocket(
      `${process.env.NEXT_PUBLIC_WS_API ?? "wss://taehui.ddns.net"}/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 wsAPI;
