import { io, Socket } from 'socket.io-client';

class AdminSocketService {
  private socket: Socket | null = null;
  private listeners = new Map<string, Set<(data: unknown) => void>>();

  connect() {
    if (this.socket?.connected) return;

    const token = localStorage.getItem('accessToken');
    if (!token) return;

    // Strip /api/v1 from API URL to get the socket server URL
    const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api/v1';
    const socketUrl = apiUrl.replace(/\/api\/v1\/?$/, '');

    this.socket = io(socketUrl, {
      auth: { token },
      transports: ['websocket', 'polling'],
      reconnection: true,
      reconnectionDelay: 2000,
      reconnectionAttempts: 10,
    });

    this.socket.on('connect', () => {
      console.log('[AdminSocket] Connected');
    });

    this.socket.on('disconnect', (reason) => {
      console.log('[AdminSocket] Disconnected:', reason);
    });

    this.socket.on('connect_error', (err) => {
      console.error('[AdminSocket] Connection error:', err.message);
    });

    // Re-attach all registered listeners
    this.listeners.forEach((callbacks, event) => {
      callbacks.forEach((cb) => {
        this.socket?.on(event, cb as (...args: unknown[]) => void);
      });
    });
  }

  disconnect() {
    if (this.socket) {
      this.socket.disconnect();
      this.socket = null;
    }
  }

  on(event: string, callback: (data: unknown) => void) {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, new Set());
    }
    this.listeners.get(event)!.add(callback);

    if (this.socket) {
      this.socket.on(event, callback as (...args: unknown[]) => void);
    }
  }

  off(event: string, callback: (data: unknown) => void) {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      callbacks.delete(callback);
      if (callbacks.size === 0) {
        this.listeners.delete(event);
      }
    }

    if (this.socket) {
      this.socket.off(event, callback as (...args: unknown[]) => void);
    }
  }

  emit(event: string, data: unknown) {
    if (this.socket?.connected) {
      this.socket.emit(event, data);
    }
  }

  get isConnected(): boolean {
    return this.socket?.connected ?? false;
  }
}

export const adminSocketService = new AdminSocketService();
