// Config Reload Log Scanner tests cover config reload log scanner script behavior.
import { appendFileSync, rmSync, writeFileSync } from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { createConfigReloadLogScanner } from "../../scripts/e2e/lib/config-reload/log-scanner.mjs";
import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.js";

const tempRoots = useAutoCleanupTempDirTracker(afterEach);

describe("config reload log scanner", () => {
  it("keeps previous matches while reading only appended log lines", () => {
    const logPath = path.join(tempRoots.make("openclaw-config-reload-log-"), "gateway.log");
    const scanner = createConfigReloadLogScanner(logPath, {
      maxReadBytes: 1024,
      tailLineLimit: 4,
    });

    expect(scanner.scan()).toEqual({ reloadLines: [], restartLines: [], tailLines: [] });

    writeFileSync(logPath, "gateway boot\n");
    expect(scanner.scan()).toEqual({
      reloadLines: [],
      restartLines: [],
      tailLines: ["gateway boot"],
    });

    appendFileSync(logPath, "config change detected; evaluating reload: plugins.entries.demo\n");
    expect(scanner.scan().reloadLines).toEqual([
      "config change detected; evaluating reload: plugins.entries.demo",
    ]);

    appendFileSync(logPath, "later noise\n");
    expect(scanner.scan().reloadLines).toEqual([
      "config change detected; evaluating reload: plugins.entries.demo",
    ]);
  });

  it("preserves partial lines between polls", () => {
    const logPath = path.join(tempRoots.make("openclaw-config-reload-log-"), "gateway.log");
    const scanner = createConfigReloadLogScanner(logPath, {
      maxReadBytes: 1024,
      tailLineLimit: 4,
    });

    writeFileSync(logPath, "config change detected");
    expect(scanner.scan().reloadLines).toEqual([]);

    appendFileSync(logPath, "; evaluating reload: ui.seamColor\n");
    expect(scanner.scan().reloadLines).toEqual([
      "config change detected; evaluating reload: ui.seamColor",
    ]);
  });

  it("starts from a bounded tail of oversized logs", () => {
    const logPath = path.join(tempRoots.make("openclaw-config-reload-log-"), "gateway.log");
    const reloadLine = "config change detected; evaluating reload: ui.seamColor\n";
    writeFileSync(logPath, `${"x".repeat(4096)}\n${reloadLine}`);

    const scanner = createConfigReloadLogScanner(logPath, {
      maxReadBytes: reloadLine.length,
      tailLineLimit: 4,
    });

    expect(scanner.scan().reloadLines).toEqual([
      "config change detected; evaluating reload: ui.seamColor",
    ]);
  });

  it("resets accumulated matches when the log rotates", () => {
    const logPath = path.join(tempRoots.make("openclaw-config-reload-log-"), "gateway.log");
    const scanner = createConfigReloadLogScanner(logPath, {
      maxReadBytes: 1024,
      tailLineLimit: 4,
    });

    writeFileSync(logPath, "config change detected; evaluating reload: old.path\n");
    expect(scanner.scan().reloadLines).toEqual([
      "config change detected; evaluating reload: old.path",
    ]);

    writeFileSync(logPath, "config change requires gateway restart: new.path\n");
    const result = scanner.scan();
    expect(result.reloadLines).toEqual([]);
    expect(result.restartLines).toEqual(["config change requires gateway restart: new.path"]);
  });

  it("resets accumulated matches when a rotated log keeps the same size", () => {
    const logPath = path.join(tempRoots.make("openclaw-config-reload-log-"), "gateway.log");
    const scanner = createConfigReloadLogScanner(logPath, {
      maxReadBytes: 1024,
      tailLineLimit: 4,
    });
    const oldText = "config change detected; evaluating reload: old.path with enough padding\n";
    const restartLine = "config change requires gateway restart: new.path";
    const restartText = `${restartLine}${" ".repeat(oldText.length - restartLine.length - 1)}\n`;

    expect(Buffer.byteLength(restartText)).toBe(Buffer.byteLength(oldText));
    writeFileSync(logPath, oldText);
    expect(scanner.scan().reloadLines).toEqual([
      "config change detected; evaluating reload: old.path with enough padding",
    ]);

    rmSync(logPath, { force: true });
    writeFileSync(logPath, restartText);

    const result = scanner.scan();
    expect(result.reloadLines).toEqual([]);
    expect(result.restartLines).toEqual([restartText.replace(/\n$/u, "")]);
  });
});
