import { useEffect, useRef } from 'react';
import { io } from 'socket.io-client';
import { parseRequiredActionPayload } from '../components/require-action/required-action-api';
import PHXGetEnvPublicV3 from '../../Func/getEnvPublic';
const INAPP_NOTI_SOCKET_CONFIG = {
    namespace: '/core-socket',
    path: '/core-socket',
    joinRoomEvent: 'join_room',
    realtimeEvent: 'inapp-noti-count',
};
const INAPP_NOTI_ROOM_ID = {
    realtime: 'inapp-noti-count',
};
const isRecord = (value) => typeof value === 'object' && value !== null;
const getPublicHostname = async () => {
    const response = await PHXGetEnvPublicV3();
    return isRecord(response) && typeof response.HOSTNAME === 'string' ? response.HOSTNAME : undefined;
};
const getDashboardCountPayload = (payload) => {
    if (!isRecord(payload) || !isRecord(payload.data))
        return undefined;
    return isRecord(payload.data.dashboard) ? payload.data.dashboard : undefined;
};
const getUnreadCount = (payload) => {
    const dashboardPayload = getDashboardCountPayload(payload);
    return dashboardPayload && typeof dashboardPayload.unread_count === 'number'
        ? dashboardPayload.unread_count
        : undefined;
};
const parseDashboardRequiredActionPayload = (payload) => {
    const dashboardPayload = getDashboardCountPayload(payload);
    const counts = dashboardPayload && isRecord(dashboardPayload.required_action_count) ? dashboardPayload.required_action_count : {};
    return parseRequiredActionPayload({ counts });
};
const getPayloadUserId = (payload) => {
    if (!isRecord(payload))
        return undefined;
    const userId = Number(payload.user_id);
    return Number.isFinite(userId) ? userId : undefined;
};
const isPayloadForCurrentUser = (payload, currentUserId) => {
    const payloadUserId = getPayloadUserId(payload);
    if (!payloadUserId)
        return true;
    return payloadUserId === currentUserId;
};
const getSocketHeaders = (accessToken, hostname) => ({
    authorization: `Bearer ${accessToken}`,
    ...(hostname ? { hostname } : {}),
    module: 'inapp-noti',
});
const joinRealtimeRooms = (socket) => {
    socket.emit(INAPP_NOTI_SOCKET_CONFIG.joinRoomEvent, {
        roomId: INAPP_NOTI_ROOM_ID.realtime,
    });
};
const bindRealtimeSocketEvents = ({ currentUserId, onConnectionChange, onRequiredAction, onUnreadCount, socket, }) => {
    socket.on('connect', () => {
        onConnectionChange === null || onConnectionChange === void 0 ? void 0 : onConnectionChange(true);
        joinRealtimeRooms(socket);
    });
    socket.on('connect_error', () => {
        onConnectionChange === null || onConnectionChange === void 0 ? void 0 : onConnectionChange(false);
    });
    socket.on('disconnect', () => {
        onConnectionChange === null || onConnectionChange === void 0 ? void 0 : onConnectionChange(false);
    });
    socket.io.on('reconnect', () => {
        onConnectionChange === null || onConnectionChange === void 0 ? void 0 : onConnectionChange(true);
    });
    socket.on(INAPP_NOTI_SOCKET_CONFIG.realtimeEvent, (payload) => {
        if (!isPayloadForCurrentUser(payload, currentUserId)) {
            return;
        }
        onUnreadCount(getUnreadCount(payload));
        onRequiredAction(parseDashboardRequiredActionPayload(payload));
    });
};
const setupRealtimeSocket = async ({ accessToken, currentUserId, onConnectionChange, onRequiredAction, onUnreadCount, }) => {
    const socketUrl = `${process.env.NEXT_PUBLIC_API_GATEWAY}${INAPP_NOTI_SOCKET_CONFIG.namespace}`;
    const hostname = await getPublicHostname();
    const socket = io(socketUrl, {
        path: INAPP_NOTI_SOCKET_CONFIG.path,
        // transports: ['websocket'],
        extraHeaders: getSocketHeaders(accessToken, hostname),
    });
    bindRealtimeSocketEvents({
        currentUserId,
        onConnectionChange,
        onRequiredAction,
        onUnreadCount,
        socket,
    });
    return socket;
};
export const useMainwrapRealtimeCounts = ({ accessToken, currentUserId, enabled, onConnectionChange, onRequiredAction, onUnreadCount, }) => {
    const onConnectionChangeRef = useRef(onConnectionChange);
    const onRequiredActionRef = useRef(onRequiredAction);
    const onUnreadCountRef = useRef(onUnreadCount);
    // Sync ref mỗi render, không trigger effect
    useEffect(() => {
        onConnectionChangeRef.current = onConnectionChange;
        onRequiredActionRef.current = onRequiredAction;
        onUnreadCountRef.current = onUnreadCount;
    });
    useEffect(() => {
        var _a;
        if (!enabled || !accessToken || !currentUserId) {
            (_a = onConnectionChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onConnectionChangeRef, false);
            return;
        }
        let socket = null;
        let isDisposed = false;
        const connectSocket = async () => {
            var _a;
            try {
                if (isDisposed)
                    return;
                const nextSocket = await setupRealtimeSocket({
                    accessToken,
                    currentUserId,
                    onConnectionChange: (...args) => { var _a; return (_a = onConnectionChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onConnectionChangeRef, ...args); },
                    onRequiredAction: (...args) => { var _a; return (_a = onRequiredActionRef.current) === null || _a === void 0 ? void 0 : _a.call(onRequiredActionRef, ...args); },
                    onUnreadCount: (...args) => { var _a; return (_a = onUnreadCountRef.current) === null || _a === void 0 ? void 0 : _a.call(onUnreadCountRef, ...args); },
                });
                if (isDisposed) {
                    nextSocket.disconnect();
                    return;
                }
                socket = nextSocket;
            }
            catch (_b) {
                (_a = onConnectionChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onConnectionChangeRef, false);
            }
        };
        void connectSocket();
        return () => {
            var _a;
            isDisposed = true;
            (_a = onConnectionChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onConnectionChangeRef, false);
            socket === null || socket === void 0 ? void 0 : socket.disconnect();
        };
    }, [enabled, accessToken, currentUserId]);
};
//# sourceMappingURL=use-mainwrap-realtime-counts.js.map