import { describe, expect, test } from "bun:test";

import type { Logger } from "../../src/server/logger";

import { createConsoleFallback, createMemoryLogger, createNoopLogger, REDACT_PATHS } from "../../src/server/logger";

describe("NoopLogger", () => {
  test("所有方法不抛异常", () => {
    const logger = createNoopLogger();
    logger.trace("trace");
    logger.debug("debug");
    logger.info("info");
    logger.warn("warn");
    logger.error("error");
    logger.fatal("fatal");
    logger.flush();
    const child = logger.child({ component: "test" });
    expect(child).toBeDefined();
  });
});

describe("MemoryLogger", () => {
  test("记录所有等级日志", () => {
    const logger = createMemoryLogger();
    logger.trace("trace-msg");
    logger.debug("debug-msg");
    logger.info("info-msg");
    logger.warn("warn-msg");
    logger.error("error-msg");
    logger.fatal("fatal-msg");

    expect(logger.entries).toHaveLength(6);
    expect(logger.entries[0]).toEqual({ level: "trace", msg: "trace-msg" });
    expect(logger.entries[5]).toEqual({ level: "fatal", msg: "fatal-msg" });
  });

  test("记录结构化日志", () => {
    const logger = createMemoryLogger();
    logger.info({ matched: true, targetId: "abc" }, "check complete");

    expect(logger.entries).toHaveLength(1);
    expect(logger.entries[0]!.level).toBe("info");
    expect(logger.entries[0]!.msg).toBe("check complete");
    expect(logger.entries[0]!.obj).toEqual({ matched: true, targetId: "abc" });
  });

  test("child 返回自身", () => {
    const logger = createMemoryLogger();
    const child = logger.child({ component: "engine" });
    child.info("child-msg");
    expect(logger.entries).toHaveLength(1);
  });

  test("flush 不抛异常", () => {
    const logger = createMemoryLogger();
    logger.flush();
  });
});

describe("ConsoleFallbackLogger", () => {
  test("不抛异常", () => {
    const logger = createConsoleFallback();
    logger.trace("trace");
    logger.debug("debug");
    logger.info("info");
    logger.warn("warn");
    logger.error("error");
    logger.fatal("fatal");
    logger.flush();
    const child = logger.child({ component: "test" });
    expect(child).toBeDefined();
  });
});

describe("Logger 接口契约", () => {
  function assertLogger(logger: Logger): void {
    logger.trace("trace");
    logger.debug("debug");
    logger.info("info");
    logger.warn("warn");
    logger.error("error");
    logger.fatal("fatal");
    logger.info({ key: "value" }, "structured");
    logger.child({ component: "test" }).info("child");
    logger.flush();
  }

  test("NoopLogger 满足 Logger 接口", () => {
    expect(() => assertLogger(createNoopLogger())).not.toThrow();
  });

  test("MemoryLogger 满足 Logger 接口", () => {
    expect(() => assertLogger(createMemoryLogger())).not.toThrow();
  });

  test("ConsoleFallbackLogger 满足 Logger 接口", () => {
    expect(() => assertLogger(createConsoleFallback())).not.toThrow();
  });
});

describe("redaction 敏感信息保护", () => {
  test("MemoryLogger 不做 redaction（测试用途，仅 Pino 运行时 redact）", () => {
    const logger = createMemoryLogger();
    logger.info({ authorization: "Bearer secret", password: "hunter2" }, "test");
    const entry = logger.entries[0]!;
    expect(entry.obj!["authorization"]).toBe("Bearer secret");
    expect(entry.obj!["password"]).toBe("hunter2");
  });

  test("REDACT_PATHS 覆盖所有敏感字段键名", () => {
    const sensitiveKeys = ["authorization", "cookie", "set-cookie", "authToken", "key", "password", "token", "apiKey"];
    for (const key of sensitiveKeys) {
      expect(REDACT_PATHS).toContain(key);
      expect(REDACT_PATHS).toContain(`*.${key}`);
    }
  });
});
