import React, {
    useContext,
    useEffect,
    useState,
    useRef,
    useCallback,
} from 'react';
import { TokenContext, TokenContextType } from '../contexts/tokenProvider';
import { ClientContext } from '../contexts/clientProvider';
import DefaultRenderer, { RenderProps } from '../renderers/DefaultRenderer';
import { Token } from '../core/token';
import Loading from './bootstrap/Loading';

export default function TokenRenderer({
    customRenderer = null,
    tokenContext = null,
    customToken = null,
    rendererProps = {},
}: {
    customRenderer?: typeof DefaultRenderer | DefaultRenderer;
    tokenContext?: TokenContextType;
    customToken?: Token;
    rendererProps?: RenderProps;
}) {
    const client = useContext(ClientContext);
    const [loading, setLoading] = useState(false);
    const [ready, setReady] = useState(false);
    const currentTokenContext = useRef(tokenContext);
    const currentTokenRenderer = useRef<
        typeof DefaultRenderer | DefaultRenderer
    >(null);
    const backupContext = useContext(TokenContext);

    currentTokenContext.current = currentTokenContext.current || backupContext;

    const load = useCallback(async () => {
        if (!client.loaded) return;
        if (!customToken && !currentTokenContext.current) return;

        setReady(false);
        setLoading(true);
        if (customRenderer) currentTokenRenderer.current = customRenderer;
        else
            currentTokenRenderer.current =
                client.controller.config.rendering.defaultRenderer ||
                DefaultRenderer;

        if (client.project.hasCustomRenderer()) {
            currentTokenRenderer.current =
                await require(client.project.getCustomRenderer());
            currentTokenRenderer.current =
                (currentTokenRenderer.current as any).default ||
                currentTokenRenderer.current;
        }

        setLoading(false);
        setReady(true);
    }, [client, customToken, customRenderer]);

    useEffect(() => {
        load();
    }, [load]);

    if (loading || !ready) return <Loading />;

    let Component = currentTokenRenderer.current as typeof DefaultRenderer;
    if (ready && Component)
        return (
            <Component
                rendererProps={{
                    ...(rendererProps || {}),
                    ...(client?.controller?.config?.rendering?.rendererProps ||
                        {}),
                }}
                token={customToken || currentTokenContext?.current?.token}
            />
        );

    return <Loading />;
}
