import { createContext, useEffect, useContext, useState, useMemo, useCallback, useRef } from "react"
import { Unstable } from "@substrate/connect-discovery"
import { createClient } from "@polkadot-api/substrate-client"
import { getObservableClient } from "@polkadot-api/observable-client"
import useSWR from "swr"

const MAX_BLOCK_TIMEOUT = 15000
const DEFAULT_CHAIN_ID = "0x475e48fab52f3d0587b6b03101d224560c549e984d1dee197b7d8b55830e7da3"
const UnstableProvider = createContext(null)
export const useUnstableProvider = () => useContext(UnstableProvider)

export const UnstableProviderProvider = ({ children }) => {
    const [chainId, setChainId] = useState(DEFAULT_CHAIN_ID);
    const [providerIndex, setProviderIndex] = useState(0);

    const { data: providerDetails } = useSWR("getGhostProviders", () =>
        Unstable.getSubstrateConnectExtensionProviders()
    );

    const providerDetail = useMemo(() => providerDetails?.at(providerIndex), [providerDetails, providerIndex]);

    const { data: provider } = useSWR(
        () => providerDetail ? `ghostProviderDetail.${providerDetail.info.uuid}.provider` : null,
        () => providerDetail ? providerDetail.provider : null
    );

    const connectionState = useMemo(() => {
        if (!providerDetail) return 'no-extension';
        if (!provider) return 'loading';

        const chains = provider.getChains();
        if (chains[chainId]) return 'connected';

        return 'wrong-network';
    }, [providerDetail, provider, chainId]);

    const client = useMemo(() => {
        if (!provider || !chainId) return undefined;

        const chain = provider.getChains()[chainId];
        if (!chain) return undefined;

        return createClient(chain.connect)
    }, [provider, chainId]);

    const observableClient = useMemo(() => client ? getObservableClient(client) : undefined, [client]);
    const chainHead$ = useMemo(() => observableClient?.chainHead$(), [observableClient]);

    const value = useMemo(() => ({
        isExtensionMissing: connectionState === "no-extension",
        providerDetails,
        providerDetail,
        connectProviderByIndex: setProviderIndex,
        chainId,
        client,
        setChainId,
        chainHead$
    }), [providerDetails, providerDetail, chainId, client, chainHead$]);

    return (
        <UnstableProvider.Provider value={value}>
            {children}
        </UnstableProvider.Provider>
    );
};
