var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _FileHandler_instances, _FileHandler_unloadCallback, _FileHandler_resetBuffer, _a, _b, _c, _d, _e, _f, _g;
// Copyright 2018-2025 the Deno authors. MIT license.
import * as dntShim from "../../../../../_dnt.shims.js";
import { LogLevels } from "./levels.js";
import { BaseHandler } from "./base_handler.js";
import { writeAllSync } from "../../io/0.225.2/write_all.js";
import { bufSymbol, encoderSymbol, filenameSymbol, fileSymbol, modeSymbol, openOptionsSymbol, pointerSymbol, } from "./_file_handler_symbols.js";
/**
 * A file-based log handler that writes log messages to a specified file with buffering and optional modes.
 * The logs are buffered for optimized performance, writing to the file only
 * when the buffer is full, on manual .flush() call, during logging of a critical message or when process ends.
 * It is important to note that the file can grow indefinitely.
 *
 * This handler requires `--allow-write` permission on the log file.
 *
 * @example Usage
 * ```ts no-assert
 * import { FileHandler } from "@std/log/file-handler";
 *
 * const handler = new FileHandler("INFO", { filename: "./_tmp/logs.txt" });
 * handler.setup();
 * handler.log('Hello, world!'); // Buffers the message, or writes it to the file depending on buffer state
 * handler.flush(); // Manually flushes the buffer
 * handler.destroy(); // Closes the file and removes listeners
 * ```
 */
