import { describe, expect, it, beforeEach, afterEach, vi } from "vitest";
// Mock pino before importing logger
const mockChild = vi.fn();
const mockPinoLogger = {
    debug: vi.fn(),
    info: vi.fn(),
    warn: vi.fn(),
    error: vi.fn(),
    child: mockChild,
};
const mockChildLogger = {
    debug: vi.fn(),
    info: vi.fn(),
    warn: vi.fn(),
    error: vi.fn(),
    child: vi.fn(),
};
vi.mock("pino", () => {
    const pinoFn = vi.fn(() => mockPinoLogger);
    return { default: pinoFn };
});
vi.mock("../paths.js", () => ({
    getLogDir: () => "/tmp/pocketcoder-test-logs",
}));
vi.mock("node:fs", () => ({
    mkdirSync: vi.fn(),
}));
describe("logger", () => {
    beforeEach(() => {
        vi.resetModules();
        vi.clearAllMocks();
        mockChild.mockReturnValue(mockChildLogger);
    });
    afterEach(() => {
        delete process.env.LOG_LEVEL;
        delete process.env.NODE_ENV;
    });
    it("should respect LOG_LEVEL environment variable", async () => {
        process.env.LOG_LEVEL = "debug";
        // Reset the singleton so it re-creates with the new env
        vi.resetModules();
        vi.clearAllMocks();
        // Re-mock after reset
        const mockLogger2 = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn(),
        };
        const pinoMock = vi.fn(() => mockLogger2);
        vi.doMock("pino", () => ({ default: pinoMock }));
        vi.doMock("../paths.js", () => ({ getLogDir: () => "/tmp/pocketcoder-test-logs" }));
        vi.doMock("node:fs", () => ({ mkdirSync: vi.fn() }));
        const { logger } = await import("../logger.js");
        logger.info("test");
        // pino was called with level from env
        expect(pinoMock).toHaveBeenCalledWith(expect.objectContaining({ level: "debug" }));
    });
    it("should default to info level when LOG_LEVEL is not set", async () => {
        delete process.env.LOG_LEVEL;
        vi.resetModules();
        vi.clearAllMocks();
        const mockLogger2 = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn(),
        };
        const pinoMock = vi.fn(() => mockLogger2);
        vi.doMock("pino", () => ({ default: pinoMock }));
        vi.doMock("../paths.js", () => ({ getLogDir: () => "/tmp/pocketcoder-test-logs" }));
        vi.doMock("node:fs", () => ({ mkdirSync: vi.fn() }));
        const { logger } = await import("../logger.js");
        logger.info("test");
        expect(pinoMock).toHaveBeenCalledWith(expect.objectContaining({ level: "info" }));
    });
    it("should include request context via createRequestLogger", async () => {
        vi.resetModules();
        vi.clearAllMocks();
        const childMock = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn(),
        };
        const mockLogger2 = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn().mockReturnValue(childMock),
        };
        const pinoMock = vi.fn(() => mockLogger2);
        vi.doMock("pino", () => ({ default: pinoMock }));
        vi.doMock("../paths.js", () => ({ getLogDir: () => "/tmp/pocketcoder-test-logs" }));
        vi.doMock("node:fs", () => ({ mkdirSync: vi.fn() }));
        const { createRequestLogger } = await import("../logger.js");
        const reqLogger = createRequestLogger("req-123");
        reqLogger.info("handling request");
        // Should create child with requestId
        expect(mockLogger2.child).toHaveBeenCalledWith({ requestId: "req-123" });
        // Should proxy info to child
        expect(childMock.info).toHaveBeenCalledWith("handling request");
    });
    it("should create child loggers", async () => {
        vi.resetModules();
        vi.clearAllMocks();
        const childMock = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn(),
        };
        const mockLogger2 = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn().mockReturnValue(childMock),
        };
        const pinoMock = vi.fn(() => mockLogger2);
        vi.doMock("pino", () => ({ default: pinoMock }));
        vi.doMock("../paths.js", () => ({ getLogDir: () => "/tmp/pocketcoder-test-logs" }));
        vi.doMock("node:fs", () => ({ mkdirSync: vi.fn() }));
        const { logger } = await import("../logger.js");
        const child = logger.child({ component: "gateway" });
        expect(mockLogger2.child).toHaveBeenCalledWith({ component: "gateway" });
        expect(child).toBe(childMock);
    });
    it("should configure file transport with pino-roll", async () => {
        vi.resetModules();
        vi.clearAllMocks();
        const mockLogger2 = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn(),
        };
        const pinoMock = vi.fn(() => mockLogger2);
        vi.doMock("pino", () => ({ default: pinoMock }));
        vi.doMock("../paths.js", () => ({ getLogDir: () => "/tmp/pocketcoder-test-logs" }));
        vi.doMock("node:fs", () => ({ mkdirSync: vi.fn() }));
        const { logger } = await import("../logger.js");
        logger.info("trigger init");
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const callArgs = pinoMock.mock.calls[0][0];
        const targets = callArgs.transport.targets;
        // Should have pino-roll file transport
        const rollTarget = targets.find((t) => t.target === "pino-roll");
        expect(rollTarget).toBeDefined();
        expect(rollTarget.options.file).toContain("daemon.log");
        expect(rollTarget.options.frequency).toBe("daily");
    });
    it("should use pino-pretty in development mode", async () => {
        process.env.NODE_ENV = "development";
        vi.resetModules();
        vi.clearAllMocks();
        const mockLogger2 = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn(),
        };
        const pinoMock = vi.fn(() => mockLogger2);
        vi.doMock("pino", () => ({ default: pinoMock }));
        vi.doMock("../paths.js", () => ({ getLogDir: () => "/tmp/pocketcoder-test-logs" }));
        vi.doMock("node:fs", () => ({ mkdirSync: vi.fn() }));
        const { logger } = await import("../logger.js");
        logger.info("trigger init");
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const callArgs = pinoMock.mock.calls[0][0];
        const targets = callArgs.transport.targets;
        const prettyTarget = targets.find((t) => t.target === "pino-pretty");
        expect(prettyTarget).toBeDefined();
    });
    it("should use JSON output in production mode", async () => {
        process.env.NODE_ENV = "production";
        vi.resetModules();
        vi.clearAllMocks();
        const mockLogger2 = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn(),
        };
        const pinoMock = vi.fn(() => mockLogger2);
        vi.doMock("pino", () => ({ default: pinoMock }));
        vi.doMock("../paths.js", () => ({ getLogDir: () => "/tmp/pocketcoder-test-logs" }));
        vi.doMock("node:fs", () => ({ mkdirSync: vi.fn() }));
        const { logger } = await import("../logger.js");
        logger.info("trigger init");
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const callArgs = pinoMock.mock.calls[0][0];
        const targets = callArgs.transport.targets;
        // Should not have pino-pretty
        const prettyTarget = targets.find((t) => t.target === "pino-pretty");
        expect(prettyTarget).toBeUndefined();
        // Should have pino/file for stdout
        const stdoutTarget = targets.find((t) => t.target === "pino/file");
        expect(stdoutTarget).toBeDefined();
    });
    it("should ignore invalid LOG_LEVEL values", async () => {
        process.env.LOG_LEVEL = "invalid_level";
        vi.resetModules();
        vi.clearAllMocks();
        const mockLogger2 = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn(),
        };
        const pinoMock = vi.fn(() => mockLogger2);
        vi.doMock("pino", () => ({ default: pinoMock }));
        vi.doMock("../paths.js", () => ({ getLogDir: () => "/tmp/pocketcoder-test-logs" }));
        vi.doMock("node:fs", () => ({ mkdirSync: vi.fn() }));
        const { logger } = await import("../logger.js");
        logger.info("test");
        // Should fall back to info
        expect(pinoMock).toHaveBeenCalledWith(expect.objectContaining({ level: "info" }));
    });
    it("should delegate all log methods to pino instance", async () => {
        vi.resetModules();
        vi.clearAllMocks();
        const mockLogger2 = {
            debug: vi.fn(),
            info: vi.fn(),
            warn: vi.fn(),
            error: vi.fn(),
            child: vi.fn(),
        };
        const pinoMock = vi.fn(() => mockLogger2);
        vi.doMock("pino", () => ({ default: pinoMock }));
        vi.doMock("../paths.js", () => ({ getLogDir: () => "/tmp/pocketcoder-test-logs" }));
        vi.doMock("node:fs", () => ({ mkdirSync: vi.fn() }));
        const { logger } = await import("../logger.js");
        logger.debug("debug msg");
        logger.info("info msg");
        logger.warn("warn msg");
        logger.error("error msg");
        expect(mockLogger2.debug).toHaveBeenCalledWith("debug msg");
        expect(mockLogger2.info).toHaveBeenCalledWith("info msg");
        expect(mockLogger2.warn).toHaveBeenCalledWith("warn msg");
        expect(mockLogger2.error).toHaveBeenCalledWith("error msg");
    });
});
//# sourceMappingURL=logger.test.js.map