"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FirestoreEmulator = void 0;
const chokidar = require("chokidar");
const fs = require("fs");
const clc = require("colorette");
const path = require("path");
const utils = require("../utils");
const downloadableEmulators = require("./downloadableEmulators");
const types_1 = require("../emulator/types");
const registry_1 = require("./registry");
const constants_1 = require("./constants");
class FirestoreEmulator {
    constructor(args) {
        this.args = args;
    }
    async start() {
        if (registry_1.EmulatorRegistry.isRunning(types_1.Emulators.FUNCTIONS)) {
            this.args.functions_emulator = registry_1.EmulatorRegistry.url(types_1.Emulators.FUNCTIONS).host;
        }
        if (this.args.rules && this.args.project_id) {
            const rulesPath = this.args.rules;
            this.rulesWatcher = chokidar.watch(rulesPath, { persistent: true, ignoreInitial: true });
            this.rulesWatcher.on("change", async () => {
                await new Promise((res) => setTimeout(res, 5));
                utils.logLabeledBullet("firestore", "Change detected, updating rules...");
                const newContent = fs.readFileSync(rulesPath, "utf8").toString();
                const issues = await this.updateRules(newContent);
                if (issues) {
                    for (const issue of issues) {
                        utils.logWarning(this.prettyPrintRulesIssue(rulesPath, issue));
                    }
                }
                if (issues.some((issue) => issue.severity === types_1.Severity.ERROR)) {
                    utils.logWarning("Failed to update rules");
                }
                else {
                    utils.logLabeledSuccess("firestore", "Rules updated.");
                }
            });
        }
        return downloadableEmulators.start(types_1.Emulators.FIRESTORE, this.args);
    }
    connect() {
        return Promise.resolve();
    }
    stop() {
        if (this.rulesWatcher) {
            this.rulesWatcher.close();
        }
        return downloadableEmulators.stop(types_1.Emulators.FIRESTORE);
    }
    getInfo() {
        const host = this.args.host || constants_1.Constants.getDefaultHost();
        const port = this.args.port || constants_1.Constants.getDefaultPort(types_1.Emulators.FIRESTORE);
        const reservedPorts = this.args.websocket_port ? [this.args.websocket_port] : [];
        return {
            name: this.getName(),
            host,
            port,
            pid: downloadableEmulators.getPID(types_1.Emulators.FIRESTORE),
            reservedPorts: reservedPorts,
            webSocketHost: this.args.websocket_port ? host : undefined,
            webSocketPort: this.args.websocket_port ? this.args.websocket_port : undefined,
        };
    }
    getName() {
        return types_1.Emulators.FIRESTORE;
    }
    async updateRules(content) {
        const projectId = this.args.project_id;
        const body = {
            ignore_errors: true,
            rules: {
                files: [
                    {
                        name: "security.rules",
                        content,
                    },
                ],
            },
        };
        const res = await registry_1.EmulatorRegistry.client(types_1.Emulators.FIRESTORE).put(`/emulator/v1/projects/${projectId}:securityRules`, body);
        if (res.body && Array.isArray(res.body.issues)) {
            return res.body.issues;
        }
        return [];
    }
    prettyPrintRulesIssue(filePath, issue) {
        const relativePath = path.relative(process.cwd(), filePath);
        const line = issue.sourcePosition.line || 0;
        const col = issue.sourcePosition.column || 0;
        return `${clc.cyan(relativePath)}:${clc.yellow(line)}:${clc.yellow(col)} - ${clc.red(issue.severity)} ${issue.description}`;
    }
}
exports.FirestoreEmulator = FirestoreEmulator;
