'use client';

import { createContext, useContext, useEffect, useState, useRef } from 'react';
import * as signalR from '@microsoft/signalr';
import useAuth from '@/hooks/useAuth';

const SignalRContext = createContext<{
    connection: signalR.HubConnection | null;
	connected: boolean;
	stopConnection: () => void;
	reConnection: () => void;
}>({
    connection: null,
	connected: false,
	stopConnection: () => {},
	reConnection: () => {}
});

type Props = {
	children: React.ReactNode;
	accessToken: string|null;
	signalRUrl: string;
}

export function SignalRProvider({ children, accessToken, signalRUrl }: Props) {
	const connection = useRef<signalR.HubConnection|null>(null);
	const [connected, setConnected] = useState<boolean>(false);
	const { logout } = useAuth();

	useEffect(() => {
		initConnection();

		return () => {
			if (connection.current) {
				stopConnection();
			}
		};
	}, []);

	useEffect(() => {
		if (connected) {
			console.info('SignalR Connected');
		} else if(connection.current) {
			console.info('SignalR Disconnected');
		} else {
			console.info('SignalR Waiting...');
		}
	}, [connected]);

	const initConnection = async () => {
		try {
			if (connection.current && connection.current.state !== signalR.HubConnectionState.Disconnected) {
				return;
			}

			console.log('SignalR Connecting...');

			const connectionOptions = accessToken ? { accessTokenFactory: async () => accessToken, withCredentials: true } : {};
			const conn = new signalR.HubConnectionBuilder().withUrl(signalRUrl, connectionOptions).build();

			if (conn.state === signalR.HubConnectionState.Disconnected) {
				console.warn('SignalR Connection is already disconnected');
				return;
			}

			await conn.start();
			setConnected(true);

			conn.on('Connected', (message) => {
				console.info(message);
			});
			conn.on('Logout', (message) => {
				console.info(message);
			});
			conn.on('Kick', async () => {
				await logout();
			});

			connection.current = conn;
		} catch (error) {
			console.error('SignalR Connect Failed:', error);
		}
	};

	const stopConnection = async () => {
		if (connection.current && connection.current.state === signalR.HubConnectionState.Connected) {
			try {
                await connection.current.invoke('Logout');
                setConnected(false);
            } catch (error) {
                console.error('SignalR Disconnect Failed:', error);
            }
		}
	};

	const reConnection = async () => {
		if (connection.current && connection.current.state === signalR.HubConnectionState.Connected) {
			try {
				console.log('SignalR ReConnecting...');
				await connection.current.stop();
				await initConnection();
				console.log('SignalR ReConnected');
			} catch (error) {
				console.error("SignalR ReConnection Failed:", error);
			}
		}
	};

	return (
		<SignalRContext.Provider value={{ connection: connection.current, connected, stopConnection, reConnection }}>
			{children}
		</SignalRContext.Provider>
	)
}

export function useSignalRContext() {
    return useContext(SignalRContext);
}