var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _ScProvider_providerP, _ScProvider_provider;
import { SupportedChains, getSpec } from "./specs/index.js";
import { DOM_ELEMENT_ID } from "@substrate/connect-extension-protocol";
/**
 * ScProvider is an API for providing an instance of a PolkadotJS Provider
 * to use a WASM-based light client. It takes care of detecting whether the
 * user has the substrate connect browser extension installed or not and
 * configures the PolkadotJS API appropriately; falling back to a provider
 * which instantiates the WASM light client in the page when the extension is
 * not available.
 *
 * @example
 *
 * ```
 * import { ScProvider, SupportedChains } from '@substrate/connect';
 * import { ApiPromise } from '@polkadot/api';
 *
 * // Create a new UApp with a unique name
 * const westendProvider = ScProvider(SupportedChains.westend)
 * const westend = await ApiPromise.create({ provider: westendProvider })
 *
 * const kusamaProvider = ScProvider(SupportedChains.kusama)
 * const kusama = await ApiPromise.create({ provider: kusamaProvider })
 *
 * await westendProvider.rpc.chain.subscribeNewHeads((lastHeader) => {
 *   console.log(lastHeader.hash);
 * );
 * await kusamaProvider.rpc.chain.subscribeNewHeads((lastHeader) => {
 *   console.log(lastHeader.hash);
 * });
 *
 * // Interact with westend and kusama APIs ...
 *
 * await westendProvider.disconnect();
 * await kusamaProvider.disconnect();
 * ```
 */
export class ScProvider {
    constructor(chainSpec, parachainSpec, autoConnect = true) {
        _ScProvider_providerP.set(this, void 0);
        _ScProvider_provider.set(this, undefined);
        /**
         * Detects and returns an appropriate PolkadotJS provider depending on whether the user has the substrate connect extension installed
         *
         * @param isExtension - whether the extension is installed
         * @param chain - either a string with the spec of the chain or the name of a supported chain ({@link SupportedChains})
         * @param parachainSpec - optional param of the parachain chainSpecs to connect to
         * @returns a provider will be used in a ApiPromise create for PolkadotJS API
         *
         * @internal
         *
         * @remarks
         * This is used internally for advanced PolkadotJS use cases and is not supported.  Use {@link connect} instead.
         */
        this.internalProvider = async (isExtension, chain, parachainSpec) => {
            if (chain.length === 0) {
                throw new Error(`No known Chain was detected and no chainSpec was provided. Either give a known chain name ('${Object.keys(SupportedChains).join("', '")}') or provide valid chainSpecs.`);
            }
            if (isExtension) {
                const { ExtensionProvider } = await import("./ExtensionProvider/ExtensionProvider.js");
                return new ExtensionProvider(chain, parachainSpec);
            }
            const chainSpecPromise = SupportedChains[chain]
                ? getSpec(chain)
                : Promise.resolve(chain);
            const [{ SmoldotProvider }, chainSpec] = await Promise.all([
                import("./SmoldotProvider/SmoldotProvider.js"),
                chainSpecPromise,
            ]);
            return new SmoldotProvider(chainSpec, parachainSpec);
        };
        const isExtension = !!document.getElementById(DOM_ELEMENT_ID);
        __classPrivateFieldSet(this, _ScProvider_providerP, this.internalProvider(isExtension, chainSpec, parachainSpec).then((provider) => (__classPrivateFieldSet(this, _ScProvider_provider, provider, "f"))), "f");
        if (autoConnect)
            __classPrivateFieldGet(this, _ScProvider_providerP, "f")
                .then((provider) => provider.connect())
                .catch((e) => console.log(e));
    }
    get hasSubscriptions() {
        return true;
    }
    get isConnected() {
        var _a, _b;
        return (_b = (_a = __classPrivateFieldGet(this, _ScProvider_provider, "f")) === null || _a === void 0 ? void 0 : _a.isConnected) !== null && _b !== void 0 ? _b : false;
    }
    /**
     * clone
     *
     * @remarks This method is not supported
     * @throws {@link Error}
     */
    clone() {
        throw new Error("clone() is not supported.");
    }
    /**
     * "Connect" to a Smoldot instance
     *
     * @returns a resolved Promise
     * @remarks this is async to fulfill the interface with PolkadotJS
     */
    async connect() {
        const provider = await __classPrivateFieldGet(this, _ScProvider_providerP, "f");
        return provider.connect();
    }
    /**
     * Manually "disconnect"
     */
    async disconnect() {
        const provider = await __classPrivateFieldGet(this, _ScProvider_providerP, "f");
        return provider.disconnect();
    }
    /**
     * Listen to provider events - in practice the smoldot provider only
     * emits a `connected` event after successfully starting the smoldot client
     * and `disconnected` after `disconnect` is called.
     * @param type - Event
     * @param sub - Callback
     */
    on(type, sub) {
        if (__classPrivateFieldGet(this, _ScProvider_provider, "f"))
            return __classPrivateFieldGet(this, _ScProvider_provider, "f").on(type, sub);
        let isActive = true;
        let innerCb = () => {
            return;
        };
        __classPrivateFieldGet(this, _ScProvider_providerP, "f")
            .then((provider) => {
            innerCb = isActive ? provider.on(type, sub) : innerCb;
        })
            .catch(() => {
            return;
        });
        return () => {
            if (!isActive)
                return;
            isActive = false;
            innerCb();
        };
    }
    /**
     * Send an RPC request  the wasm client
     *
     * @param method - The RPC methods to execute
     * @param params - Encoded paramaters as applicable for the method
     */
    async send(method, params) {
        const provider = await __classPrivateFieldGet(this, _ScProvider_providerP, "f");
        return provider.send(method, params);
    }
    /**
     * Allows subscribing to a specific event.
     *
     * @param type     - Subscription type
     * @param method   - Subscription method
     * @param params   - Parameters
     * @param callback - Callback
     * @returns Promise  - resolves to the id of the subscription you can use with [[unsubscribe]].
     *
     * @example
     * <BR>
     *
     * ```javascript
     * const provider = new ExtensionProvider(client);
     * const rpc = new Rpc(provider);
     *
     * rpc.state.subscribeStorage([[storage.balances.freeBalance, <Address>]], (_, values) => {
     *   console.log(values)
     * }).then((subscriptionId) => {
     *   console.log('balance changes subscription id: ', subscriptionId)
     * })
     * ```
     */
    async subscribe(
    // the "method" property of the JSON response to this subscription
    type, 
    // the "method" property of the JSON request to register the subscription
    method, 
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    params, callback) {
        const provider = await __classPrivateFieldGet(this, _ScProvider_providerP, "f");
        return provider.subscribe(type, method, params, callback);
    }
    /**
     * Allows unsubscribing to subscriptions made with [[subscribe]].
     *
     * @param type   - Subscription type
     * @param method - Subscription method
     * @param id     - Id passed for send parameter
     * @returns Promise resolving to whether the unsunscribe request was successful.
     */
    async unsubscribe(type, method, id) {
        const provider = await __classPrivateFieldGet(this, _ScProvider_providerP, "f");
        return provider.unsubscribe(type, method, id);
    }
}
_ScProvider_providerP = new WeakMap(), _ScProvider_provider = new WeakMap();
//# sourceMappingURL=ScProvider.js.map