"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthEmulator = exports.SingleProjectMode = void 0;
const fs = require("fs");
const path = require("path");
const http = require("http");
const utils = require("../../utils");
const constants_1 = require("../constants");
const emulatorLogger_1 = require("../emulatorLogger");
const types_1 = require("../types");
const server_1 = require("./server");
const error_1 = require("../../error");
const track_1 = require("../../track");
var SingleProjectMode;
(function (SingleProjectMode) {
    SingleProjectMode[SingleProjectMode["NO_WARNING"] = 0] = "NO_WARNING";
    SingleProjectMode[SingleProjectMode["WARNING"] = 1] = "WARNING";
    SingleProjectMode[SingleProjectMode["ERROR"] = 2] = "ERROR";
})(SingleProjectMode = exports.SingleProjectMode || (exports.SingleProjectMode = {}));
class AuthEmulator {
    constructor(args) {
        this.args = args;
    }
    async start() {
        const { host, port } = this.getInfo();
        const app = await (0, server_1.createApp)(this.args.projectId, this.args.singleProjectMode);
        const server = app.listen(port, host);
        this.destroyServer = utils.createDestroyer(server);
    }
    async connect() {
    }
    stop() {
        return this.destroyServer ? this.destroyServer() : Promise.resolve();
    }
    getInfo() {
        const host = this.args.host || constants_1.Constants.getDefaultHost();
        const port = this.args.port || constants_1.Constants.getDefaultPort(types_1.Emulators.AUTH);
        return {
            name: this.getName(),
            host,
            port,
        };
    }
    getName() {
        return types_1.Emulators.AUTH;
    }
    async importData(authExportDir, projectId, options) {
        void (0, track_1.trackEmulator)("emulator_import", {
            initiated_by: options.initiatedBy,
            emulator_name: types_1.Emulators.AUTH,
        });
        const logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.AUTH);
        const { host, port } = this.getInfo();
        const configPath = path.join(authExportDir, "config.json");
        const configStat = await stat(configPath);
        if (configStat === null || configStat === void 0 ? void 0 : configStat.isFile()) {
            logger.logLabeled("BULLET", "auth", `Importing config from ${configPath}`);
            await importFromFile({
                method: "PATCH",
                host: utils.connectableHostname(host),
                port,
                path: `/emulator/v1/projects/${projectId}/config`,
                headers: {
                    Authorization: "Bearer owner",
                    "Content-Type": "application/json",
                },
            }, configPath);
        }
        else {
            logger.logLabeled("WARN", "auth", `Skipped importing config because ${configPath} does not exist.`);
        }
        const accountsPath = path.join(authExportDir, "accounts.json");
        const accountsStat = await stat(accountsPath);
        if (accountsStat === null || accountsStat === void 0 ? void 0 : accountsStat.isFile()) {
            logger.logLabeled("BULLET", "auth", `Importing accounts from ${accountsPath}`);
            await importFromFile({
                method: "POST",
                host: utils.connectableHostname(host),
                port,
                path: `/identitytoolkit.googleapis.com/v1/projects/${projectId}/accounts:batchCreate`,
                headers: {
                    Authorization: "Bearer owner",
                    "Content-Type": "application/json",
                },
            }, accountsPath, { ignoreErrors: ["MISSING_USER_ACCOUNT"] });
        }
        else {
            logger.logLabeled("WARN", "auth", `Skipped importing accounts because ${accountsPath} does not exist.`);
        }
    }
}
exports.AuthEmulator = AuthEmulator;
function stat(path) {
    return new Promise((resolve, reject) => fs.stat(path, (err, stats) => {
        if (err) {
            if (err.code === "ENOENT") {
                return resolve(undefined);
            }
            return reject(err);
        }
        else {
            return resolve(stats);
        }
    }));
}
function importFromFile(reqOptions, path, options = {}) {
    const readStream = fs.createReadStream(path);
    return new Promise((resolve, reject) => {
        const req = http.request(reqOptions, (response) => {
            if (response.statusCode === 200) {
                resolve();
            }
            else {
                let data = "";
                response
                    .on("data", (d) => {
                    data += d.toString();
                })
                    .on("error", reject)
                    .on("end", () => {
                    const ignoreErrors = options === null || options === void 0 ? void 0 : options.ignoreErrors;
                    if (ignoreErrors === null || ignoreErrors === void 0 ? void 0 : ignoreErrors.length) {
                        let message;
                        try {
                            message = JSON.parse(data).error.message;
                        }
                        catch (_a) {
                            message = undefined;
                        }
                        if (message && ignoreErrors.includes(message)) {
                            return resolve();
                        }
                    }
                    return reject(new error_1.FirebaseError(`Received HTTP status code: ${response.statusCode}\n${data}`));
                });
            }
        });
        req.on("error", reject);
        readStream.pipe(req, { end: true });
    }).catch((e) => {
        throw new error_1.FirebaseError(`Error during Auth Emulator import: ${e.message}`, {
            original: e,
            exit: 1,
        });
    });
}