import { io } from 'socket.io-client';
import type { ChatSocket } from './chat-contract';

let socket: ChatSocket | null = null;

export function getSocket(): ChatSocket {
  if (!socket) {
    // socket.io-client 4.8.3's `io()` factory declaration always returns the
    // default unparameterized Socket (it accepts no <ListenEvents, EmitEvents>
    // generics), so this one cast is the unavoidable boundary between that and the
    // typed `/chat` contract. Every other call site uses the resulting ChatSocket
    // with no further assertions.
    socket = io('/chat', {
      withCredentials: true,
      autoConnect: false,
      transports: ['websocket', 'polling'],
    }) as unknown as ChatSocket;

    // A transient `disconnect` (network blip, server restart) must NOT null
    // the singleton: socket.io-client auto-reconnects this same instance,
    // and its listeners stay registered across that reconnect. Nulling here
    // previously orphaned those listeners on the next getSocket() call by
    // handing back a brand-new, unconnected instance. Only destroySocket()
    // (an explicit, intentional teardown) may reset the singleton.
  }
  return socket;
}

/** Tear down the singleton socket and reset the reference. */
export function destroySocket(): void {
  if (socket) {
    socket.offAny();
    socket.disconnect();
    socket = null;
  }
}
