/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Tiles
 */
import { BentleyStatus } from "@itwin/core-bentley";
import { IModelError, RealityDataFormat } from "@itwin/core-common";
import { request } from "../request/Request";
import { ThreeDTileFormatInterpreter } from "../tile/internal";
/** This class provides access to the reality data provider services.
 * It encapsulates access to a reality data from the Google Photorealistic 3D Tiles service.
 * A valid Google 3D Tiles authentication key must be configured for this provider to work (provide the key in the [[RealityDataSourceGoogle3dTilesImpl.createFromKey]] method).
* @internal
*/
export class RealityDataSourceGoogle3dTilesImpl {
    key;
    /** The URL that supplies the 3d tiles for displaying the Google 3D Tiles tileset. */
    _tilesetUrl;
    /** Base URL of the Google 3D Tiles tileset. Does not include trailing subdirectories. */
    _baseUrl = "";
    /** Search parameters that must be passed down to child tile requests. */
    _searchParams;
    /** Google Map Tiles API Key used to access Google 3D Tiles. */
    _apiKey;
    /** Function that returns an OAuth token for authenticating with GP3sDT. This token is expected to not contain the "Bearer" prefix. */
    _getAuthToken;
    /** This is necessary for Google 3D Tiles tilesets! This tells the iTwin.js tiling system to use the geometric error specified in the tileset rather than any of our own. */
    usesGeometricError = true;
    maximumScreenSpaceError = 16;
    /** Construct a new reality data source.
     * @param props JSON representation of the reality data source
     */
    constructor(props, apiKey, _getAuthToken) {
        this.key = props.sourceKey;
        this._tilesetUrl = this.key.id;
        this._apiKey = apiKey;
        this._getAuthToken = _getAuthToken;
    }
    /**
     * Create an instance of this class from a source key and iTwin context.
     */
    static async createFromKey(sourceKey, _iTwinId, apiKey, _getAuthToken) {
        return new RealityDataSourceGoogle3dTilesImpl({ sourceKey }, apiKey, _getAuthToken);
    }
    get isContextShare() {
        return false;
    }
    /**
     * Returns Reality Data if available
    */
    get realityData() {
        return undefined;
    }
    get realityDataId() {
        return undefined;
    }
    /**
     * Returns Reality Data type if available
     */
    get realityDataType() {
        return undefined;
    }
    getTilesetUrl() {
        return this._tilesetUrl;
    }
    /** Return the URL of the Google 3D Tiles tileset with its API key included. */
    getTilesetUrlWithKey() {
        const google3dTilesKey = this._apiKey;
        if (this._getAuthToken) {
            // If we have a getAuthToken function, no need to append API key to the URL
            return this._tilesetUrl;
        }
        else {
            return `${this._tilesetUrl}?key=${google3dTilesKey}`;
        }
    }
    setBaseUrl(url) {
        const urlParts = url.split("/");
        const newUrl = new URL(url);
        this._searchParams = newUrl.searchParams;
        urlParts.pop();
        if (urlParts.length === 0) {
            this._baseUrl = "";
        }
        else {
            this._baseUrl = newUrl.origin;
        }
    }
    /**
     * This method returns the URL to access the actual 3d tiles from the service provider.
     * @returns string containing the URL to reality data.
     */
    async getServiceUrl(_iTwinId) {
        return this._tilesetUrl;
    }
    async getRootDocument(_iTwinId) {
        const url = this.getTilesetUrlWithKey();
        if (!url)
            throw new IModelError(BentleyStatus.ERROR, "Unable to get service url");
        this.setBaseUrl(url);
        let authToken;
        if (this._getAuthToken) {
            authToken = await this._getAuthToken();
        }
        return request(url, "json", authToken ? {
            headers: {
                authorization: `Bearer ${authToken}`
            }
        } : undefined);
    }
    /** Returns the tile URL relative to the base URL.
     * If the tile path is a relative URL, the base URL is prepended to it.
     * For both absolute and relative tile path URLs, the search parameters are checked. If the search params are empty, the base URL's search params are appended to the tile path.
     */
    getTileUrl(tilePath) {
        // this._baseUrl does not include the trailing subdirectories.
        // This is not an issue because the tile path always starts with the appropriate subdirectories.
        // We also do not need to worry about the tile path starting with a slash.
        // This happens in these tiles at the second .json level, but the URL API will handle that for us.
        const url = new URL(tilePath, this._baseUrl);
        // If tile is a reference to a tileset, iterate over tileset url's search params and store them in this._searchParams so we can pass them down to children
        if (this.getTileContentType(url.toString()) === "tileset" && url.searchParams.size !== 0) {
            for (const [key, value] of url.searchParams.entries()) {
                this._searchParams?.append(key, value);
            }
        }
        if (this._searchParams === undefined || this._searchParams.size === 0) {
            return url.toString();
        }
        // Append all stored search params to url's existing ones
        const newUrl = new URL(url.toString());
        for (const [key, value] of this._searchParams.entries()) {
            if (!url.searchParams.has(key)) {
                // Only append the search param if it does not already exist in the url
                newUrl.searchParams.append(key, value);
            }
        }
        return newUrl.toString();
    }
    /**
     * Returns the tile content. The path to the tile is relative to the base url of present reality data whatever the type.
     */
    async getTileContent(name) {
        let authToken;
        if (this._getAuthToken) {
            authToken = await this._getAuthToken();
        }
        return request(this.getTileUrl(name), "arraybuffer", authToken ? {
            headers: {
                authorization: `Bearer ${authToken}`
            }
        } : undefined);
    }
    /**
     * Returns the tile content in json format. The path to the tile is relative to the base url of present reality data whatever the type.
     */
    async getTileJson(name) {
        let authToken;
        if (this._getAuthToken) {
            authToken = await this._getAuthToken();
        }
        return request(this.getTileUrl(name), "json", authToken ? {
            headers: {
                authorization: `Bearer ${authToken}`
            }
        } : undefined);
    }
    getTileContentType(url) {
        return new URL(url, "https://localhost/").pathname.toLowerCase().endsWith("json") ? "tileset" : "tile";
    }
    /**
     * Gets spatial location and extents of this reality data source
     * @returns spatial location and extents
     * @internal
     */
    async getSpatialLocationAndExtents() {
        let spatialLocation;
        if (this.key.format === RealityDataFormat.ThreeDTile) {
            const rootDocument = await this.getRootDocument(undefined);
            spatialLocation = ThreeDTileFormatInterpreter.getSpatialLocationAndExtents(rootDocument);
        }
        return spatialLocation;
    }
    /**
     * Gets information to identify the product and engine that create this reality data
     * Will return undefined if cannot be resolved
     * @returns information to identify the product and engine that create this reality data
     * @alpha
     */
    async getPublisherProductInfo() {
        let publisherInfo;
        return publisherInfo;
    }
}
//# sourceMappingURL=RealityDataSourceGoogle3dTilesImpl.js.map