import { computed, ref, shallowRef, onScopeDispose, getCurrentScope } from "vue";
import { useApi } from "./api.js";
function toWsUrl(httpUrl) {
  if (httpUrl.startsWith("https://")) return "wss://" + httpUrl.slice("https://".length);
  if (httpUrl.startsWith("http://")) return "ws://" + httpUrl.slice("http://".length);
  return httpUrl;
}
export function useHostAgentWs() {
  const api = useApi();
  const base = ["agent"];
  const ws = shallowRef(null);
  const wsConnected = ref(false);
  const wsSubscribed = ref(false);
  const wsReader = ref(null);
  const wsWithPhoto = ref(false);
  const wsLastMessage = ref(null);
  const wsLastRaw = ref(null);
  const wsLastError = ref(null);
  const subscribers = /* @__PURE__ */ new Set();
  const emit = (ev) => {
    for (const cb of subscribers) cb(ev);
  };
  function disconnectIdCardWs(code, reason) {
    if (ws.value) {
      try {
        ws.value.close(code, reason);
      } catch {
      }
    }
    ws.value = null;
    wsConnected.value = false;
    wsSubscribed.value = false;
  }
  function connectIdCardWs() {
    disconnectIdCardWs();
    const httpUrl = api.urlBuilder([...base, "idcard/ws"]);
    const socket = new WebSocket(toWsUrl(httpUrl));
    ws.value = socket;
    wsConnected.value = false;
    wsSubscribed.value = false;
    wsLastMessage.value = null;
    wsLastRaw.value = null;
    wsLastError.value = null;
    socket.onopen = () => {
      wsConnected.value = true;
      emit({ type: "open" });
    };
    socket.onclose = (e) => {
      wsConnected.value = false;
      wsSubscribed.value = false;
      emit({ type: "close", code: e.code, reason: e.reason });
    };
    socket.onerror = (e) => {
      wsLastError.value = e;
      emit({ type: "error", error: e });
    };
    socket.onmessage = (e) => {
      wsLastRaw.value = e;
      let msg;
      if (typeof e.data === "string") {
        try {
          msg = JSON.parse(e.data);
        } catch {
          msg = { type: "error", message: "invalid json from server", raw: e.data };
        }
      } else {
        msg = { type: "error", message: "non-text ws message", raw: e.data };
      }
      wsLastMessage.value = msg;
      switch (msg.type) {
        case "monitor.subscribed":
          wsSubscribed.value = !!msg.ok;
          wsReader.value = msg.reader ?? null;
          wsWithPhoto.value = !!msg.withPhoto;
          break;
        case "monitor.started":
          wsReader.value = msg.reader ?? null;
          break;
        case "monitor.switchAck":
          if (msg.ok) wsReader.value = msg.reader ?? null;
          break;
        case "monitor.switched":
          wsReader.value = msg.reader ?? null;
          break;
        case "monitor.unsubscribed":
          wsSubscribed.value = false;
          break;
      }
      emit({ type: "message", data: msg, raw: e });
    };
    return socket;
  }
  function sendIdCardWs(message) {
    if (!ws.value || ws.value.readyState !== WebSocket.OPEN) {
      throw new Error("IDCard WS is not connected");
    }
    ws.value.send(JSON.stringify(message));
  }
  function subscribeIdCardWs(params) {
    const reader = params?.reader ?? null;
    const withPhoto = !!params?.withPhoto;
    wsReader.value = reader;
    wsWithPhoto.value = withPhoto;
    sendIdCardWs({ action: "subscribe", reader, withPhoto });
  }
  function pingIdCardWs() {
    sendIdCardWs({ action: "ping" });
  }
  function switchReaderIdCardWs(reader) {
    sendIdCardWs({ action: "switchReader", reader: reader ?? null });
  }
  function unsubscribeIdCardWs() {
    sendIdCardWs({ action: "unsubscribe" });
  }
  function onIdCardWsEvent(cb) {
    subscribers.add(cb);
    return () => subscribers.delete(cb);
  }
  if (getCurrentScope()) {
    onScopeDispose(() => {
      disconnectIdCardWs();
      subscribers.clear();
    });
  }
  return {
    // WS state
    ws,
    wsConnected: computed(() => wsConnected.value),
    wsSubscribed: computed(() => wsSubscribed.value),
    wsReader: computed(() => wsReader.value),
    wsWithPhoto: computed(() => wsWithPhoto.value),
    wsLastMessage: computed(() => wsLastMessage.value),
    wsLastRaw: computed(() => wsLastRaw.value),
    wsLastError: computed(() => wsLastError.value),
    // WS controls
    connectIdCardWs,
    disconnectIdCardWs,
    sendIdCardWs,
    subscribeIdCardWs,
    pingIdCardWs,
    switchReaderIdCardWs,
    unsubscribeIdCardWs,
    onIdCardWsEvent
  };
}
