/**
 * Tests Windows spawn compatibility helpers.
 */
import { writeFile } from "node:fs/promises";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { createPluginSdkTestHarness } from "./test-helpers.js";
import { materializeWindowsSpawnProgram, resolveWindowsSpawnProgram } from "./windows-spawn.js";

const { createTempDir } = createPluginSdkTestHarness({
  cleanup: {
    maxRetries: 8,
    retryDelay: 8,
  },
});

describe("resolveWindowsSpawnProgram", () => {
  it("rejects node command strings that include inline entrypoint arguments on Windows", () => {
    expect(() =>
      resolveWindowsSpawnProgram({
        command: "node C:\\Users\\me\\.openclaw\\npm\\node_modules\\@openai\\codex\\bin\\codex.js",
        platform: "win32",
        env: {},
        execPath: "C:\\node\\node.exe",
      }),
    ).toThrow("Windows spawn command must be an executable path only");
  });

  it("allows executable paths with spaces on Windows", () => {
    const resolved = resolveWindowsSpawnProgram({
      command: "C:\\Program Files\\OpenAI Codex\\codex.exe",
      platform: "win32",
      env: {},
      execPath: "C:\\node\\node.exe",
    });

    expect(resolved).toEqual({
      command: "C:\\Program Files\\OpenAI Codex\\codex.exe",
      leadingArgv: [],
      resolution: "direct",
      windowsHide: undefined,
    });
  });

  it("fails closed by default for unresolved windows wrappers", async () => {
    const dir = await createTempDir("openclaw-windows-spawn-test-");
    const shimPath = path.join(dir, "wrapper.cmd");
    await writeFile(shimPath, "@ECHO off\r\necho wrapper\r\n", "utf8");

    expect(() =>
      resolveWindowsSpawnProgram({
        command: shimPath,
        platform: "win32",
        env: { PATH: dir, PATHEXT: ".CMD;.EXE;.BAT" },
        execPath: "C:\\node\\node.exe",
      }),
    ).toThrow(/without shell execution/);
  });

  it("only returns shell fallback when explicitly opted in", async () => {
    const dir = await createTempDir("openclaw-windows-spawn-test-");
    const shimPath = path.join(dir, "wrapper.cmd");
    await writeFile(shimPath, "@ECHO off\r\necho wrapper\r\n", "utf8");

    const resolved = resolveWindowsSpawnProgram({
      command: shimPath,
      platform: "win32",
      env: { PATH: dir, PATHEXT: ".CMD;.EXE;.BAT" },
      execPath: "C:\\node\\node.exe",
      allowShellFallback: true,
    });
    const invocation = materializeWindowsSpawnProgram(resolved, ["--cwd", "C:\\safe & calc.exe"]);

    expect(invocation).toEqual({
      command: shimPath,
      argv: ["--cwd", "C:\\safe & calc.exe"],
      resolution: "shell-fallback",
      shell: true,
      windowsHide: undefined,
    });
  });

  it("preserves custom batch-wrapper behavior instead of bypassing its target", async () => {
    const dir = await createTempDir("openclaw-windows-spawn-test-");
    const targetPath = path.join(dir, "tool.exe");
    const wrapperPath = path.join(dir, "wrapper.cmd");
    await writeFile(targetPath, "", "utf8");
    await writeFile(
      wrapperPath,
      '@ECHO off\r\nSET WRAPPER_FLAG=1\r\n"%~dp0\\tool.exe" %*\r\n',
      "utf8",
    );

    const resolved = resolveWindowsSpawnProgram({
      command: wrapperPath,
      platform: "win32",
      env: { PATH: dir, PATHEXT: ".CMD;.EXE;.BAT" },
      execPath: "C:\\node\\node.exe",
      allowShellFallback: true,
    });

    expect(resolved).toEqual({
      command: wrapperPath,
      leadingArgv: [],
      resolution: "shell-fallback",
      shell: true,
    });
  });

  it("does not reinterpret a forwarded batch wrapper as a Node script", async () => {
    const dir = await createTempDir("openclaw-windows-spawn-test-");
    const targetPath = path.join(dir, "inner.cmd");
    const wrapperPath = path.join(dir, "wrapper.cmd");
    await writeFile(targetPath, "@ECHO off\r\necho inner\r\n", "utf8");
    await writeFile(wrapperPath, '@ECHO off\r\n"%~dp0\\inner.cmd" %*\r\n', "utf8");

    const resolved = resolveWindowsSpawnProgram({
      command: wrapperPath,
      platform: "win32",
      env: { PATH: dir, PATHEXT: ".CMD;.EXE;.BAT" },
      execPath: "C:\\node\\node.exe",
      allowShellFallback: true,
    });

    expect(resolved).toEqual({
      command: wrapperPath,
      leadingArgv: [],
      resolution: "shell-fallback",
      shell: true,
    });
  });
});
