import { useEffect, useMemo, useRef, useCallback } from "react";
import { useAsyncMemo } from "../../hooks/async";
import { createSimpleContext } from "../simple";
import { useNetwork } from "./network";
import Signal from "@equilab/utils/lib/async/signal";
const useApiHook = ({ useBase }) => {
    const base = useBase();
    const { network } = useNetwork();
    const api = useAsyncMemo(async () => {
        if (network && base.api?.getApiCreator) {
            const create = base.api.getApiCreator(network.type ?? "Eq");
            const api = await create(network.node);
            return api;
        }
    }, [network, base.api?.getApiCreator]);
    const enableOn = useCallback((apiType, callbackOrNode) => {
        if (typeof callbackOrNode === "function") {
            if (base.api?.isApi(api.data, apiType)) {
                const curApi = api.data;
                queueMicrotask(async () => await callbackOrNode(curApi));
            }
            return;
        }
        else if (network?.type === apiType) {
            return callbackOrNode;
        }
    }, [api.data, base.api?.isApi, network]);
    const disableOn = useCallback((apiType, callbackOrNode) => {
        if (typeof callbackOrNode === "function") {
            if (api.data && !base.api?.isApi(api.data, apiType)) {
                const curApi = api.data;
                if (typeof callbackOrNode === "function") {
                    queueMicrotask(async () => await callbackOrNode(curApi));
                }
                return;
            }
        }
        else if (network?.type !== apiType) {
            return callbackOrNode;
        }
    }, [api.data, base.api?.isApi, network]);
    const prev = useRef();
    useEffect(() => {
        prev.current?._api.disconnect();
        prev.current = api.data;
    }, [api.data]);
    const handleSumbittableResult = useCallback(() => {
        // TODO move this helper somewhere
        const sig = new Signal();
        const callback = (res) => {
            try {
                if (res.status.isInBlock || res.status.isFinalized) {
                    for (const { event: { data, section, method }, } of res.events) {
                        if (section === "system" && method === "ExtrinsicSuccess") {
                            sig.emit();
                        }
                        if (section === "system" && method === "ExtrinsicFailed") {
                            const [error] = data;
                            let message;
                            if (error.isModule) {
                                const err = api?.data?.getError(error.asModule);
                                // @ts-ignore
                                message = err?.documentation.join("\n");
                            }
                            else {
                                message = error?.toString();
                            }
                            throw new Error(message ?? "Unknown error");
                        }
                    }
                }
            }
            catch (e) {
                if (e instanceof Error) {
                    sig.cancel(e);
                }
            }
        };
        return { sig, callback };
    }, [api]);
    return useMemo(() => ({
        /** @deprecated */
        api: api.data,
        apiRx: api.data?._api.rx,
        registry: api.data?._api.registry,
        events: api.data?._api.events,
        apiError: api.error,
        enableOn,
        disableOn,
        /**
         * @deprecated
         */
        handleSumbittableResult,
    }), [api.data, api.error, enableOn, disableOn]);
};
const Context = createSimpleContext("eq-api", {
    api: undefined,
    apiError: undefined,
    apiRx: undefined,
    registry: undefined,
    events: undefined,
    handleSumbittableResult: () => ({
        sig: new Signal(),
        callback: (_) => {
            throw Error("Not implemented");
        },
    }),
    enableOn() {
        throw new Error("Not implemented");
    },
    disableOn() {
        throw new Error("Not implemented");
    },
}, useApiHook);
export const ApiProvider = Context.Provider;
export const useApi = () => Context.useContext();
//# sourceMappingURL=api.js.map