import { createReadStream, existsSync, statSync, readdirSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { join, dirname } from "node:path";
import { createInterface } from "node:readline";
import { spawn } from "node:child_process";
import { fileURLToPath } from "node:url";
import { getLogDir } from "../../utils/paths.js";
/**
 * Find the pino-pretty binary path.
 * Looks in node_modules/.bin relative to the package.
 */
function findPinoPretty() {
    // Try to find pino-pretty in node_modules/.bin
    const __dirname = dirname(fileURLToPath(import.meta.url));
    const localBin = join(__dirname, "..", "..", "..", "node_modules", ".bin", "pino-pretty");
    if (existsSync(localBin)) {
        return localBin;
    }
    // For global installs, pino-pretty should be in the same node_modules
    const globalBin = join(__dirname, "..", "..", "node_modules", ".bin", "pino-pretty");
    if (existsSync(globalBin)) {
        return globalBin;
    }
    return null;
}
/**
 * Find the current log file. pino-roll creates files like daemon.1.log, daemon.2.log, etc.
 * Returns the most recently modified log file matching the daemon.*.log pattern.
 */
function findLogFile() {
    const logDir = getLogDir();
    if (!existsSync(logDir)) {
        return null;
    }
    try {
        const files = readdirSync(logDir);
        const logFiles = files
            .filter((f) => f.startsWith("daemon.") && f.endsWith(".log"))
            .map((f) => ({
            name: f,
            path: join(logDir, f),
            mtime: statSync(join(logDir, f)).mtime.getTime(),
        }))
            .sort((a, b) => b.mtime - a.mtime); // Most recent first
        return logFiles.length > 0 ? logFiles[0].path : null;
    }
    catch {
        return null;
    }
}
/**
 * Output a line, optionally through pino-pretty.
 */
function outputLine(line, prettyProcess) {
    if (prettyProcess?.stdin?.writable) {
        prettyProcess.stdin.write(line + "\n");
    }
    else {
        console.log(line);
    }
}
/**
 * Handle the `pocketcoder logs` CLI command.
 * Shows daemon log output with --tail and --follow options.
 */
export async function logsCommand(opts) {
    const logFile = findLogFile();
    if (!logFile) {
        console.log("No log file found. Is the daemon running?");
        return;
    }
    const tailLines = parseInt(opts.tail, 10);
    if (Number.isNaN(tailLines) || tailLines < 1) {
        console.error("Invalid --tail value. Must be a positive number.");
        process.exitCode = 1;
        return;
    }
    // Set up pino-pretty if requested
    let prettyProcess = null;
    if (opts.pretty) {
        const pinoPrettyPath = findPinoPretty();
        if (!pinoPrettyPath) {
            console.error("pino-pretty not found. Install it with: npm install -g pino-pretty");
            process.exitCode = 1;
            return;
        }
        prettyProcess = spawn(pinoPrettyPath, [], {
            stdio: ["pipe", "inherit", "inherit"],
        });
    }
    // Show last N lines
    const content = await readFile(logFile, "utf-8");
    const lines = content.split("\n");
    // Remove trailing empty line from split
    if (lines.length > 0 && lines[lines.length - 1] === "") {
        lines.pop();
    }
    const startIndex = Math.max(0, lines.length - tailLines);
    const lastLines = lines.slice(startIndex);
    for (const line of lastLines) {
        outputLine(line, prettyProcess);
    }
    // Follow mode
    if (opts.follow) {
        await followLog(logFile, prettyProcess);
    }
    else {
        // Close pino-pretty stdin to let it finish
        prettyProcess?.stdin?.end();
    }
}
/**
 * Follow the log file, printing new lines as they appear (like tail -f).
 * Runs until the process is interrupted (Ctrl+C).
 */
function followLog(logFile, prettyProcess) {
    return new Promise((resolve) => {
        let fileSize = 0;
        try {
            fileSize = statSync(logFile).size;
        }
        catch {
            // Start from beginning if we can't stat
        }
        const checkInterval = setInterval(() => {
            let currentSize;
            try {
                currentSize = statSync(logFile).size;
            }
            catch {
                // File might have been rotated or removed
                return;
            }
            if (currentSize > fileSize) {
                const stream = createReadStream(logFile, {
                    start: fileSize,
                    encoding: "utf-8",
                });
                const rl = createInterface({ input: stream });
                rl.on("line", (line) => {
                    outputLine(line, prettyProcess);
                });
                rl.on("close", () => {
                    fileSize = currentSize;
                });
            }
            else if (currentSize < fileSize) {
                // File was truncated/rotated, start from beginning
                fileSize = 0;
            }
        }, 500);
        // Clean up on SIGINT
        const onSignal = () => {
            clearInterval(checkInterval);
            prettyProcess?.stdin?.end();
            prettyProcess?.kill();
            resolve();
        };
        process.once("SIGINT", onSignal);
        process.once("SIGTERM", onSignal);
    });
}
//# sourceMappingURL=logs.js.map