// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { isNamedKeyCredential, isSASCredential, isTokenCredential } from "@azure/core-auth";
import { COSMOS_SCOPE, STORAGE_SCOPE, TablesLoggingAllowedHeaderNames } from "./utils/constants.js";
import { injectSecondaryEndpointHeader, tablesSecondaryEndpointPolicy, } from "./secondaryEndpointPolicy.js";
import { parseXML, stringifyXML } from "@azure/core-xml";
import { GeneratedClient } from "./generated/generatedClient.js";
import { apiVersionPolicy } from "./utils/apiVersionPolicy.js";
import { getClientParamsFromConnectionString } from "./utils/connectionString.js";
import { handleTableAlreadyExists } from "./utils/errorHelpers.js";
import { isCredential } from "./utils/isCredential.js";
import { logger } from "./logger.js";
import { setTokenChallengeAuthenticationPolicy } from "./utils/challengeAuthenticationUtils.js";
import { tablesNamedKeyCredentialPolicy } from "./tablesNamedCredentialPolicy.js";
import { tablesSASTokenPolicy } from "./tablesSASTokenPolicy.js";
import { tracingClient } from "./utils/tracing.js";
import { isCosmosEndpoint } from "./utils/isCosmosEndpoint.js";
/**
 * A TableServiceClient represents a Client to the Azure Tables service allowing you
 * to perform operations on the tables and the entities.
 */
