"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LogStoreClient = void 0;
const utils_1 = require("@streamr/utils");
/// lighter and with more compatibilities implementation of reflect-metadata
require("@abraham/reflection");
const rxjs_1 = require("rxjs");
const tsyringe_1 = require("tsyringe");
const Config_1 = require("./Config");
const events_1 = require("./events");
const Queries_1 = require("./Queries");
const LogStoreRegistry_1 = require("./registry/LogStoreRegistry");
const NodeManager_1 = require("./registry/NodeManager");
const QueryManager_1 = require("./registry/QueryManager");
const TokenManager_1 = require("./registry/TokenManager");
const StreamObservableFactory_1 = require("./StreamObservableFactory");
const Authentication_1 = require("./streamr/Authentication");
const Config_2 = require("./streamr/Config");
const ContractFactory_1 = require("./streamr/ContractFactory");
const DestroySignal_1 = require("./streamr/DestroySignal");
const LoggerFactory_1 = require("./streamr/LoggerFactory");
const StreamIDBuilder_1 = require("./streamr/StreamIDBuilder");
const StreamrClient_1 = require("./streamr/StreamrClient");
const MessagePipelineFactory_1 = require("./streamr/subscribe/MessagePipelineFactory");
const BroadbandSubscriber_1 = require("./utils/BroadbandSubscriber");
const GraphQLClient_1 = require("./utils/GraphQLClient");
const SystemMessageObservable_1 = require("./utils/SystemMessageObservable");
const systemStreamUtils_1 = require("./utils/systemStreamUtils");
const ValidationManager_1 = require("./validationManager/ValidationManager");
class LogStoreClient {
    constructor(streamrClient, logStoreClientConfig = {}, 
    /** @internal */
    parentContainer = tsyringe_1.container) {
        this.streamrClient = streamrClient;
        const container = parentContainer.createChildContainer();
        container.register(StreamrClient_1.StreamrClientInjectionToken, {
            useValue: streamrClient,
        });
        container.register(Config_2.StreamrClientConfigInjectionToken, {
            // @ts-expect-error config is marked as private in StreamrClient
            useValue: streamrClient.config,
        });
        this.strictLogStoreClientConfig = (0, Config_1.createStrictConfig)(logStoreClientConfig);
        this.systemMessages$ = (0, systemStreamUtils_1.systemStreamFromClient)(this.streamrClient, this.strictLogStoreClientConfig).pipe((0, rxjs_1.map)((stream) => new BroadbandSubscriber_1.BroadbandSubscriber(this.streamrClient, stream)), (0, rxjs_1.switchMap)(SystemMessageObservable_1.systemMessageFromSubscriber), 
        // we share the observable so that multiple subscribers can listen to the same stream
        // and turn off the subscription when there are no more subscribers
        (0, rxjs_1.share)({
            resetOnRefCountZero: true,
        }));
        container.register(LoggerFactory_1.LoggerFactoryInjectionToken, {
            // @ts-expect-error loggerFactory is marked as private in StreamrClient
            useValue: streamrClient.loggerFactory,
        });
        // @ts-expect-error authentication is marked as private in StreamrClient
        this.authentication = streamrClient.authentication;
        container.register(Authentication_1.AuthenticationInjectionToken, {
            // @ts-expect-error authentication is marked as private in StreamrClient
            useValue: streamrClient.authentication,
        });
        container.register(ContractFactory_1.ContractFactoryInjectionToken, {
            // @ts-expect-error streamRegistry.contractFactory is marked as private in StreamrClient
            useValue: streamrClient.streamRegistry.contractFactory,
        });
        // @ts-expect-error streamIdBuilder is marked as private in StreamrClient
        this.streamIdBuilder = streamrClient.streamIdBuilder;
        container.register(StreamIDBuilder_1.StreamIDBuilderInjectionToken, {
            // @ts-expect-error streamIdBuilder is marked as private in StreamrClient
            useValue: streamrClient.streamIdBuilder,
        });
        container.register(DestroySignal_1.DestroySignalInjectionToken, {
            // @ts-expect-error destroySignal is marked as private in StreamrClient
            useValue: streamrClient.destroySignal,
        });
        container.register(MessagePipelineFactory_1.MessagePipelineFactoryInjectionToken, {
            // @ts-expect-error Property 'resends' is private and only accessible within class 'StreamrClient'
            useValue: streamrClient.resends.messagePipelineFactory,
        });
        container.register(LogStoreClient, {
            useValue: this,
        });
        container.register(Config_1.LogStoreClientConfigInjectionToken, {
            useValue: this.strictLogStoreClientConfig,
        });
        container.register(systemStreamUtils_1.LogStoreClientSystemMessagesInjectionToken, {
            useValue: this.systemMessages$,
        });
        container.resolve(GraphQLClient_1.GQtyClients);
        this.logStoreClientEventEmitter =
            container.resolve(events_1.LogStoreClientEventEmitter);
        this.logStoreRegistry =
            container.resolve(LogStoreRegistry_1.LogStoreRegistry);
        this.logStoreQueries = container.resolve(Queries_1.Queries);
        this.logStoreQueryManager = container.resolve(QueryManager_1.QueryManager);
        this.logstoreTokenManager = container.resolve(TokenManager_1.TokenManager);
        this.logStoreNodeManager = container.resolve(NodeManager_1.NodeManager);
        this.validationManager =
            container.resolve(ValidationManager_1.ValidationManager);
        this.streamObservableFactory = container.resolve(StreamObservableFactory_1.StreamObservableFactory);
    }
    async getSigner() {
        return this.authentication.getStreamRegistryChainSigner();
    }
    // --------------------------------------------------------------------------------------------
    // Query
    // --------------------------------------------------------------------------------------------
    /**
     * Stake funds so can query
     */
    async queryStake(amount, options = { usd: false }, overrides) {
        return this.logStoreQueryManager.queryStake(amount, { usd: options.usd }, overrides);
    }
    /**
     * Performs a query of stored historical data.
     *
     * @category Important
     *
     * @param streamDefinition - the stream partition for which data should be resent
     * @param input - defines the kind of query that should be performed
     * @param onMessage - callback will be invoked for each message retrieved
     * @returns a {@link MessageStream} that provides an alternative way of iterating messages. Rejects if the stream is
     * not stored (i.e. is not assigned to a storage node).
     */
    async query(streamDefinition, input, onMessage, options) {
        const streamPartId = await this.streamIdBuilder.toStreamPartID(streamDefinition);
        const messageStream = await this.logStoreQueries.query(streamPartId, input, options);
        if (onMessage !== undefined) {
            messageStream.useLegacyOnMessageHandler(onMessage);
        }
        return messageStream;
    }
    async getQueryBalance() {
        return this.logStoreQueryManager.getQueryBalance();
    }
    async getQueryBalanceOf(address) {
        return this.logStoreQueryManager.getQueryBalanceOf(address);
    }
    async createQueryUrl(nodeUrl, streamDefinition, type, queryParams) {
        const streamPartId = await this.streamIdBuilder.toStreamPartID(streamDefinition);
        const url = this.logStoreQueries.createUrl(nodeUrl, type, streamPartId, queryParams);
        return url;
    }
    apiAuth() {
        return this.logStoreQueries.getAuth();
    }
    // --------------------------------------------------------------------------------------------
    // LogStore
    // --------------------------------------------------------------------------------------------
    /**
     * Add a stream to LogStore.
     */
    async stakeOrCreateStore(streamIdOrPath, amount, overrides) {
        return this.logStoreRegistry.stakeOrCreateStore(streamIdOrPath, amount, overrides);
    }
    /**
     * Checks whether a stream is assigned to a storage node.
     */
    async isLogStoreStream(streamIdOrPath) {
        return this.logStoreRegistry.isLogStoreStream(streamIdOrPath);
    }
    /**
     * Gets all streams assigned to a storage node.
     *
     * @returns a list of {@link Stream} as well as `blockNumber` of result (i.e. blockchain state)
     */
    async getLogStoreStreams() {
        return this.logStoreRegistry.getStoredStreams();
    }
    /**
     * Retrieves the balance of a stream.
     *
     * @param {string} streamIdOrPath - The ID or path of the stream.
     *
     * @return {Promise<bigint>} The balance of the stream as a bigint.
     */
    async getStreamBalance(streamIdOrPath) {
        return this.logStoreRegistry.getStreamBalance(streamIdOrPath);
    }
    /**
     * Retrieves the balance of the store for this account.
     */
    async getStoreBalance() {
        return this.logStoreRegistry.getStoreBalance();
    }
    /**
     * Sets the validation schema to validate new messages before storing on LogStore nodes.
     */
    async setValidationSchema(...params) {
        return this.validationManager.setValidationSchema(...params);
    }
    /**
     * Removes the validation schema from a stream.
     */
    async removeValidationSchema(...params) {
        return this.validationManager.removeValidationSchema(...params);
    }
    /**
     * Retrieves the validation schema for a stream.
     */
    async getValidationSchema(...params) {
        return this.validationManager.getValidationSchema(...params);
    }
    /**
     * Extracts the validation schema for a stream from the stream metadata object.
     */
    getValidationSchemaFromStreamMetadata(...params) {
        return this.validationManager.getValidationSchemaFromStreamMetadata(...params);
    }
    /**
     * Creates important observables for a stream.
     *
     * An observable is a stream of data that an observer can subscribe to.
     * It provides a way to handle or execute tasks whenever an event occurs, such as metadata updates.
     *
     * @param params - Parameters for stream observable creation
     * @returns A dictionary of observables that provides an alternative way to process stream data.
     */
    createStreamObservable(...params) {
        return this.streamObservableFactory.createStreamObservable(...params);
    }
    // --------------------------------------------------------------------------------------------
    // Token utilities
    // --------------------------------------------------------------------------------------------
    async getBalance() {
        return this.logstoreTokenManager.getBalance();
    }
    /**
     * Mints tokens for the account, using MATIC. Tokens are used to stake for querying and storage.
     */
    async mint(weiAmountToMint, overrides) {
        return this.logstoreTokenManager.mint(weiAmountToMint, overrides);
    }
    /**
     * Gets price data for the token.
     */
    async getPrice() {
        return this.logstoreTokenManager.getPrice();
    }
    /**
     * Gets conversion rate for the token, from/to multiple amount types.
     */
    async convert({ amount, from, to, }) {
        return this.logstoreTokenManager.convert({ amount, from, to });
    }
    // --------------------------------------------------------------------------------------------
    // Client
    // --------------------------------------------------------------------------------------------
    getConfig() {
        return this.strictLogStoreClientConfig;
    }
    // --------------------------------------------------------------------------------------------
    // Network Utilities
    // --------------------------------------------------------------------------------------------
    /**
     * Get the URL for a LogStore Node, given the address, using on-chain data.
     * Not all nodes are guaranteed to expose a Gateway.
     *
     * @param address
     */
    getNodeUrl(address) {
        const ethAddress = (0, utils_1.toEthereumAddress)(address);
        return this.logStoreNodeManager.getNodeUrl(ethAddress);
    }
    /**
     * Get node URLs list for LogStore, ordered by latency.
     */
    async getNodeUrlsByLatency() {
        return this.logStoreNodeManager.getNodeUrlsByLatency();
    }
    /**
     * This observable emits lists of nodes information from the LogStore, ordered by latency, as heartbeat messages are received.
     */
    get nodesHeartbeatInformationListObservable() {
        return this.logStoreNodeManager.nodeListByLatency$;
    }
    // --------------------------------------------------------------------------------------------
    // Events
    // --------------------------------------------------------------------------------------------
    /**
     * Adds an event listener to the client.
     * @param eventName - event name, see {@link LogStoreClientEvents} for options
     * @param listener - the callback function
     */
    on(eventName, listener) {
        this.logStoreClientEventEmitter.on(eventName, listener);
    }
    /**
     * Adds an event listener to the client that is invoked only once.
     * @param eventName - event name, see {@link LogStoreClientEvents} for options
     * @param listener - the callback function
     */
    once(eventName, listener) {
        this.logStoreClientEventEmitter.once(eventName, listener);
    }
    /**
     * Removes an event listener from the client.
     * @param eventName - event name, see {@link LogStoreClientEvents} for options
     * @param listener - the callback function to remove
     */
    off(eventName, listener) {
        this.logStoreClientEventEmitter.off(eventName, listener);
    }
    /**
     * Destroys an instance of a {@link LogStoreClient} by disconnecting from peers, clearing any pending tasks, and
     * freeing up resources. This should be called once a user is done with the instance.
     *
     * @remarks As the name implies, the client instance (or any streams or subscriptions returned by it) should _not_
     * be used after calling this method.
     */
    destroy() {
        this.logStoreNodeManager.destroy();
    }
    /**
     * Part of the Explicit Resource Management feature from ECMAScript. Polyfilled to work from ES3 onwards.
     * Supports the `using` statement in TypeScript 5.2+.
     *
     * @see {link https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management}
     */
    [Symbol.dispose]() {
        this.destroy();
    }
}
exports.LogStoreClient = LogStoreClient;
//# sourceMappingURL=LogStoreClient.js.map