"use strict";
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.watchLoad = watchLoad;
const fs_1 = require("fs");
const promises_1 = __importDefault(require("fs/promises"));
const util_files_1 = require("./util-files");
const debounceAsync_1 = require("./debounceAsync");
const events_1 = require("./events");
function watchLoad(path, parser, { failedOnFirstAttempt, immediateFirst } = {}) {
    let doing = false;
    let watcher;
    const debounced = (0, debounceAsync_1.debounceAsync)(load, { wait: 500, maxWait: 1000, reuseRunning: true });
    let retry;
    let last;
    const emitter = new events_1.BetterEventEmitter();
    const save = (0, debounceAsync_1.debounceAsync)(async (data, { reparse = false } = {}) => {
        await promises_1.default.writeFile(path, data, 'utf8');
        last = data;
        if (reparse)
            await parser(data);
        emitter.emit('change', last);
    });
    install(true);
    return { unwatch, save, emitter, getText: () => last, getPath: () => path };
    function install(first = false) {
        try {
            watcher = (0, fs_1.watch)(path, () => {
                if (!save.isWorking())
                    void debounced();
            });
            debounced().catch(x => x);
            if (immediateFirst && first)
                void debounced.flush();
        }
        catch (e) {
            retry = setTimeout(install, 3_000); // manual watching until watch is successful
            if (first)
                failedOnFirstAttempt?.();
        }
    }
    function unwatch() {
        watcher?.close();
        clearTimeout(retry);
        watcher = undefined;
    }
    async function load() {
        if (doing)
            return;
        doing = true;
        try {
            await save.flush(); // apply pending saves first
            const text = await (0, util_files_1.readFileWithBusyRetry)(path).catch(e => {
                if (e.code === 'EPERM')
                    console.error("Missing permissions on file", path); // warn user, who could be clueless about this problem
                // keep the last good content on transient read failures so we don't apply accidental "empty file" state
                if (e.code === 'ENOENT')
                    return '';
                throw e;
            });
            if (text === last)
                return;
            last = text;
            emitter.emit('change', last);
            console.debug('Loaded', path);
            unwatch();
            install(); // reinstall, as the original file could have been renamed. We watch by the name.
            await parser(text);
        }
        catch (e) {
            console.error("Error loading", path, String(e));
        }
        finally {
            doing = false;
        }
    }
}