export class TableServiceClient {
    /**
     * Table Account URL
     */
    url;
    /**
     * Represents a pipeline for making a HTTP request to a URL.
     * Pipelines can have multiple policies to manage manipulating each request before and after it is made to the server.
     */
    pipeline;
    table;
    service;
    constructor(url, credentialOrOptions, options) {
        this.url = url;
        const isCosmos = isCosmosEndpoint(this.url);
        const credential = isCredential(credentialOrOptions) ? credentialOrOptions : undefined;
        const clientOptions = (!isCredential(credentialOrOptions) ? credentialOrOptions : options) || {};
        const internalPipelineOptions = {
            ...clientOptions,
            endpoint: clientOptions.endpoint || this.url,
            loggingOptions: {
                logger: logger.info,
                additionalAllowedHeaderNames: [...TablesLoggingAllowedHeaderNames],
            },
            deserializationOptions: {
                parseXML,
            },
            serializationOptions: {
                stringifyXML,
            },
        };
        const client = new GeneratedClient(this.url, internalPipelineOptions);
        client.pipeline.addPolicy(tablesSecondaryEndpointPolicy);
        if (isNamedKeyCredential(credential)) {
            client.pipeline.addPolicy(tablesNamedKeyCredentialPolicy(credential));
        }
        else if (isSASCredential(credential)) {
            client.pipeline.addPolicy(tablesSASTokenPolicy(credential));
        }
        if (isTokenCredential(credential)) {
            const scope = isCosmos ? COSMOS_SCOPE : STORAGE_SCOPE;
            setTokenChallengeAuthenticationPolicy(client.pipeline, credential, scope);
        }
        if (options?.version) {
            client.pipeline.addPolicy(apiVersionPolicy(options.version));
        }
        this.pipeline = client.pipeline;
        this.table = client.table;
        this.service = client.service;
    }
    /**
     * Retrieves statistics related to replication for the Table service. It is only available on the
     * secondary location endpoint when read-access geo-redundant replication is enabled for the account.
     * @param options - The options parameters.
     */
    async getStatistics(options = {}) {
        return tracingClient.withSpan("TableServiceClient.getStatistics", options, (updatedOptions) => this.service.getStatistics(injectSecondaryEndpointHeader(updatedOptions)));
    }
    /**
     * Gets the properties of an account's Table service, including properties for Analytics and CORS
     * (Cross-Origin Resource Sharing) rules.
     * @param options - The options parameters.
     */
    getProperties(options = {}) {
        return tracingClient.withSpan("TableServiceClient.getProperties", options, (updatedOptions) => this.service.getProperties(updatedOptions));
    }
    /**
     * Sets properties for an account's Table service endpoint, including properties for Analytics and CORS
     * (Cross-Origin Resource Sharing) rules.
     * @param properties - The Table Service properties.
     * @param options - The options parameters.
     */
    setProperties(properties, options = {}) {
        return tracingClient.withSpan("TableServiceClient.setProperties", options, (updatedOptions) => this.service.setProperties(properties, updatedOptions));
    }
    /**
     * Creates a new table under the given account.
     * @param name - The name of the table.
     * @param options - The options parameters.
     */
    createTable(name, options = {}) {
        return tracingClient.withSpan("TableServiceClient.createTable", options, async (updatedOptions) => {
            try {
                await this.table.create({ name }, updatedOptions);
            }
            catch (e) {
                handleTableAlreadyExists(e, { ...updatedOptions, logger, tableName: name });
            }
        });
    }
    /**
     * Operation permanently deletes the specified table.
     * @param name - The name of the table.
     * @param options - The options parameters.
     */
    deleteTable(name, options = {}) {
        return tracingClient.withSpan("TableServiceClient.deleteTable", options, async (updatedOptions) => {
            try {
                await this.table.delete(name, updatedOptions);
            }
            catch (e) {
                if (e.statusCode === 404) {
                    logger.info("TableServiceClient.deleteTable: Table doesn't exist");
                }
                else {
                    throw e;
                }
            }
        });
    }
    /**
     * Queries tables under the given account.
     * @param options - The options parameters.
     */
    listTables(
    // eslint-disable-next-line @azure/azure-sdk/ts-naming-options
    options) {
        const iter = this.listTablesAll(options);
        return {
            next() {
                return iter.next();
            },
            [Symbol.asyncIterator]() {
                return this;
            },
            byPage: (settings) => {
                const pageOptions = {
                    ...options,
                    queryOptions: { ...options?.queryOptions, top: settings?.maxPageSize },
                };
                if (settings?.continuationToken) {
                    pageOptions.continuationToken = settings.continuationToken;
                }
                return this.listTablesPage(pageOptions);
            },
        };
    }
    async *listTablesAll(options) {
        const firstPage = await this._listTables(options);
        const { continuationToken } = firstPage;
        yield* firstPage;
        if (continuationToken) {
            const optionsWithContinuation = {
                ...options,
                continuationToken,
            };
            for await (const page of this.listTablesPage(optionsWithContinuation)) {
                yield* page;
            }
        }
    }
    async *listTablesPage(options = {}) {
        let result = await tracingClient.withSpan("TableServiceClient.listTablesPage", options, (updatedOptions) => this._listTables(updatedOptions));
        yield result;
        while (result.continuationToken) {
            const optionsWithContinuation = {
                ...options,
                continuationToken: result.continuationToken,
            };
            result = await tracingClient.withSpan("TableServiceClient.listTablesPage", optionsWithContinuation, async (updatedOptions, span) => {
                span.setAttribute("continuationToken", updatedOptions.continuationToken);
                return this._listTables(updatedOptions);
            });
            yield result;
        }
    }
    async _listTables(options = {}) {
        const { continuationToken: nextTableName, ...listOptions } = options;
        const { xMsContinuationNextTableName: continuationToken, value = [] } = await this.table.query({
            ...listOptions,
            nextTableName,
        });
        return Object.assign([...value], { continuationToken });
    }
    /**
     *
     * Creates an instance of TableServiceClient from connection string.
     *
     * @param connectionString - Account connection string or a SAS connection string of an Azure storage account.
     *                           [ Note - Account connection string can only be used in NODE.JS runtime. ]
     *                           Account connection string example -
     *                           `DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=accountKey;EndpointSuffix=core.windows.net`
     *                           SAS connection string example -
     *                           `BlobEndpoint=https://myaccount.table.core.windows.net/;QueueEndpoint=https://myaccount.queue.core.windows.net/;FileEndpoint=https://myaccount.file.core.windows.net/;TableEndpoint=https://myaccount.table.core.windows.net/;SharedAccessSignature=sasString`
     * @param options - Options to configure the HTTP pipeline.
     * @returns A new TableServiceClient from the given connection string.
     */
    static fromConnectionString(connectionString, 
    // eslint-disable-next-line @azure/azure-sdk/ts-naming-options
    options) {
        const { url, options: clientOptions, credential, } = getClientParamsFromConnectionString(connectionString, options);
        if (credential) {
            return new TableServiceClient(url, credential, clientOptions);
        }
        else {
            return new TableServiceClient(url, clientOptions);
        }
    }
}
//# sourceMappingURL=TableServiceClient.js.map