// services/socketService.ts
import { PAYMENT_SOCKET_BASE_URL, STORAGE_KEYS } from "@/constants/config";
import AsyncStorage from "@react-native-async-storage/async-storage";
import io, { Socket } from "socket.io-client";

class SocketService {
  private socket: Socket | null = null;
  private static instance: SocketService;

  private constructor() {}

  public static getInstance(): SocketService {
    if (!SocketService.instance) {
      SocketService.instance = new SocketService();
    }
    return SocketService.instance;
  }

  public async connect(): Promise<Socket> {
    try {
      const token = await AsyncStorage.getItem(STORAGE_KEYS.AUTH_TOKEN);

      if (!token) {
        throw new Error("No auth token found");
      }

      this.socket = io(PAYMENT_SOCKET_BASE_URL, {
        transports: ["websocket"],
        autoConnect: true,
        reconnection: true,
        reconnectionDelay: 1000,
        reconnectionAttempts: 5,
        timeout: 20000,
        extraHeaders: {
          Authorization: `Bearer ${token}`,
        },
      });

      return new Promise((resolve, reject) => {
        this.socket!.on("connect", () => {
          console.log("Socket connected:", this.socket?.id);
          resolve(this.socket!);
        });

        this.socket!.on("connect_error", (error) => {
          console.error("Socket connection error:", error);
          reject(error);
        });

        this.socket!.on("disconnect", (reason) => {
          console.log("Socket disconnected:", reason);
        });
      });
    } catch (error) {
      console.error("Failed to connect socket:", error);
      return Promise.reject(error);
    }
  }

  public registerTransaction(transactionId: string): Promise<void> {
    return new Promise((resolve, reject) => {
      const socket = this.socket; // Save reference to socket here

      if (!socket || !socket.connected) {
        reject(new Error("Socket not connected"));
        return;
      }

      const timeoutMs = 5000;

      const timeoutId = setTimeout(() => {
        socket.off("registration-ack", onRegistrationAck);
        reject(new Error("Timeout: No registration-ack received"));
      }, timeoutMs);

      const onRegistrationAck = (data: any) => {
        console.log("inside onRegisterAck");
        if (data.transactionId === transactionId) {
          clearTimeout(timeoutId);
          //   socket.off("registration-ack", onRegistrationAck);

          if (data.success) {
            resolve();
          } else {
            reject(new Error("Registration failed"));
          }
        }
      };

      socket.on("registration-ack", onRegistrationAck);

      socket.on("register-transaction", this.onPaymentConfirm);
      socket.onAny((eventName, ...args) => {
        console.log(eventName, "eventname", JSON.stringify(args), "✅✅✅✅✅");
      });

      socket.emit("register-transaction", { transactionId });
    });
  }

  private onPaymentConfirm(eventname: string, ...args: any[]): void {
    console.log(eventname, "eventName", JSON.stringify(args));
  }

  public onPaymentConfirmation(callback: (data: any) => void): void {
    if (!this.socket) {
      console.error("Socket not connected");
      return;
    }

    this.socket.on("register-transaction", callback);
  }

  public offPaymentConfirmation(): void {
    if (this.socket) {
      this.socket.off("payment-confirmation");
    }
  }

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

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

  public getSocket(): Socket | null {
    return this.socket;
  }
}

export default SocketService.getInstance();
