import { io, Socket } from "socket.io-client";
import CONFIG from "./config.js";
import { logger } from "./index.js";
import { getSdkData, getAuthToken } from "./methods/init.js";
import { showNotification } from "./methods/push.js";
import { showPopup, getPopupDisplayed } from "./methods/popup.js";
import { NotificationData, SDKData, PopupData } from "./types/types.js";


let webSocketInstance: WebSocketManager | null = null;
let popupDisplayed = getPopupDisplayed();

class WebSocketManager {
    private socket: Socket;
    private isConnected: boolean = false;
    private gaId: string;
    private sdkData: SDKData;

    constructor(url: string, sdkData: SDKData, gaId: string) {
        this.socket = io(url, {
            // auth: { token: getAuthToken() },
            transports: ["websocket"],
            reconnection: true,
            reconnectionAttempts: 10,
            reconnectionDelay: 5000,
            timeout: 10000,
        });

        this.isConnected = false;
        this.gaId = gaId;
        this.sdkData = sdkData;

        this.socket.on("connect", () => {
            logger.info("✅ Connected to server");
            logger.info("🆔 Socket ID:", this.socket.id);
            this.isConnected = true;

            if (this.sdkData.show_web_push === "1") {
                this.socket.on(`sendNotification+${gaId}`, (data: NotificationData) => {
                    // logger.info("Notification received for gaId:", gaId);
                    // logger.info("Notification data:", data);
                    showNotification(data);
                });
            }

            if (this.sdkData.show_web_pop === "1") {
                this.socket.on(`response+${gaId}`, (data: PopupData) => {
                    // logger.info("Response received for gaId:", gaId);
                    // logger.info("Response data:", data);

                    const showPopupAnywhere = data.show_pop_anywhere ?? true;
                    const specificUrls = data.specific_urls ?? [];
                    const currentPath = `${window.location.hostname}${window.location.pathname}`;

                    if (showPopupAnywhere || specificUrls.includes(currentPath)) {
                        const popup = document.querySelector('.popup-wrapper') as HTMLElement | null;

                        if (!popup) {
                            showPopup(data, this.socket);
                        } else {
                            if (popup.style.display === "none" && !popupDisplayed) {
                                showPopup(data, this.socket);
                                popupDisplayed = true;
                            }
                        }
                    }
                });
            }
        });

        this.socket.on("connect_error", (error: any) => {
            logger.error("❌ Connection failed:", error);
            this.isConnected = false;
        });

        this.socket.on("disconnect", (reason: any) => {
            logger.warn("⚠️ Disconnected:", reason);
            this.isConnected = false;
        });
    }

    async send(event: string, data: any): Promise<void> {
        if (!this.isConnected) {
            logger.warn("⚠️ Waiting for socket to connect...");
            await this.waitForConnection();
        }

        if (this.isConnected) {
            this.socket.emit(event, data);
        } else {
            logger.warn("❌ Still not connected. Message not sent:", data);
        }
    }

    waitForConnection(): Promise<boolean> {
        return new Promise((resolve) => {
            const checkConnection = () => {
                if (this.isConnected) {
                    resolve(true);
                } else {
                    setTimeout(checkConnection, 1000);
                }
            };
            checkConnection();
        });
    }

    close(): void {
        this.socket.disconnect();
        this.isConnected = false;
    }
}

const getWebSocketInstance = (gaId: string): WebSocketManager => {
    if (!webSocketInstance) {
        const sdkData = getSdkData();
        webSocketInstance = new WebSocketManager(CONFIG.WebSocket_URl, sdkData, gaId);
    }
    return webSocketInstance;
};

export { getWebSocketInstance, WebSocketManager };
