/*! firebase-admin v8.7.0 */
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var url_1 = require("url");
var path = require("path");
var error_1 = require("../utils/error");
var validator = require("../utils/validator");
var api_request_1 = require("../utils/api-request");
/**
 * Internals of a Database instance.
 */
var DatabaseInternals = /** @class */ (function () {
    function DatabaseInternals() {
        this.databases = {};
    }
    /**
     * Deletes the service and its associated resources.
     *
     * @return {Promise<()>} An empty Promise that will be fulfilled when the service is deleted.
     */
    DatabaseInternals.prototype.delete = function () {
        for (var _i = 0, _a = Object.keys(this.databases); _i < _a.length; _i++) {
            var dbUrl = _a[_i];
            var db = this.databases[dbUrl];
            db.INTERNAL.delete();
        }
        return Promise.resolve(undefined);
    };
    return DatabaseInternals;
}());
var DatabaseService = /** @class */ (function () {
    function DatabaseService(app) {
        this.INTERNAL = new DatabaseInternals();
        if (!validator.isNonNullObject(app) || !('options' in app)) {
            throw new error_1.FirebaseDatabaseError({
                code: 'invalid-argument',
                message: 'First argument passed to admin.database() must be a valid Firebase app instance.',
            });
        }
        this.appInternal = app;
    }
    Object.defineProperty(DatabaseService.prototype, "app", {
        /**
         * Returns the app associated with this DatabaseService instance.
         *
         * @return {FirebaseApp} The app associated with this DatabaseService instance.
         */
        get: function () {
            return this.appInternal;
        },
        enumerable: true,
        configurable: true
    });
    DatabaseService.prototype.getDatabase = function (url) {
        var dbUrl = this.ensureUrl(url);
        if (!validator.isNonEmptyString(dbUrl)) {
            throw new error_1.FirebaseDatabaseError({
                code: 'invalid-argument',
                message: 'Database URL must be a valid, non-empty URL string.',
            });
        }
        var db = this.INTERNAL.databases[dbUrl];
        if (typeof db === 'undefined') {
            var rtdb = require('@firebase/database');
            var version = require('../../package.json').version;
            db = rtdb.initStandalone(this.appInternal, dbUrl, version).instance;
            var rulesClient_1 = new DatabaseRulesClient(this.app, dbUrl);
            db.getRules = function () {
                return rulesClient_1.getRules();
            };
            db.getRulesJSON = function () {
                return rulesClient_1.getRulesJSON();
            };
            db.setRules = function (source) {
                return rulesClient_1.setRules(source);
            };
            this.INTERNAL.databases[dbUrl] = db;
        }
        return db;
    };
    DatabaseService.prototype.ensureUrl = function (url) {
        if (typeof url !== 'undefined') {
            return url;
        }
        else if (typeof this.appInternal.options.databaseURL !== 'undefined') {
            return this.appInternal.options.databaseURL;
        }
        throw new error_1.FirebaseDatabaseError({
            code: 'invalid-argument',
            message: 'Can\'t determine Firebase Database URL.',
        });
    };
    return DatabaseService;
}());
exports.DatabaseService = DatabaseService;
var RULES_URL_PATH = '.settings/rules.json';
/**
 * A helper client for managing RTDB security rules.
 */
var DatabaseRulesClient = /** @class */ (function () {
    function DatabaseRulesClient(app, dbUrl) {
        var parsedUrl = new url_1.URL(dbUrl);
        parsedUrl.pathname = path.join(parsedUrl.pathname, RULES_URL_PATH);
        this.dbUrl = parsedUrl.toString();
        this.httpClient = new api_request_1.AuthorizedHttpClient(app);
    }
    /**
     * Gets the currently applied security rules as a string. The return value consists of
     * the rules source including comments.
     *
     * @return {Promise<string>} A promise fulfilled with the rules as a raw string.
     */
    DatabaseRulesClient.prototype.getRules = function () {
        var _this = this;
        var req = {
            method: 'GET',
            url: this.dbUrl,
        };
        return this.httpClient.send(req)
            .then(function (resp) {
            return resp.text;
        })
            .catch(function (err) {
            throw _this.handleError(err);
        });
    };
    /**
     * Gets the currently applied security rules as a parsed JSON object. Any comments in
     * the original source are stripped away.
     *
     * @return {Promise<object>} A promise fulfilled with the parsed rules source.
     */
    DatabaseRulesClient.prototype.getRulesJSON = function () {
        var _this = this;
        var req = {
            method: 'GET',
            url: this.dbUrl,
            data: { format: 'strict' },
        };
        return this.httpClient.send(req)
            .then(function (resp) {
            return resp.data;
        })
            .catch(function (err) {
            throw _this.handleError(err);
        });
    };
    /**
     * Sets the specified rules on the Firebase Database instance. If the rules source is
     * specified as a string or a Buffer, it may include comments.
     *
     * @param {string|Buffer|object} source Source of the rules to apply. Must not be `null`
     *  or empty.
     * @return {Promise<void>} Resolves when the rules are set on the Database.
     */
    DatabaseRulesClient.prototype.setRules = function (source) {
        var _this = this;
        if (!validator.isNonEmptyString(source) &&
            !validator.isBuffer(source) &&
            !validator.isNonNullObject(source)) {
            var error = new error_1.FirebaseDatabaseError({
                code: 'invalid-argument',
                message: 'Source must be a non-empty string, Buffer or an object.',
            });
            return Promise.reject(error);
        }
        var req = {
            method: 'PUT',
            url: this.dbUrl,
            data: source,
            headers: {
                'content-type': 'application/json; charset=utf-8',
            },
        };
        return this.httpClient.send(req)
            .then(function () {
            return;
        })
            .catch(function (err) {
            throw _this.handleError(err);
        });
    };
    DatabaseRulesClient.prototype.handleError = function (err) {
        if (err instanceof api_request_1.HttpError) {
            return new error_1.FirebaseDatabaseError({
                code: error_1.AppErrorCodes.INTERNAL_ERROR,
                message: this.getErrorMessage(err),
            });
        }
        return err;
    };
    DatabaseRulesClient.prototype.getErrorMessage = function (err) {
        var intro = 'Error while accessing security rules';
        try {
            var body = err.response.data;
            if (body && body.error) {
                return intro + ": " + body.error.trim();
            }
        }
        catch (_a) {
            // Ignore parsing errors
        }
        return intro + ": " + err.response.text;
    };
    return DatabaseRulesClient;
}());
