// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
export type SocketCallback = (data: unknown) => void;

export class ZeroSocket {
  private url: string;
  private listeners: Record<string, SocketCallback[]> = {};
  private eventSource: EventSource | null = null;
  private channel: string = "global_lobby";
  public id: string;

  constructor(url: string) {
    this.url = url;
    // Generate random id simulating socket.id
    this.id = Math.random().toString(36).substring(2, 15);
  }

  // Connect is called explicitly or implicitly
  connect() {
    if (this.eventSource) return;
    this.initSSE(this.channel);
  }

  private initSSE(channelName: string) {
    if (this.eventSource) {
      this.eventSource.close();
    }
    
    this.eventSource = new EventSource(`/api/omnibrain/sse?channel=${channelName}`);
    
    this.eventSource.onmessage = (e) => {
      try {
        const data = JSON.parse(e.data);
        if (data.event && this.listeners[data.event]) {
          this.listeners[data.event].forEach(fn => fn(data.payload));
        }
      } catch {
        // Abaikan parse error (mungkin keep-alive)
      }
    };
    
    this.eventSource.onerror = () => {
        console.warn("[ZeroSocket] SSE Koneksi terputus, mencoba memulihkan otomatis...");
    };
  }

  on(event: string, callback: SocketCallback) {
    if (!this.listeners[event]) this.listeners[event] = [];
    this.listeners[event].push(callback);
    return this; // for chaining
  }
  
  once(event: string, callback: SocketCallback) {
    const onceWrapper = (data: unknown) => {
        callback(data);
        this.off(event, onceWrapper);
    };
    this.on(event, onceWrapper);
    return this;
  }

  off(event: string, callback?: SocketCallback) {
    if (!this.listeners[event]) return this;
    if (callback) {
        this.listeners[event] = this.listeners[event].filter(cb => cb !== callback);
    } else {
        delete this.listeners[event];
    }
    return this;
  }

  emit(event: string, payload: string | Record<string, unknown> = {}) {
    const normalizedPayload = typeof payload === 'string' ? { value: payload } : payload;
    // Simulasi `socket.join(room)`
    // Di backend socket.io asli, `join` memasukkan client ke room. Di ZeroSocket, kita mengubah parameter channel SSE.
    if (event === "qr_auth_init") {
       this.channel = `qr_session_${(payload as Record<string, unknown>).sessionId}`;
       this.initSSE(this.channel);
    } else if (event === "guest_knock") {
       // Kita ganti channel menjadi lobby_ROOM agar bisa mendengarkan approval
       this.channel = `guest_${this.id}`;
       this.initSSE(this.channel);
       (payload as Record<string, any>).guestSocketId = this.id; // Sisipkan ID agar host tahu harus membalas kemana
    } else if (event === "register_user") {
       const userId = typeof payload === 'string' ? payload : (payload as Record<string, unknown>).userId;
       this.channel = `USER_${userId}`;
       this.initSSE(this.channel);
    }

    // Fire & Forget HTTP POST ke Redis PubSub OmniBrain
    fetch('/api/omnibrain/emit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ 
        channel: this.channel, 
        event, 
        payload: normalizedPayload 
      })
    }).catch(() => console.error("[ZeroSocket] Gagal memancarkan sinyal:"));
    
    return this;
  }

  disconnect() {
    if (this.eventSource) {
      this.eventSource.close();
      this.eventSource = null;
    }
  }
}

// Named export 'io' untuk meniru "import { io } from 'socket.io-client'"
export const io = (url?: string, options?: any) => {
  const socket = new ZeroSocket(url || "");
  socket.connect();
  return socket; 
};

// Export tipe tiruan
export type Socket = ZeroSocket;
