import type { Response } from '../../models/Response';
import type { QVueGlobals } from 'quasar';
import { ref } from 'vue';
import type { Payload } from './models';

let socket: WebSocket | null = null;

const isConnected = ref(false);

export function useStatusServer(
  host: string,
  port: number = 9500,
  path: string,
  id: string,
  callback: (payload: Payload) => void,
  $q?: QVueGlobals,
) {
  const connect = () => {
    socket = new WebSocket(`ws://${host}:${port}/${path}?id=${id}`);

    socket.onopen = () => {
      console.log('WebSocket connected');
      isConnected.value = true;
    };

    socket.onclose = () => {
      isConnected.value = false;
      console.log('WebSocket disconnected');
      $q?.notify({
        message: 'WebSocket disconnected',
        color: 'orange',
        position: 'bottom-right',
        icon: 'warning',
        timeout: 10000,
      });
    };
    socket.onerror = (err) => {
      console.log(`WebSocket error: ${err.type}`);
      isConnected.value = false;
      $q?.notify({
        message: `WebSocket error: ${err.type}`,
        color: 'red',
        position: 'bottom-right',
        icon: 'error',
        timeout: 10000,
      });
    };
    socket.onmessage = (event) => {
      callback(JSON.parse(event.data));
    };
  };

  function subscribe(topic: string): Promise<Response | undefined> {
    return new Promise((resolve) => {
      waitForSocketConnection()
        .then(() => {
          socket?.send('{"action":"subscribe", "topic":"' + topic + '"}');
        })
        .catch((err) => {
          console.warn('WebSocket send failed:', err);
          resolve(undefined); // or reject(err) if strict failure is desired
        });
    });
  }

  function publish(topic: string, data: unknown): Promise<Response | undefined> {
    return new Promise((resolve) => {
      waitForSocketConnection()
        .then(() => {
          socket?.send(
            '{"action":"publish", "topic":"' + topic + '", "data":' + JSON.stringify(data) + '}',
          );
        })
        .catch((err) => {
          console.warn('WebSocket send failed:', err);
          resolve(undefined); // or reject(err) if strict failure is desired
        });
    });
  }

  const close = () => {
    if (socket) {
      socket.close();
    }
  };

  return {
    connect,
    close,
    subscribe,
    publish,
  };
}

function waitForSocketConnection(): Promise<void> {
  return new Promise((resolve, reject) => {
    const maxWait = 5000; // timeout after 5 seconds
    const interval = 50;
    let waited = 0;

    const check = () => {
      if (socket && socket.readyState === WebSocket.OPEN) {
        resolve();
      } else {
        waited += interval;
        if (waited >= maxWait) {
          reject(new Error('WebSocket connection timeout'));
        } else {
          setTimeout(check, interval);
        }
      }
    };
    check();
  });
}