export class FileHandler extends BaseHandler {
    /**
     * Constructs a new FileHandler instance.
     *
     * @param levelName The level name to log messages at.
     * @param options Options for the handler.
     */
    constructor(levelName, options) {
        super(levelName, options);
        _FileHandler_instances.add(this);
        /** Opened file to append logs to.
         *
         * @private
         */
        Object.defineProperty(this, _a, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        /** Buffer used to write to file.
         *
         * @private
         */
        Object.defineProperty(this, _b, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        /**
         * Current position for pointer.
         *
         * @private
         */
        Object.defineProperty(this, _c, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 0
        });
        /**
         * Filename associated with the file being logged.
         *
         * @private
         */
        Object.defineProperty(this, _d, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        /**
         * Current log mode.
         *
         * @private
         */
        Object.defineProperty(this, _e, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        /**
         * File open options.
         *
         * @private
         */
        Object.defineProperty(this, _f, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        /**
         * Text encoder.
         *
         * @private
         */
        Object.defineProperty(this, _g, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: new TextEncoder()
        });
        _FileHandler_unloadCallback.set(this, (() => {
            this.destroy();
        }).bind(this));
        this[filenameSymbol] = options.filename;
        // default to append mode, write only
        this[modeSymbol] = options.mode ?? "a";
        this[openOptionsSymbol] = {
            createNew: this[modeSymbol] === "x",
            create: this[modeSymbol] !== "x",
            append: this[modeSymbol] === "a",
            truncate: this[modeSymbol] !== "a",
            write: true,
        };
        this[bufSymbol] = new Uint8Array(options.bufferSize ?? 4096);
    }
    /**
     * Sets up the file handler by opening the specified file and initializing resources.
     *
     * @example Usage
     * ```ts no-assert
     * import { FileHandler } from "@std/log/file-handler";
     *
     * const handler = new FileHandler("INFO", { filename: "./_tmp/logs.txt" });
     * handler.setup(); // Opens the file and prepares the handler for logging.
     * handler.destroy();
     * ```
     */
    setup() {
        this[fileSymbol] = dntShim.Deno.openSync(this[filenameSymbol], this[openOptionsSymbol]);
        __classPrivateFieldGet(this, _FileHandler_instances, "m", _FileHandler_resetBuffer).call(this);
        addEventListener("unload", __classPrivateFieldGet(this, _FileHandler_unloadCallback, "f"));
    }
    /**
     * Handles a log record and flushes the buffer if the log level is higher than error.
     *
     * @param logRecord Log record to handle.
     *
     * @example Usage
     * ```ts
     * import { FileHandler } from "@std/log/file-handler";
     * import { assertInstanceOf } from "@std/assert/instance-of";
     * import { LogLevels } from "./levels.ts";
     * import { LogRecord } from "./logger.ts";
     *
     * const handler = new FileHandler("INFO", { filename: "./_tmp/logs.txt" });
     * handler.setup();
     *
     * // Flushes the buffer immediately and logs "CRITICAL This log is very critical indeed." into the file.
     * handler.handle(
     *   new LogRecord({
     *     msg: "This log is very critical indeed.",
     *     args: [],
     *     level: LogLevels.CRITICAL,
     *     loggerName: "INFO",
     *   }),
     * );
     * handler.destroy();
     *
     * assertInstanceOf(handler, FileHandler);
     * ```
     */
    handle(logRecord) {
        super.handle(logRecord);
        // Immediately flush if log level is higher than ERROR
        if (logRecord.level > LogLevels.ERROR) {
            this.flush();
        }
    }
    /**
     * Logs a message by adding it to the buffer, with flushing as needed.
     *
     * @param msg The message to log.
     *
     * @example Usage
     * ```ts
     * import { FileHandler } from "@std/log/file-handler";
     * import { assertInstanceOf } from "@std/assert/instance-of";
     *
     * const handler = new FileHandler("INFO", { filename: "./_tmp/logs.txt" });
     * handler.setup();
     * handler.log('Hello, world!');
     * handler.flush();
     * handler.destroy();
     *
     * assertInstanceOf(handler, FileHandler);
     * ```
     */
    log(msg) {
        const bytes = this[encoderSymbol].encode(msg + "\n");
        if (bytes.byteLength > this[bufSymbol].byteLength - this[pointerSymbol]) {
            this.flush();
        }
        if (bytes.byteLength > this[bufSymbol].byteLength) {
            writeAllSync(this[fileSymbol], bytes);
        }
        else {
            this[bufSymbol].set(bytes, this[pointerSymbol]);
            this[pointerSymbol] += bytes.byteLength;
        }
    }
    /**
     * Immediately writes the contents of the buffer to the previously opened file.
     *
     * @example Usage
     * ```ts
     * import { FileHandler } from "@std/log/file-handler";
     * import { assertInstanceOf } from "@std/assert/instance-of";
     *
     * const handler = new FileHandler("INFO", { filename: "./_tmp/logs.txt" });
     * handler.setup();
     * handler.log('Hello, world!');
     * handler.flush(); // Writes buffered log messages to the file immediately.
     * handler.destroy();
     *
     * assertInstanceOf(handler, FileHandler);
     * ```
     */
    flush() {
        if (this[pointerSymbol] > 0 && this[fileSymbol]) {
            let written = 0;
            while (written < this[pointerSymbol]) {
                written += this[fileSymbol].writeSync(this[bufSymbol].subarray(written, this[pointerSymbol]));
            }
            __classPrivateFieldGet(this, _FileHandler_instances, "m", _FileHandler_resetBuffer).call(this);
        }
    }
    /**
     * Destroys the handler, performing any cleanup that is required and closes the file handler.
     *
     * @example Usage
     * ```ts
     * import { FileHandler } from "@std/log/file-handler";
     * import { assertInstanceOf } from "@std/assert/instance-of";
     *
     * const handler = new FileHandler("INFO", { filename: "./_tmp/logs.txt" });
     * handler.setup();
     * handler.destroy();
     *
     * assertInstanceOf(handler, FileHandler);
     * ```
     */
    destroy() {
        this.flush();
        this[fileSymbol]?.close();
        this[fileSymbol] = undefined;
        removeEventListener("unload", __classPrivateFieldGet(this, _FileHandler_unloadCallback, "f"));
    }
}
_FileHandler_unloadCallback = new WeakMap(), _FileHandler_instances = new WeakSet(), _a = fileSymbol, _b = bufSymbol, _c = pointerSymbol, _d = filenameSymbol, _e = modeSymbol, _f = openOptionsSymbol, _g = encoderSymbol, _FileHandler_resetBuffer = function _FileHandler_resetBuffer() {
    this[pointerSymbol] = 0;
};
